Skip to content

fix(security): parser-based SVG/MDX scanning, replacing per-bypass regex patches - #1245

Merged
mrbobbytables merged 2 commits into
cncf:mainfrom
mrbobbytables:sec/parser-based-content-scanners
Oct 9, 2026
Merged

mrbobbytables merged 2 commits into
cncf:mainfrom
mrbobbytables:sec/parser-based-content-scanners

Conversation

@mrbobbytables

Copy link
Copy Markdown
Member

Implements the decision on #1194 (option 1: parse, do not pattern-match).

What changes

  • SVG (scripts/lib/svg-active-content.mjs): scans a strict XML parse (sax); CSS is tokenized with css-tree. Escapes, comments, quote pairing, and XML character references are resolved before inspection. srcset, poster, and background are covered. stripActiveContent rebuilds from the parse instead of splicing text.
  • MDX (scripts/lib/mdx-active-content.mjs): scans the mdast from the same grammar Docusaurus compiles with. Shares URI scheme rules with the SVG scanner (scripts/lib/uri-safety.mjs).
  • cleanMarkdown: images are found in the CommonMark tree, so reference-style images are demoted like inline ones.
  • Docs: CONTENT-SECURITY.md explains the approach, residual risks, and the meta-only CSP.

Behaviour change to note

Malformed XML (unquoted attributes, unclosed tags, undefined entities such as  , unterminated DOCTYPE) is now rejected as is not well-formed XML rather than leniently read. Every historical bypass fixture is kept and still rejected; tests that asserted regex-era behaviour on malformed input now assert rejection. All SVGs under static/ still pass.

Validation

npm run test:unit:coverage:check, validate:architecture-assets, validate:architectures, and prettier all pass.

Closes #1194
Closes #1205
Closes #1212
Closes #1218
Closes #1223
Closes #1228

Supersedes #1206, #1213, #1219, #1229. #1235 (meta CSP script/style-src) and #1242 (symlinked directory gate) are orthogonal and left open.

…matching them

Replace the regex-based active-content scanners with parser-based ones, per
the decision recorded on cncf#1194:

- SVG: scan a strict XML parse (sax) and tokenize CSS with css-tree, so
  escapes, comments, quote pairing and character references are resolved the
  way a browser resolves them. A document the parser rejects is a finding.
  Stripping rebuilds the document from the parse rather than splicing text.
- MDX: scan the mdast produced by the grammar Docusaurus compiles with.
- cleanMarkdown: find images in the CommonMark tree, so reference-style
  images follow the same remote-image policy as inline ones.
- Share URI scheme rules between the scanners in scripts/lib/uri-safety.mjs.
- Document the approach and residual risks in CONTENT-SECURITY.md.

Closes cncf#1194
Closes cncf#1205
Closes cncf#1212
Closes cncf#1218
Closes cncf#1223
Closes cncf#1228

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
Comment thread scripts/lib/svg-active-content.mjs Fixed
Comment thread scripts/lib/svg-active-content.mjs Fixed
CodeQL flagged the prolog pattern as exponential on repeated '<?' and
'<!--' units. Walk the prolog linearly instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: mrbobbytables <mrbobbytables@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment