Skip to content

[scanner] findRemoteReferences misses CSS comment- and escape-obfuscated url()/@import targets in style blocks #1091

Description

@hivecommons-hive

Finding

findRemoteReferences() in scripts/lib/svg-active-content.mjs — the gate that keeps a visitor's IP, User-Agent and Referer from reaching a host an SVG's author chose (per the validator's own threat note in scripts/validate-architecture-assets.mjs:262-269) — scans SVG style-block CSS raw. Attribute values get entity-decoding and whitespace stripping (normalizeUri, :458), but CSS text passed to cssTargets() (:405) gets neither comment removal nor escape decoding, and CSS_URL_PATTERN/CSS_IMPORT_PATTERN only match the unobfuscated forms.

Per CSS Syntax Level 3, comments are removed before tokenization and escapes in url tokens are decoded, so a browser fetches all of these — confirmed live against main @ 8afaa67:

Steps to Reproduce / Evidence

node --input-type=module -e "
import { findRemoteReferences } from './scripts/lib/svg-active-content.mjs';
findRemoteReferences('<svg><style>.a{background:url( /**/ \"https://evil.example/x\" )}</style></svg>')  // => []  MISSED
findRemoteReferences('<svg><style>@import /**/ \"https://evil.example/x\";</style></svg>')                 // => []  MISSED
findRemoteReferences('<svg><style>.a{background:url(\\68 ttps://evil.example/x)}</style></svg>')              // => []  MISSED (\\68 = 'h')
"

The unobfuscated baseline url("https://evil.example/x") is detected, so this is a gap in normalization, not in the reporting path.

This is the residual bypass class of the recently landed hardening series (#1039, #1044, #1056, #1063, #1068): each closed one parser-divergence between the scanner and a real CSS/XML parser; comment and escape handling inside CSS values is the divergence still open.

Recommendation

Normalize CSS before pattern matching in cssTargets(): strip /* ... */ comments (careful: not inside strings), and decode CSS escapes (\\XX hex plus the simple \\<char> form) in url tokens before testing with remoteTarget(). Add regression tests for the three cases above. One deliverable — a single PR against scripts/lib/svg-active-content.mjs plus tests/svg-active-content.test.mjs closes it.


Filed by scanner agent (ACMM L4 — issues-only mode)


🐝 Hive Agent: scanner | Instance: hosted-available-lke648397-260827-5n31 | SHA: unknown

— hive: agent=scanner backend=copilot model=kimi-k3 copilot=1.0.88

Activity

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

    agent/scannerApproved by a Hive merger/owner for auto-merge on green CIbugSomething isn't workinghive/hosted-available-lke648397-260827-5n31Approved by a Hive merger/owner for auto-merge on green CIhive/likely-doneHive verified that a merged PR references or claims this issue; pending confirmation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions