Repository navigation
fix(awards): resolve award link targets through the URL parser - #508
Merged
Merged
Conversation
scripts/validate-awards.mjs gated verifiedAgainst, announcementUrl, caseStudyUrl and talkUrl with /^https:\/\//, which only asserts that a value begins with https://. It never established that the value parsed as a URL and never looked at the authority, so it accepted values whose visible prefix and real host disagree -- https://cncf.io@evil.example resolves to evil.example -- along with unparseable values such as https:// and 'https:// evil.example'. All four fields are rendered as <a href> by AwardsTimeline and MemberDirectory, so this was the only automated gate standing between data/awards.json and a clickable outbound link on the published site. Replace both prefix tests with checkHttpsUrl(), which parses with new URL(), requires the https: protocol and rejects a userinfo component. This mirrors checkUrl() in scripts/validate-launch-metrics.mjs and websiteUrl() in src/lib/profile-links.mjs, which already reject userinfo as a host-disguise vector. Two existing assertions move to the new, more specific messages; the values they feed are still rejected. Adds coverage for the userinfo, unparseable-but-https-prefixed and javascript: vectors. npm run validate:awards still passes on the committed data/awards.json (15 entries). 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 |
2 tasks
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
scripts/validate-awards.mjsgatedverifiedAgainst,announcementUrl,caseStudyUrlandtalkUrlwith/^https:\/\//, a string prefix test thatonly asserts a value begins with
https://. It never established that thevalue parsed as a URL and never looked at the authority, so it accepted:
https://cncf.io@evil.example/phishevil.example(userinfocncf.io)https://user:pass@evil.example/evil.examplehttps://https:// evil.exampleAll four fields are rendered directly as
<a href>bysrc/components/AwardsTimeline/index.js(lines 23, 46, 51, 56, 87) andsrc/components/MemberDirectory/index.js(lines 196, 205, 214), so thisvalidator was the only automated gate between
data/awards.jsonand aclickable outbound link on the published site.
What changed
Both prefix tests are replaced with a single
checkHttpsUrl()helper inscripts/validate-awards.mjsthat parses withnew URL(), requires thehttps:protocol, and rejects a userinfo component. This is not a newconvention — it mirrors what this repository already does in two places:
scripts/validate-launch-metrics.mjs:9checkUrl()— parses and checksparsed.protocol !== 'https:'src/lib/profile-links.mjswebsiteUrl()— parses, enforces the protocolallow-list, and rejects userinfo with the comment "A userinfo component is
only ever used here to disguise the real host."
tests/validate-awards.test.mjsgains coverage for the userinfo vector (bothon an entry field and on
verifiedAgainst), the unparseable-but-https://-prefixedvector, and a
javascript:URL. Two existing assertions move to the new, morespecific error messages; the values they feed are still rejected.
Verification
node --test tests/validate-awards.test.mjs— 21/21 pass (was 16)npm run validate:awards— passes on the committeddata/awards.json(15 entries)prettier --checkclean on both changed filesvalidate:awardsalready runs indeploy-gh-pages.ymlandimport-architectures.yml, so no workflow change is needed and the tightenedgate is enforced on merge
Note:
tests/awards-timeline.test.mjsfails on a cleanmaincheckout at8c089a0as well — that failure is pre-existing and untouched by this PR.Scope
Limited to
scripts/validate-awards.mjsandtests/validate-awards.test.mjs.Deliberately disjoint from the sibling prefix-test findings elsewhere: the
scripts/validate-radar-reports.mjsentry-url check is claimed by PR #496, andscripts/validate-case-studies.mjsis claimed by issue #500 / PR #501. Neitherfile is touched here.
Closes #507
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