Every CVE Search/ Get API key

CVE-2026-79663

Ech0 before 4.7.3 Stored XSS via RSS feed tag names

4.8 MediumFix available

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
High
User interaction
Passive

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Exploit likelihood

0.25%Up 0.1 points since Aug 26, 2026
90%50%10%1%

What each source reports

CVE List Score used 4.8

Ech0 before 4.7.3 Stored XSS via RSS feed tag names

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Record
CVE-2026-79663
CVSS 4.0
4.8 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
CVSS 3.1
4.8 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
EUVDEUVD-2026-65451 4.8

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Record
EUVD-2026-65451
CVSS 4.0
4.8 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-3v85-fqvh-7rxf 4.8

Ech0's RSS feed renders unescaped tag names and raw-HTML markdown, stored XSS against subscribers

Summary

The public RSS/Atom feed at /rss renders two attacker-controlled surfaces without HTML escaping. Tag names flow through fmt.Appendf(renderedContent, "<br /><span class=\"tag\">#%s</span>", tag.Name) at internal/service/common/common.go:120, and the Markdown renderer at internal/util/md/md.go does not set the html.SkipHTML flag, so raw HTML blocks in echo content pass through unmodified. The resulting Atom <summary type="html"> is valid XML but contains executable <script> tags after the RSS reader decodes it. RSS subscribers whose readers render HTML (including many self-hosted and desktop clients) execute attacker JavaScript in the reader's origin.

Details

Tag sink at internal/service/common/common.go:120:

if len(msg.Tags) > 0 {
    for _, tag := range msg.Tags {
        renderedContent = fmt.Appendf(renderedContent,
            "<br /><span class=\"tag\">#%s</span>", tag.Name)
    }
}

fmt.Appendf with %s does not HTML-escape. Tag names come from user-supplied EchoUpsertDto.Tags and are persisted after strings.TrimSpace(strings.TrimPrefix(tag.Name, "#")) at internal/service/echo/echo.go:326, which strips a leading # and trims whitespace but does nothing about HTML metacharacters. A tag name of </span><script>document.title='RSS-XSS-HIT'</script><span>x breaks out of the surrounding <span> element and injects executable JavaScript into the RSS summary field.

Markdown sink at internal/util/md/md.go:

htmlFlags := html.CommonFlags | html.Safelink | html.HrefTargetBlank |
             html.NoopenerLinks | html.NoreferrerLinks
// html.SkipHTML is NOT set

The gomarkdown library passes raw HTML through when SkipHTML is not set. MdToHTML([]byte(msg.Content)) at internal/service/common/common.go:102 produces the rendered HTML for the echo body; tag markup is appended to that output at line 120 and the combined byte slice becomes the RSS summary field.

The RSS feed declares <summary type="html">, which per Atom RFC 4287 §3.1.1.3 means the content is HTML encoded as XML. RSS readers that render HTML decode the XML entities and pass the decoded string to an HTML renderer. Any script tag survives this round-trip.

Echo creation requires admin role (internal/service/echo/echo.go:54-56 checks user.IsAdmin). In a single-admin Ech0 instance this is self-attack. In a multi-admin deployment (non-owner admins promoted by the owner), one admin injects XSS into the shared RSS feed consumed by other admins, registered users, and anonymous subscribers.

Prior precedent: GHSA-69hx-63pv-f8f4 (2026-04-09) accepted stored XSS via SVG file upload, with the same "admin creates content" precondition. Cross-subscriber RSS XSS from one admin belongs to the same class.

Proof of Concept

Default install, admin account seeds malicious tag + markdown content, anonymous subscriber fetches /rss and the decoded summary contains executable <script>:

import requests, xml.etree.ElementTree as ET, html
TARGET = "http://localhost:8300"

# Admin creates two echoes: one with a hostile tag name, one with raw-HTML markdown.
owner = requests.post(f"{TARGET}/api/login",
                      json={"username": "owner", "password": "owner-pw"}
                     ).json()["data"]["access_token"]

tag_payload = "</span><script>document.title='RSS-XSS-HIT'</script><span>x"
md_payload = "<script>document.title='MD-XSS-HIT'</script>normal text"

requests.post(f"{TARGET}/api/echos",
              headers={"Authorization": f"Bearer {owner}",
                       "content-type": "application/json"},
              json={"content": "echo with malicious tag",
                    "tags": [tag_payload]})

requests.post(f"{TARGET}/api/echos",
              headers={"Authorization": f"Bearer {owner}",
                       "content-type": "application/json"},
              json={"content": md_payload})

# Anyone fetches /rss anonymously.
feed =…
Record
GHSA-3v85-fqvh-7rxf
CVSS 3.1
4.8 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79, CWE-116
Updated
2026-11-02
GitHub AdvisoriesGHSA-9277-65xq-8gww 4.8

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed...

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Record
GHSA-9277-65xq-8gww
CVSS 4.0
4.8 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
4.8 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
NVD 4.8

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Record
CVE-2026-79663
CVSS 4.0
4.8 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
4.8 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
OSV 4.8

Ech0 before 4.7.3 Stored XSS via RSS feed tag names

Ech0 before 4.7.3 contains a stored cross-site scripting vulnerability in the public RSS feed where tag names and markdown content are rendered without HTML escaping. Attackers with admin privileges can inject malicious tag names or raw HTML in echo content that executes as JavaScript in RSS readers that render HTML-type summaries, affecting anonymous subscribers and other users.

