Skip to content

fix(security): parse members.json URLs instead of prefix-matching them - #731

Closed
hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
sec/fix-members-url-gate
Closed

hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
sec/fix-members-url-gate

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Security Fix

data/members.json is imported straight into the bundle
(src/components/MemberDirectory/index.js:2) and its URLs render as live
<a href> links on /community/members — announcementUrl, caseStudyUrl
and talkUrl in MemberProfile.js, plus sourceAttribution[] and
architectures[].sourceUrl.

Unlike every other href-rendering data file it has no validator script:
no validate:members in package.json, nothing for it in ci.yml's
validator list, and it is absent from READ_ONLY_VALIDATORS in
tests/validators-smoke.test.mjs. Its only gate was the /^https:\/\//
prefix regex in tests/members-data.test.mjs.

That is precisely the test this repo's own validators document as
insufficient (scripts/validate-awards.mjs:17-20,
scripts/validate-architectures.mjs:22-29):
https://www.cncf.io@evil.example/phish matches the prefix while resolving
to evil.example, and the bare string https:// matches while failing to
parse at all. The awards cross-check does not compensate — it compares only
the slug/year/award key, never the URL values.

Before

Poisoning one announcementUrl with https://www.cncf.io@evil.example/phish
left every gate in the repository green:

ℹ tests 14
ℹ pass 14
ℹ fail 0
$ npm run -s validate:awards
Validated 15 award entries

After

AssertionError: adobe award announcementUrl must not carry userinfo;
  its real host is evil.example (https://www.cncf.io@evil.example/phish)

What this changes

tests/members-data.test.mjs only. Adds httpsUrlProblem() /
assertHttpsUrl() — parse with new URL(), require protocol === 'https:',
reject any username/password — mirroring isHttpsUrl() in
scripts/validate-architectures.mjs, and applies it to
architectures[].sourceUrl, the three award URLs and sourceAttribution[].
Two regression tests cover the userinfo-spoofed, bare-https://,
wrong-scheme, whitespace and non-string forms alongside ordinary https links.

No workflow change is needed: tests/members-data.test.mjs already runs in CI
through the npm run test:unit:coverage:check step in .github/workflows/ci.yml.

Verification

  • TZ=UTC node --test tests/members-data.test.mjs — 16/16 pass against real data
  • npm run test:unit:coverage:check — exit 0, src files 100.00% lines / 97.95% regions
  • npx prettier --check tests/members-data.test.mjs — clean
  • data/members.json is unmodified by this PR

Files/functions claimed: tests/members-data.test.mjs (httpsUrlProblem,
assertHttpsUrl, and the three URL assertions). Disjoint from #684
(scripts/validate-projects-born.mjs), #688 (validator fallback-label
coverage), #717 (validate-community-groups.mjs) and #725
(validate-community-people.mjs).

Closes #730


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

data/members.json renders as <a href> on /community/members via
MemberProfile.js, but it has no validator script: there is no
validate:members, nothing for it in ci.yml's validator list, and it is
absent from READ_ONLY_VALIDATORS in validators-smoke.test.mjs. Its only
gate was the /^https:\/\// prefix regex in members-data.test.mjs.

That is the test validate-awards.mjs and validate-architectures.mjs
already document as insufficient: "https://www.cncf.io@evil.example/"
matches the prefix while resolving to evil.example, and the bare string
"https://" matches while failing to parse at all. The awards
cross-check does not compensate, because it compares only the
slug/year/award key and never the URL values.

Gate architectures[].sourceUrl, the three award URLs and every
sourceAttribution entry on a parsed URL that must use https and must
carry no userinfo, mirroring isHttpsUrl() in validate-architectures.mjs,
and cover the spoofed forms.

Signed-off-by: hivecommons-hive[bot] <hivecommons-hive@hive.kubestellar.io>
@hivecommons-hive

Copy link
Copy Markdown
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 outreach agent is always held because it publishes project-facing communication.

Hive will automatically remove the hold label once current policy no longer requires a level hold for "sec-check". If this is an outreach PR, a human must review it and remove the label.

@hivecommons-hive hivecommons-hive Bot added security Approved by a Hive merger/owner for auto-merge on green CI agent/security Approved by a Hive merger/owner for auto-merge on green CI hive/hosted-available-lke648397-260827-5n31 Approved by a Hive merger/owner for auto-merge on green CI labels Sep 27, 2026
@mrbobbytables

Copy link
Copy Markdown
Member

Superseded by #753, which consolidates the six open security-fix PRs (commits cherry-picked unmodified, authorship and DCO preserved).

@mrbobbytables
mrbobbytables deleted the sec/fix-members-url-gate branch September 28, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent/security Approved by a Hive merger/owner for auto-merge on green CI hive/hosted-available-lke648397-260827-5n31 Approved by a Hive merger/owner for auto-merge on green CI hold security Approved by a Hive merger/owner for auto-merge on green CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sec-check] data/members.json href URLs are gated only by a ^https:// prefix regex, so a userinfo-spoofed host ships to the live site

1 participant