Skip to content

Strengthen the static/ asset security gate: discover directories dynamically and block external references in SVGs #754

Description

@mrbobbytables

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.

Activity

  1. added
    securityApproved by a Hive merger/owner for auto-merge on green CI
    on Sep 27, 2026
  2. hivecommons-hive commented on Sep 27, 2026

    @hivecommons-hive
    Contributor

    Scanner 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-70 defines assetDirs as a fixed list (static/img/architectures, static/img/cncf-projects, static/img/awards, shallow static/img, static/favicons). Nothing walks static/ itself. A contributor adding static/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: current static/ contains favicons/, fonts/, img/, manifest.json, robots.txt; only img/favicons are gated, and the exemptions for fonts/ + 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 assetDirs entry (gate applies), or
    • listed in an explicit EXEMPT_PATHS map 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 animate href (lines 60-67) — but a plain static external reference passes untouched. Verified: no pattern in svg-active-content.mjs matches href="http(s)://…", xlink:href to an external origin, or CSS url(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 to findActiveContent) to reject, for gated quality dirs:

    • href / xlink:href values starting with http:// or https:// (protocol-relative // too), on any element
    • CSS url() with an http(s)/protocol-relative argument, in both style attributes and <style> elements

    Namespace declarations (xmlns="http://www.w3.org/…") are identifiers, not fetches, and must be allowlisted. Same-origin/relative references and data: URIs for non-raster content are fine (raster data: 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_PATHS map with required reason strings; error on unclaimed paths
    • Add external-reference detection for SVG href/xlink:href/url() with xmlns allowlist
    • 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

  3. hivecommons-hive commented on Sep 28, 2026

    @hivecommons-hive
    Contributor

    Status 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 to scripts/lib/svg-active-content.mjs — it now covers href/xlink:href on resource-loading elements, CSS url(...) targets, and <animate>/<set> installing an href at runtime, with tests in tests/svg-active-content.test.mjs and tests/static-svg-active-content.test.mjs.

    Goal 2 — dynamic discovery of static/ subdirectories: STILL OPEN. scripts/validate-architecture-assets.mjs:58 still uses a hardcoded assetDirs list, so a newly added static/ 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 for static/fonts and the static/ 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

  4. added a commit that references this issue on Sep 29, 2026
    4c26f6f
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

    securityApproved 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