Skip to content

Fix persistent XSS in data export via unsanitized review messages#2

Open
emrazik wants to merge 1 commit into
masterfrom
fix/persistent-xss-data-export
Open

Fix persistent XSS in data export via unsanitized review messages#2
emrazik wants to merge 1 commit into
masterfrom
fix/persistent-xss-data-export

Conversation

@emrazik

@emrazik emrazik commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Finding

NetSPI Finding #1048219768 — Cross-Site Scripting (Persistent) | High

Users can store XSS payloads in product reviews. When any user exports their data at /#/privacy-security/data-export, those review messages are returned verbatim in the JSON payload and the frontend renders the JSON into a new window with document.write(). This executes embedded <script> tags and event-handler attributes in the victim's browser.

What changed

routes/dataExport.ts

review.message is now passed through security.sanitizeSecure() before being added to the export payload. This strips or escapes any HTML tags from the stored review text before it leaves the server.

frontend/src/app/data-export/data-export.component.ts

Replaced window.open('', '_blank').document.write(this.userData) with a Blob-based file download. The JSON string is wrapped in a Blob with application/json MIME type, a temporary object URL is created, an <a> element triggers the download, and the URL is revoked immediately after. The browser never parses the content as HTML, so no injected markup can execute regardless of what the server returns.

Test plan

  • Log in, post a product review containing <img src=x onerror="alert(1)">, then navigate to /privacy-security/data-export and export — the downloaded file should contain the sanitized text and no alert should fire
  • Verify the export still downloads valid JSON with all user data (orders, memories, reviews) intact
  • Confirm no regression: existing reviews without HTML render correctly in the download

🤖 Generated with Claude Code

Review messages were stored and re-emitted verbatim by the JSON export
endpoint and then rendered into a new window via document.write(), allowing
stored XSS payloads to execute in any user's browser on export.

- routes/dataExport.ts: sanitize review.message with sanitizeSecure()
  before including it in the export payload
- data-export.component.ts: replace document.write() with a safe Blob
  download so the JSON is saved as a file instead of rendered as HTML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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