Skip to content

Sanitize rawHtml on ingest to prevent stored XSS (matches fetch-url r… - #1

Open
Iseekdopamine wants to merge 1 commit into
SyntaxMasons:mainfrom
Iseekdopamine:fix/sanitize-html-on-ingest
Open

Iseekdopamine wants to merge 1 commit into
SyntaxMasons:mainfrom
Iseekdopamine:fix/sanitize-html-on-ingest

Conversation

@Iseekdopamine

Copy link
Copy Markdown

Summary

Stored XSS in /api/documents/ingest lets a reviewer-level account fully compromise an admin account, with no admin action needed beyond opening the affected document.

Root cause

POST /api/documents/ingest saves rawHtml directly with no sanitization. The URL-fetch route (/api/documents/fetch-url) already sanitizes with sanitizeHtml(..., SANITIZE_OPTIONS) — the ingest route was just missing the same call.

Proof of concept

  1. As a reviewer, ingest a document with:
    <img src=x onerror="fetch('/api/admin/users',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'username=pwned_admin&password=Pwned123!&role=admin'})">
  2. When an admin opens that document in the review pane, the script runs in their session and silently creates a new admin account.
  3. Verified locally — pwned_admin appeared in User Management with role Administrator, created purely by the admin viewing the document (screenshot available on request).

Fix

One-line change: run the existing sanitizeHtml(rawHtml, SANITIZE_OPTIONS) in the ingest route too, same as fetch-url already does.

-      rawHtml:  rawHtml.trim(),
+      rawHtml: sanitizeHtml(rawHtml.trim(), SANITIZE_OPTIONS),

Tested: the XSS payload no longer executes after this change, and normal HTML ingestion (headings, paragraphs, images) still renders and generates Q&A correctly.

Separate minor issue (not fixed in this PR)

The README lists both seeded accounts' passwords as password123, but the actual defaults in db.mjs are Admin@2026! and Reviewer@2026!. Worth a quick doc fix separately.
Screenshot 2026-11-13 145441

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant