Skip to content

fix(security): gate srcset, poster and background in findRemoteReferences - #1213

Closed
hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
sec/fix-srcset-poster-background
Closed

hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
sec/fix-srcset-poster-background

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Security Fix

findRemoteReferences() in scripts/lib/svg-active-content.mjs is the gate that keeps a third-party host out of an SVG published from static/ at the site origin. mirrorArtworkUrls(), mirrorLandscapeLogo() and scripts/validate-architecture-assets.mjs all rely on it. It decides by attribute name, and gated only src and (per-element) href.

Three attributes a browser fetches on load, with no user interaction, were not gated: srcset, poster and the legacy presentational background. All three are reachable because foreignObject is deliberately allowed, so an imported diagram can carry ordinary HTML, and none of them is active content — findActiveContent() reports nothing and stripActiveContent() removes nothing. An imported reference-architecture diagram or landscape logo could therefore carry a beacon that every gate in this repository reported as clean, and a visitor opening the SVG directly — a document, not an image, and served without the meta CSP that only Docusaurus HTML pages carry — discloses their IP, User-Agent and Referer to the chosen host.

srcset needed more than adding the name. It is a comma-separated candidate list, so the whole value is not a URL: normalizeUri() strips the descriptors' whitespace, and "/local.png 1x, https://evil.example/x.png 2x" collapses to a value beginning with the local first candidate, which reads as same-origin and hides every candidate after it. Each candidate's URL part is now tested on its own. Splitting can never lose a target, because a comma cannot appear in a scheme or an authority.

Verification

  • Six regression tests added to tests/svg-active-content.test.mjs; five of them fail on main and all six pass here (the sixth pins that an all-local srcset still reports nothing).
  • node --test tests/svg-active-content.test.mjs: 127 pass, 0 fail (121 before).
  • npm run test:unit: 1693 tests / 1639 pass / 54 fail, against a main baseline of 1687 / 1633 / 54 in the same sandbox. The 54 failures are pre-existing and identical on both: @swc/core cannot load its native binding here, so the React component suites abort. No regression, and six new passes.
  • npx prettier --check clean on both files.

Files touched: scripts/lib/svg-active-content.mjs (new FETCHED_URL_ATTRIBUTES and urlAttributeTargets(), attribute branch of findRemoteReferences()) and tests/svg-active-content.test.mjs.

Disjoint from #1206, which changes CSS quote/escape pairing (stripCssComments, imageSetArguments, CSS_STRING) in the same file. This PR does not touch the CSS tokenizer, cssTargets(), or any function #1206 edits; it changes attribute-name coverage only.

Closes #1212


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

…nces

findRemoteReferences() decides by attribute name, and gated only src and
href. srcset, poster and the legacy presentational background attribute
are fetched by the browser on load with no user interaction, and are
reachable because foreignObject is deliberately allowed, so an imported
diagram could carry a third-party beacon that every gate in this
repository reported as clean.

srcset needs more than the name: it is a comma-separated candidate list,
so normalizing it undivided strips the descriptors' whitespace and reads
a local first candidate as same-origin, hiding every candidate after it.
Each candidate's URL part is tested on its own.

Closes #1212

Signed-off-by: sec-check <sec-check@hive.kubestellar.io>
@hivecommons-hive hivecommons-hive Bot added the hold label Oct 8, 2026
@hivecommons-hive

Copy link
Copy Markdown
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 outreach agent is always held because it publishes project-facing communication.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@mrbobbytables

Copy link
Copy Markdown
Member

Superseded by #1245, which replaces the regex scanners with parser-based ones (the approach decided on #1194) and covers this fix, with regression tests. Closing in favour of that PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sec-check] findRemoteReferences misses srcset, poster and background: remote beacons pass the published-SVG gate

1 participant