Repository navigation
Strengthen the static/ asset security gate: discover directories dynamically and block external references in SVGs #754
Description
Activity
- addedsecurityApproved by a Hive merger/owner for auto-merge on green CIApproved by a Hive merger/owner for auto-merge on green CI
on Sep 27, 2026 hivecommons-hive commented
on Sep 27, 2026 ContributorMore actionsScanner analysis @ main 26946ba (2026-09-27)
Both gaps confirmed present at HEAD. #753 is merged (extended the gate to
static/img+static/favicons); the two structural gaps below remain open.Gap 1 — hardcoded directory list (from #697)
scripts/validate-architecture-assets.mjs:55-70definesassetDirsas a fixed list (static/img/architectures,static/img/cncf-projects,static/img/awards, shallowstatic/img,static/favicons). Nothing walksstatic/itself. A contributor addingstatic/downloads/foo.svg(or any new subdirectory) gets published at the site origin with zero CI signal — extension allow-list, symlink rejection, and SVG checks all silently skip it. Verified: currentstatic/containsfavicons/,fonts/,img/,manifest.json,robots.txt; onlyimg/faviconsare gated, and the exemptions forfonts/+ root files exist only in a comment (lines 52-54), not in code.Fix direction: replace the static list with discovery — walk
static/one level deep, and require every subdirectory and every root-level file to be either:- claimed by an
assetDirsentry (gate applies), or - listed in an explicit
EXEMPT_PATHSmap with a reason string (e.g.static/fonts→ "no SVG, extensions legitimately outside image allow-list").
Anything unclaimed and unexempted is a hard error. This converts "ungated by default" into "gated or loudly exempted", so a new directory fails CI until a human classifies it.
Gap 2 — no external-reference check in the SVG gate (from #745)
scripts/lib/svg-active-content.mjs(findActiveContent, line 162) covers<script>, event-handler attributes,javascript:URIs, and<animate>/<set>elements that animatehref(lines 60-67) — but a plain static external reference passes untouched. Verified: no pattern insvg-active-content.mjsmatcheshref="http(s)://…",xlink:hrefto an external origin, or CSSurl(https://…). An imported architecture diagram can carry<image href="https://attacker.example/track.png">or<use href="https://third-party.example/sprite.svg#icon">and the gate reports nothing — the site origin hot-links third-party content, enabling tracking pixels and supply-chain drift (the remote bytes change without any PR).Fix direction: extend the SVG gate (likely as a sibling check in
validateSvg, or a new exported check next tofindActiveContent) to reject, for gated quality dirs:href/xlink:hrefvalues starting withhttp://orhttps://(protocol-relative//too), on any element- CSS
url()with an http(s)/protocol-relative argument, in bothstyleattributes and<style>elements
Namespace declarations (
xmlns="http://www.w3.org/…") are identifiers, not fetches, and must be allowlisted. Same-origin/relative references anddata:URIs for non-raster content are fine (rasterdata:is already caught separately). Like active-content findings, these should be errors a human reviews — not auto-fixed.Suggested implementation plan (one PR can close this)
- Add
static/directory discovery +EXEMPT_PATHSmap with required reason strings; error on unclaimed paths - Add external-reference detection for SVG
href/xlink:href/url()withxmlnsallowlist - Unit tests: ungated new subdir → error; exempted path with reason → pass; external
href/url()→ error;xmlns, relative refs, same-origin → pass - Run
--fix-less gate against current tree to confirm zero new findings on existing assets
🐝 Hive Agent:
scanner| Instance:hosted-available-lke648397-260827-5n31| SHA:unknown— hive: agent=scanner backend=copilot model=kimi-k3 copilot=1.0.88
- claimed by an
hivecommons-hive commented
on Sep 28, 2026 ContributorMore actionsStatus update (main @e0b7571): one of two goals shipped
Goal 1 — extend the SVG gate to reject external URL references: SHIPPED. Merged PR #775 (
fix(security): gate remote resource references in imported SVG diagrams) added remote-reference rejection toscripts/lib/svg-active-content.mjs— it now covershref/xlink:hrefon resource-loading elements, CSSurl(...)targets, and<animate>/<set>installing an href at runtime, with tests intests/svg-active-content.test.mjsandtests/static-svg-active-content.test.mjs.Goal 2 — dynamic discovery of
static/subdirectories: STILL OPEN.scripts/validate-architecture-assets.mjs:58still uses a hardcodedassetDirslist, so a newly addedstatic/subdirectory is published without passing the gate until a maintainer hand-adds it.Suggest narrowing this issue's scope/title to goal 2 only, so a single PR (walk
static/top-level directories and derive the gate set, keeping the documented exclusions forstatic/fontsand thestatic/root files) can close it.
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
- added a commit that references this issue
on Sep 29, 2026
Consolidates two related findings about the static/ asset security gate in scripts/validate-architecture-assets.mjs:
Fix direction: walk static/ and require every subdirectory to be either gated or explicitly exempted with a reason, and extend the SVG gate to reject external URL references (href/xlink:href/url() to non-site origins).
Note: #753 (consolidated security fixes) already extends the gate to static/img and static/favicons; this issue covers the remaining structural gaps.