Repository navigation
fix(security): treat backslash authority prefixes as remote in remoteTarget() - #1068
Merged
Merged
Conversation
remoteTarget() accepted only `https?://` and a `//` prefix when deciding whether an SVG value points at another host. The URL parser treats `\` as `/` in the scheme and authority prefix of a special-scheme URL, and the site is served over https, so `\\host`, `/\host`, `\/host` and `https:\\host` all resolve to host exactly as `//host` does while the gate reported them local. findRemoteReferences() routes every href/src value and every url()/@import CSS target through remoteTarget(), so an imported diagram could reference an attacker-chosen host and still pass validate:architecture-assets. A visitor opening the published SVG then discloses their IP, User-Agent and Referer to that host -- the exposure the gate exists to prevent. Translate only the leading run of separators: a single separator keeps the value on this origin (`\host` is the path /host) and an interior backslash stays an ordinary path character, so `./sub\dir/x.png` is still local. Signed-off-by: sec-check <sec-check@hive.kubestellar.io>
Contributor
Author
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "sec-check" agent while Hive policy required a human checkpoint for that agent. Non-outreach agents are held at ACMM L3–L5; the Hive will automatically remove the |
This was referenced Oct 5, 2026
This was referenced Oct 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security Fix
remoteTarget()inscripts/lib/svg-active-content.mjsis the single hosttest behind
findRemoteReferences(). It accepted onlyhttps?://and a//prefix.
The WHATWG URL standard treats
\as equivalent to/in the scheme andauthority prefix of a special-scheme URL, and the site is served over
https, so every relative reference in a published SVG resolves against a
special-scheme base. These values therefore reach a third-party host exactly
as
//hostdoes, while the gate reported every one of them local:\\evil.example/phttps://evil.example/p/\evil.example/phttps://evil.example/p\/evil.example/phttps://evil.example/phttps:\\evil.example/phttps://evil.example/phttps:/\evil.example/phttps://evil.example/p//evil.example/phttps://evil.example/pBecause
findRemoteReferences()routes everyhref/srcvalue and everyurl()/@importCSS target throughremoteTarget(), the bypass applied toall of them at once, and it is the only remote-reference check in
scripts/lib/enduser-collector.mjs:201as well.What changed
remoteTarget()now normalizes the leading authority prefix the way the URLparser does, translating
\to/only in the leading run of separators.The narrow scope is deliberate and is pinned by tests: a single leading
separator keeps the value on this origin (
\hostis the path/host, andhttps:/hostlikewise), and an interior backslash stays an ordinary pathcharacter, so
a\b/c.pngand./sub\dir/x.pngstill report local. Wideningthe translation would have failed diagrams that reference their own sibling
assets.
Verification
End to end through the real validator, with the PoC planted under
static/img/architectures/:npm run test:unit— 1923/1923 pass (1912 baseline + 11 added here)remoteTarget()change fails 7 of the 11 added tests, sothey are load-bearing rather than restating current behaviour
npm run check:formatcleannpm run test:unit:coverage:checkpasses (99.40% lines / 94.88% regions)Scope
Touches
remoteTarget()only (scripts/lib/svg-active-content.mjs:243) plusits tests. Deliberately disjoint from the other open held PRs:
STYLE_BLOCK_PATTERN/styleBlockContentsin the same file atlines 210-220 and 308-315 — different function, non-overlapping hunks
mirrorArtworkUrls()call this gate; this PR fixes what thegate tests. Complementary, different file
project-assets.mjsCloses #1067
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode). Hold-gated: human review required.
— hive: agent=sec-check backend=copilot model=claude-opus-5 copilot=1.0.88