fix(security): gate static/ root files through the published-asset security gate - #827
Merged
Merged
Conversation
…curity gate static/ is copied verbatim into the build and served at the site origin, and validate-architecture-assets.mjs gates everything published there. But checkForUngatedStaticDirs() skipped every non-directory entry, so a regular file placed directly in static/ had no enclosing directory for assetDirs to gate and was never extension-checked: static/pwn.html passed the validator, the full unit suite and the production build, shipping to the site origin with no CI signal. Gate top-level files individually, mirroring the existing directory treatment: the known non-asset files are named in exemptTopLevelFiles and everything else is held to SITE_CHROME_EXTENSIONS, which rejects anything the browser executes as markup and routes an SVG through the active-content scan. 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 Sep 29, 2026
Merged
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
static/is copied verbatim into the build and served at the site origin, andscripts/validate-architecture-assets.mjsgates everything published there — extension allow-list, symlink rejection, SVG active-content scanning.checkForUngatedStaticDirs()skipped every non-directory entry on its first statement, so a regular file placed directly instatic/had no enclosing directory forassetDirsto gate and was never extension-checked.Verified on
7772dcf:static/pwn.htmlcontaining<html><script>alert(document.domain)</script></html>passedvalidate:architecture-assets(exit 0), the full unit suite (exit 0, 1421 pass / 0 fail) andbuild:production, shipping verbatim asbuild/pwn.html— served from the site origin with no CI signal from any gate.tests/static-svg-active-content.test.mjsalready catches a script-bearing.svgat the root, but it only inspects.svgfiles and so does not constrain the file type. The gap closed here is the missing extension allow-list on top-level files.What this changes
scripts/validate-architecture-assets.mjscheckForUngatedStaticDirs→checkForUngatedStaticEntries, which now handles top-level files as well as directories. Directory handling is unchanged.exemptTopLevelFilesmap names the three legitimate non-asset root files (.nojekyll,manifest.json,robots.txt), each with the reason a reviewer needs to approve a new exemption — mirroring howexemptTopLevelDirsdocumentsfonts.validateAsset(..., SITE_CHROME_EXTENSIONS), which rejects anything the browser executes as markup and routes an SVG through the active-content scan.assetDirsthat documented this gap as accepted.tests/validate-architecture-assets.test.mjs— four tests appended: a top-level.htmlis rejected, a top-level script-bearing.svgis rejected, the three exempted root files are accepted, and a legitimate top-level image is accepted.Verification
validate:architecture-assetsexit 0 (unchanged, same single pre-existingforeignObjectwarning).html is not an allowed asset type; static/ is served at the site originandactive content: contains a <script> elementtest:unit:coverage:checkexit 0check:formatexit 0Closes #826
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