Skip to content

Scanner hardening strategy: move SVG/MDX active-content scanning off per-bypass regex patching #1194

Closed

Description

@mrbobbytables

Problem: the bypass class keeps recurring; per-bypass patching is losing

The import-pipeline content scanner (scripts/lib/svg-active-content.mjs, scripts/lib/architecture-content.mjs) accumulated roughly ten distinct bypass classes in one week of sec-check findings, each fixed by another regex:

svg-active-content.mjs currently performs its analysis through 13 regex operations over text that is actually XML + CSS. Each finding above is the same root cause: regexes approximate grammars that have escaping, comments, and tokenizer states the regex cannot see. The historical rate (~10/week) predicts the next bypass; the per-bypass loop produces unbounded future work and a permanently uncertain gate.

Proposed direction (pick via discussion)

  1. Parse, do not pattern-match. Run SVG through a real XML parser (e.g. @rgrove/parse-xml or sax) and walk the element/attribute tree; tokenize embedded CSS with a real CSS tokenizer before looking for remote targets. Grammar-level analysis eliminates the escaping/comment/CDATA class wholesale.
  2. Sanitize instead of scan-and-reject for the mirror path: project the SVG onto an element/attribute allowlist (DOMPurify-style, or rebuild from the parsed tree), so unknown constructs are dropped rather than needing to be anticipated.
  3. Defense in depth at serve time: the CSP currently ships only as a <meta http-equiv> tag (docusaurus.config.js:148), which cannot cover everything response headers can on GitHub Pages — document this residual risk and the compensating controls in the content-security doc requested by [guide] Content-security rules enforced by architecture validators are documented nowhere — submitters hit 'active content'/'remote reference' CI failures with no doc to consult #1096.

Keep the existing regression test corpus (tests/svg-active-content.test.mjs) as the acceptance suite: every past bypass becomes a fixture the parser-based gate must still reject.

Completion criteria

Refs #1096 (documentation counterpart).

Activity

  1. added
    enhancementNew feature or request
    securityApproved by a Hive merger/owner for auto-merge on green CI
    on Oct 8, 2026
  2. mrbobbytables commented on Oct 8, 2026

    @mrbobbytables
    MemberAuthor

    Two updates folding related work into this issue:

    1. [scanner] svg-active-content.mjs: unterminated-string arms in #1176's two new CSS scanners have no unit coverage #1197 is consolidated here as acceptance fixtures. PR test: cover the CSS scanners' unterminated-string fallback arms #1200 lands the two unit tests it asked for (unterminated-string arms in the image-set() walker and stripCssComments), closing [scanner] svg-active-content.mjs: unterminated-string arms in #1176's two new CSS scanners have no unit coverage #1197. Those cases now join the regression corpus in tests/svg-active-content.test.mjs that this issue designates as the acceptance suite — the parser/sanitizer replacement must still pass them. [scanner] svg-active-content.mjs: unterminated-string arms in #1176's two new CSS scanners have no unit coverage #1197 is also the latest data point for the trend this issue describes: every scanner hardening PR (fix(security): detect image-set() and comment-hidden CSS remote references #1176 most recently) grows the hand-rolled tokenizer surface and leaves new fallback arms to test, which is the per-bypass loop compounding.

    2. The documentation counterpart has landed. [guide] Content-security rules enforced by architecture validators are documented nowhere — submitters hit 'active content'/'remote reference' CI failures with no doc to consult #1096 is closed via docs: document the architecture content-security rules submitters hit in CI #1199 (docs: document the architecture content-security rules submitters hit in CI), so the third completion criterion ('residual risks documented alongside the submitter-facing rules from [guide] Content-security rules enforced by architecture validators are documented nowhere — submitters hit 'active content'/'remote reference' CI failures with no doc to consult #1096') now has a concrete home: extend that doc rather than create one.

    Current state of the corpus for whoever implements the decision: scripts/lib/svg-active-content.mjs sits at 100% lines / 99.61% regions with only the documented-unreachable ?? '' fallback uncovered, and the test file carries 121 passing cases including every historical bypass listed in this issue's body.

  3. added
    🐝 covered by PRHive verified that an open PR references or claims this issue; still actionable until confirmed
    hive/likely-doneHive verified that a merged PR references or claims this issue; pending confirmation
    and removed
    🐝 covered by PRHive verified that an open PR references or claims this issue; still actionable until confirmed
    on Oct 8, 2026
  4. mrbobbytables commented on Oct 8, 2026

    @mrbobbytables
    MemberAuthor

    Maintainer direction recorded (@mrbobbytables): option 1 — parse, don't pattern-match — is the preferred approach for the scanner replacement.

    Scope of that decision, to anchor whoever picks up the implementation:

    This settles the first completion criterion (direction decision via issue consensus). Remaining work is the implementation itself and the residual-risk documentation.

  5. removed
    hive/likely-doneHive verified that a merged PR references or claims this issue; pending confirmation
    on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestsecurityApproved by a Hive merger/owner for auto-merge on green CI

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions