Skip to content

Fix XSS in semantic HTML export: escape code-block language#4818

Open
LeeSeungjae00 wants to merge 1 commit into
slab:mainfrom
LeeSeungjae00:fix-syntax-html-export-xss
Open

Fix XSS in semantic HTML export: escape code-block language#4818
LeeSeungjae00 wants to merge 1 commit into
slab:mainfrom
LeeSeungjae00:fix-syntax-html-export-xss

Conversation

@LeeSeungjae00

Copy link
Copy Markdown

Summary

Fixes #4789.

SyntaxCodeBlockContainer.html() interpolates the code block's language value into the data-language attribute without escaping, while the code content itself goes through escapeText(). The language can be set to an arbitrary string via formatLine(0, 1, 'code-block', value) (or crafted pasted content), so a value like "><img src=x onerror="alert(1)"> breaks out of the attribute and executes script wherever the output of getSemanticHTML() is rendered.

This is the remaining code path not covered by #4774, which fixes the same pattern in the formula and video formats. Related advisory: GHSA-v3m3-f69x-jf25 (CVE-2025-15056).

Fix

Wrap the language value with the existing escapeText() helper — the same one-line pattern already used for the code content on the next line.

Testing

  • Added a unit test that formats a line with a malicious language value and asserts the semantic HTML output is escaped. Without the fix it fails with the raw <img payload present in the output; with the fix it passes.
  • Full unit suite passes: 32 files, 522 tests, no type errors, lint clean.

🤖 Generated with Claude Code

The language value was interpolated into the data-language attribute
without escaping, allowing XSS via getSemanticHTML(). Fixes slab#4789
@0xLeif

0xLeif commented Jul 23, 2026

Copy link
Copy Markdown

Review (via AI-assisted code review): APPROVE

This is a correct, minimal fix for a real XSS vector.

  • In SyntaxCodeBlockContainer.html(), the data-language value (attacker-controllable via formatLine(..., 'code-block', value) or crafted pasted <pre data-language="..."> content) was interpolated raw while the code body on the next line was already escaped. Wrapping it in the existing escapeText() helper closes the attribute-breakout vector: escapeText (src/blots/text.ts) escapes & < > " ', so "><img src=x onerror=...> can no longer terminate the attribute.
  • The added unit test asserts both the absence of <img and the exact &quot;&gt;&lt;... escaped output, and matches escapeText's entity map. It fails without the fix and passes with it.
  • No behavior change for well-formed languages (javascript, plain are unaffected), so this is backward compatible. Branch is based on current main (539cbff).

Notes (non-blocking): this overlaps with #4774 (which contains the identical one-line syntax fix plus broader changes) and #4788 — whichever lands first, the others should rebase and drop the duplicate hunk. No CI runs have executed on this fork head, so please trigger the unit suite before merge.

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.

XSS in Syntax module: data-language attribute not escaped in html() (not covered by PR #4788)

2 participants