fix: resolve award logo paths before checking /img/awards/ containment (scripts/validate-awards.mjs) - #329
Merged
Conversation
…/ containment
The award logo gate in scripts/validate-awards.mjs tested the raw value with
startsWith('/img/awards/') and then resolved that same raw value through
new URL(), which normalises '..' away. A value like
/img/awards/../../../../../etc/hostname passed the prefix test and resolved
outside the repository, so the containment invariant never held and the
existsSync probe ran against an arbitrary absolute path on the build runner.
Resolve the path first and check containment against the resolved
static/img/awards/ directory, probing for existence only once containment
holds. Also reject a non-string logo instead of throwing a TypeError out of
startsWith.
Closes #327
Signed-off-by: kubestellar-hive[bot] <kubestellar-hive@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 20, 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
Files claimed by this PR:
scripts/validate-awards.mjs(awardlogocontainment check) and
tests/validate-awards.test.mjs. No other file istouched.
scripts/validate-awards.mjsenforced "logo must live under/img/awards/"by testing the raw value with
startsWith('/img/awards/')and thenresolving that same raw value through
new URL('../static' + entry.logo, ...),which normalises
..segments away. The two steps disagreed:So the containment invariant never actually held, and the
existsSyncproberan against an arbitrary absolute path on the build runner (
validate:awardsruns in
deploy-gh-pages.ymlandimport-architectures.yml). An escaped valuealso propagates:
scripts/generate-members.mjspickLogo()copiesawardEntries[0].logointodata/members.json, andsrc/components/AwardsTimeline/index.js/src/components/MemberDirectory/index.jsrender it as
<img src={useBaseUrl(logo)}>.What changed
static/first, then require the resolvedpath to sit inside
static/img/awards/(with a trailing separator soimg/awards-other/cannot pass). The/img/awards/prefix test is kept aswell, so the error message and behaviour for ordinary wrong-directory values
are unchanged.
existsSynconly after containment holds, removing thearbitrary-path existence oracle.
logowith a reported error instead of throwingTypeError: entry.logo.startsWith is not a functionout of the validator.Falsy/absent
logovalues are still skipped exactly as before.Verification
npm run test:unit: 58/58 pass (was 55; 3 new cases —..escape out ofimg/awards/,..escape out ofstatic/, and a non-string logo).npm run validate:awardsagainst real repo data:Validated 15 award entries,exit 0 — no behaviour change for the 10 real
/img/awards/*.svgvalues.npx prettier --checkclean on both changed files.Disjointness
Cut fresh from
origin/main@00b44df. No other open PR touchesscripts/validate-awards.mjsortests/validate-awards.test.mjs: #304 changesscripts/validate-metrics.mjs+tests/validate-metrics-urls.test.mjs, #231changes
tests/helpers.mjs+tests/validate-architecture-assets.test.mjs,#253 changes
tests/members-data.test.mjs, #185 changestests/validate-utils.test.mjs.Closes #327
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