May 8, 2026·5 min read·11 visits
Ech0 renders unescaped user input into its public RSS feed, permitting stored XSS attacks when users read the feed.
A stored Cross-Site Scripting (XSS) vulnerability exists in the Ech0 project's RSS feed generation component. The application fails to properly escape user-supplied tags and Markdown content before reflecting them in the `/rss` endpoint, allowing arbitrary JavaScript execution in vulnerable RSS readers.
The Ech0 application exposes an RSS and Atom feed endpoint at /rss to distribute content updates. This syndication component suffers from a stored Cross-Site Scripting (XSS) vulnerability. The flaw manifests when user-supplied input, specifically post content and associated tags, is incorporated into the XML response without adequate contextual output encoding or sanitization.
An attacker with permissions to create or modify content on the platform can inject arbitrary HTML or JavaScript payloads. When a user requests the feed or an RSS reader parses it, the injected payloads are reflected in the <summary type="html"> node. This reflection occurs continuously as long as the malicious post remains in the syndication queue.
This vulnerability represents a classic CWE-79 manifestation, specifically impacting downstream consumers of the syndication feed. The vulnerability assumes a moderate risk profile, as execution depends on the target RSS client honoring HTML rendering within the feed's summary tags.
The vulnerability is underpinned by two distinct rendering flaws in the application's Go source code. The first flaw resides in internal/service/common/common.go, where the GenerateRSS function constructs the feed summary.
The application appends dynamically generated tag names into the RSS feed using the fmt.Appendf function. The tag name string is passed via the %s format verb directly into a static HTML <span> container. Because no HTML escaping function is invoked on the tag name prior to string interpolation, standard HTML entity boundaries can be bypassed.
The second issue involves permissive rendering configuration in the gomarkdown library, located within internal/util/md/md.go. The MdToHTML utility invokes the renderer without specifying the html.SkipHTML flag. This omission instructs the parser to treat raw HTML tags embedded in Markdown as literal output rather than stripping them, thereby allowing direct script injection.
The patch applied in commit fd320fe3e9021c8d8d284fb274775c018690520e addresses both vectors through context-aware output encoding and input validation.
In the feed generation routine, the vulnerable implementation directly concatenated user input:
// Vulnerable
renderedContent = fmt.Appendf(
renderedContent,
"<br /><span class=\"tag\">#%s</span>",
tag.Name,
)The patched implementation wraps the tag name in stdhtml.EscapeString, preventing boundary breakouts:
// Patched
renderedContent = fmt.Appendf(
renderedContent,
"<br /><span class=\"tag\">#%s</span>",
stdhtml.EscapeString(tag.Name),
)Furthermore, the Markdown parsing configuration was hardened. The developer added html.SkipHTML to the Bitmask defining the renderer's standard flags, stripping raw HTML from parsed Markdown bodies. A defense-in-depth validation helper function, isSafeTagName, was also introduced in internal/service/echo/echo.go to reject tag names containing dangerous characters (<, >, ", ', &) during creation.
Exploitation requires the attacker to possess sufficient privileges to generate or modify an "echo" (post) or its associated tags. The attacker begins by submitting a payload designed to break out of the intended XML or HTML structure.
For the tag vector, an attacker creates a tag named </span><script>alert(1)</script>. For the Markdown vector, the attacker embeds a raw payload, such as <iframe src="javascript:alert(1)">, directly into the body of the post. The application stores this malicious content persistently in the backend database.
The execution phase triggers asynchronously when a victim subscribes to or views the /rss endpoint. An RSS reader that parses <summary type="html"> decodes the feed content and evaluates the unescaped script elements. The JavaScript executes within the security context of the domain hosting the feed or the local environment of the vulnerable client application.
The CVSS 3.1 base score of 5.3 reflects a moderate severity profile characterized by a low attack complexity but reliance on user interaction. The execution context determines the specific security impact.
If the victim views the feed through a web-based RSS reader hosted on the same domain as the application, the attacker gains the ability to hijack active sessions. The malicious script executes in the victim's browser context, enabling unauthorized API requests and access to sensitive user data.
When viewed through external or desktop RSS clients, the impact varies based on the client's internal rendering engine constraints. A client employing a hardened WebView minimizes direct exploitation, whereas less restrictive clients permit phishing, forced redirection to malicious infrastructure, or localized information disclosure.
Administrators must update their Ech0 deployments to a version incorporating commit fd320fe3e9021c8d8d284fb274775c018690520e. The patch natively resolves both root causes by applying strict output encoding and stripping raw HTML during markdown parsing.
If immediate patching is unfeasible, operators can deploy a Web Application Firewall (WAF) rule to inspect and block inbound requests attempting to submit HTML metacharacters to the post or tag creation endpoints. This prevents the initial storage of the payload.
Developers building upon similar syndication services must mandate strict output encoding for all user-controlled data placed into XML and HTML contexts. Employing structured templating engines with auto-escaping enabled by default prevents interpolation vulnerabilities inherent to standard string formatting functions.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Ech0 lin-snow | All versions prior to fix commit fd320fe3 | fd320fe3e9021c8d8d284fb274775c018690520e |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 5.3 |
| Impact | Stored Cross-Site Scripting |
| Exploit Status | Proof-of-Concept |
| Authentication Required | Yes (to post/tag) |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')