Record
CVE-2026-79663
CVSS 4.0
4.8 MediumCVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N
Weakness
CWE-79
Updated
2026-11-02
OSVGHSA-3v85-fqvh-7rxf 4.8

Ech0's RSS feed renders unescaped tag names and raw-HTML markdown, stored XSS against subscribers

Summary

The public RSS/Atom feed at /rss renders two attacker-controlled surfaces without HTML escaping. Tag names flow through fmt.Appendf(renderedContent, "<br /><span class=\"tag\">#%s</span>", tag.Name) at internal/service/common/common.go:120, and the Markdown renderer at internal/util/md/md.go does not set the html.SkipHTML flag, so raw HTML blocks in echo content pass through unmodified. The resulting Atom <summary type="html"> is valid XML but contains executable <script> tags after the RSS reader decodes it. RSS subscribers whose readers render HTML (including many self-hosted and desktop clients) execute attacker JavaScript in the reader's origin.

Details

Tag sink at internal/service/common/common.go:120:

if len(msg.Tags) > 0 {
    for _, tag := range msg.Tags {
        renderedContent = fmt.Appendf(renderedContent,
            "<br /><span class=\"tag\">#%s</span>", tag.Name)
    }
}

fmt.Appendf with %s does not HTML-escape. Tag names come from user-supplied EchoUpsertDto.Tags and are persisted after strings.TrimSpace(strings.TrimPrefix(tag.Name, "#")) at internal/service/echo/echo.go:326, which strips a leading # and trims whitespace but does nothing about HTML metacharacters. A tag name of </span><script>document.title='RSS-XSS-HIT'</script><span>x breaks out of the surrounding <span> element and injects executable JavaScript into the RSS summary field.

Markdown sink at internal/util/md/md.go:

htmlFlags := html.CommonFlags | html.Safelink | html.HrefTargetBlank |
             html.NoopenerLinks | html.NoreferrerLinks
// html.SkipHTML is NOT set

The gomarkdown library passes raw HTML through when SkipHTML is not set. MdToHTML([]byte(msg.Content)) at internal/service/common/common.go:102 produces the rendered HTML for the echo body; tag markup is appended to that output at line 120 and the combined byte slice becomes the RSS summary field.

The RSS feed declares <summary type="html">, which per Atom RFC 4287 §3.1.1.3 means the content is HTML encoded as XML. RSS readers that render HTML decode the XML entities and pass the decoded string to an HTML renderer. Any script tag survives this round-trip.

Echo creation requires admin role (internal/service/echo/echo.go:54-56 checks user.IsAdmin). In a single-admin Ech0 instance this is self-attack. In a multi-admin deployment (non-owner admins promoted by the owner), one admin injects XSS into the shared RSS feed consumed by other admins, registered users, and anonymous subscribers.

Prior precedent: GHSA-69hx-63pv-f8f4 (2026-04-09) accepted stored XSS via SVG file upload, with the same "admin creates content" precondition. Cross-subscriber RSS XSS from one admin belongs to the same class.

Proof of Concept

Default install, admin account seeds malicious tag + markdown content, anonymous subscriber fetches /rss and the decoded summary contains executable <script>:

import requests, xml.etree.ElementTree as ET, html
TARGET = "http://localhost:8300"

# Admin creates two echoes: one with a hostile tag name, one with raw-HTML markdown.
owner = requests.post(f"{TARGET}/api/login",
                      json={"username": "owner", "password": "owner-pw"}
                     ).json()["data"]["access_token"]

tag_payload = "</span><script>document.title='RSS-XSS-HIT'</script><span>x"
md_payload = "<script>document.title='MD-XSS-HIT'</script>normal text"

requests.post(f"{TARGET}/api/echos",
              headers={"Authorization": f"Bearer {owner}",
                       "content-type": "application/json"},
              json={"content": "echo with malicious tag",
                    "tags": [tag_payload]})

requests.post(f"{TARGET}/api/echos",
              headers={"Authorization": f"Bearer {owner}",
                       "content-type": "application/json"},
              json={"content": md_payload})

# Anyone fetches /rss anonymously.
feed =…
Record
GHSA-3v85-fqvh-7rxf
CVSS 3.1
4.8 MediumCVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-116, CWE-79
Updated
2026-11-02
OSVGO-2026-5100 No score

Ech0's RSS feed renders unescaped tag names and raw-HTML markdown, stored XSS against subscribers in github.com/lin-snow/ech0

Ech0's RSS feed renders unescaped tag names and raw-HTML markdown, stored XSS against subscribers in github.com/lin-snow/ech0

Record
GO-2026-5100
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
github.com/lin-snow/Ech0
Go
before 1.4.8-0.20260503035519-fd320fe3e902
1.4.8-0.20260503035519-fd320fe3e902
github.com/lin-snow/ech0
Go
before 1.4.8-0.20260503035519-fd320fe3e902
1.4.8-0.20260503035519-fd320fe3e902

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-79663 is a medium vulnerability (CVSS 4.8) in Lin-snow Ech0, published May 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in github.com/lin-snow/Ech0 1.4.8-0.20260503035519-fd320fe3e902.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open