[sec-check] validate:end-user-talks is missing from ci.yml, so the required status check never gates the URLs EndUserTalkSchedule renders as hrefs
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 74/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- github-actions, javascript
Research direction
Read .github/workflows/ci.yml and scripts["validate:all"] in package.json, then compare their validator steps with ciValidators() in tests/netlify-publish-contract.test.mjs. Add the missing End User talks validator step and the reverse inclusion test described in the issue. Run npm run test:unit; done means the CI validator list matches validate:all and the tests pass.
Written by the indexing model from the issue text.
Description
Security Finding
Severity: medium
Type: missing-gate (required status check does not run a URL validator)
scripts/validate-end-user-talks.mjs is the scheme/host gate for the three
fields src/components/EndUserTalkSchedule/index.js renders as <a href>:
index.js:25—<a href={schedule.apiUrl} …>index.js:30—<a href={schedule.sourceUrl} …>index.js:57—<a href={talk.url} …>
That validator is in validate:all (package.json) but it is the only one of
the fourteen that is missing from the validate job in
.github/workflows/ci.yml, which is the job behind the required status check
Validate repository.
Reproduced against b490a7f, comparing the npm run validate:* steps in
ci.yml's validate job with the targets chained in scripts["validate:all"]:
IN validate:all BUT NOT ci.yml:
npm run validate:end-user-talks
The branch ruleset for main requires exactly two checks — Validate repository and Lint repository, both GitHub Actions. The Netlify deploy
check is not a required check. So a pull request that edits
data/end-user-talks.json passes every required check and merges, with the
validator that exists specifically to reject a javascript: scheme or an
off-host link never having run on the change.
Impact
data/end-user-talks.json is maintained through ordinary pull requests, which
is precisely the lane ci.yml gates. A change to it that sets talk.url,
sourceUrl or apiUrl to a javascript: URI, or to a host outside the
schedule host the validator pins, merges to main unchallenged.
Publication is still blocked — the Netlify build runs validate:all, so the
deploy fails and the previous deploy stays live — so this is not a live XSS on
the published site. The damage is that the gate moves from "rejected in review"
to "merged, then every deploy is frozen until someone reverts it": main
carries the bad data, and no site update can ship until it is removed.
The drift went unnoticed because the guard in
tests/netlify-publish-contract.test.mjs:80 asserts only one direction —
every validator ci.yml runs must also be in validate:all. A validator present
in validate:all but absent from ci.yml satisfies that assertion, which is
exactly the state the repository is in.
Recommendation
Two edits. They must land together, or the workflow edit first: the test edit
alone fails on main until the ci.yml step exists.
1. .github/workflows/ci.yml — add the missing step. Insert between the
existing Validate projects-born data and Validate button contrast steps, so
the job order keeps matching validate:all:
- name: Validate projects-born data
run: npm run validate:projects-born
- name: Validate End User talks data
run: npm run validate:end-user-talks
- name: Validate button contrast
run: npm run validate:button-contrast
2. tests/netlify-publish-contract.test.mjs — close the one-way guard so
the two sets cannot drift apart again in either direction. Add after the
existing validate:all runs everything the PR lane validates test:
test('the PR lane validates everything validate:all does', () => {
const inCi = ciValidators();
const inAll = new Set(
npmRunTargets(scripts['validate:all'] ?? '').filter((target) =>
target.startsWith('validate:'),
),
);
const missing = [...inAll].filter((target) => !inCi.has(target));
assert.deepEqual(
missing,
[],
'validators validate:all runs that ci.yml does not; the required status ' +
'check is the only gate a human-authored data pull request passes, so ' +
'a validator missing from it lets that data merge unvalidated',
);
});
The existing test asserts ci.yml ⊆ validate:all; this one asserts
validate:all ⊆ ci.yml. Together they pin the two lists as equal.
Why no pull request accompanies this issue
Edit 1 is in .github/workflows/. This agent's token is minted at the
contributor tier, which does not carry the Workflows permission, so GitHub
rejects any push whose diff touches that directory. Edit 2 is pushable on its
own, but landing it alone would turn main red, because the assertion it adds
fails until edit 1 exists. Both edits are therefore left here as exact
replacement text; applying them needs a human maintainer or an agent with
workflow-write scope.
Completion criteria
-
.github/workflows/ci.ymlrunsnpm run validate:end-user-talksin thevalidatejob -
tests/netlify-publish-contract.test.mjsassertsvalidate:all ⊆ ci.ymlvalidators -
npm run test:unitpasses with both edits applied
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)
🐝 Hive Agent: security | Instance: hosted-available-lke648397-260827-5n31 | SHA: b490a7f
— hive: agent=sec-check backend=copilot model=claude-opus-5 copilot=1.0.88
- Dominant language
- JavaScript
- Stars
- 0
- Forks
- 3
- Avg merge
- 7h 15m
- Merged PRs (30d)
- 623
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from cncf/endusers
-
[sec-check] collect-metrics.mjs tallies upstream landscape category and maturity names on prototype-bearing objects, corrupting or dropping published countsPossibly taken @hivecommons-hive claimed this today. Openagent/sec-check security stage/040-covered-by-pr
Difficulty 1/5 Under an hour Newbie friendliness 25/100
Maintainers usually reply within 1 day
-
[sec-check] ip-address 10.7.2 carries ReDoS advisory GHSA-rxp7-6hxx-x8q5; patched 10.7.4 is a lockfile-only bumpPossibly taken @hivecommons-hive claimed this today. Openagent/sec-check security stage/040-covered-by-pr
Difficulty 1/5 Under an hour Newbie friendliness 10/100
Maintainers usually reply within 1 day
-
agent/strategist roadmap stage/045-needs-decision
Difficulty 5/5 Over a week Newbie friendliness 25/100
cncf/endusers#1822 · 1 comment ·
Maintainers usually reply within 1 day
-
[architect] Duplicated interactive-card hover/focus-visible CSS across CNCFProjectCard, MetricsDashboard, ReferenceArchitecturesPossibly taken @hivecommons-hive claimed this today. Openagent/architect architecture stage/040-covered-by-pr tech-debt
Difficulty 3/5 1-2 days Newbie friendliness 25/100
Maintainers usually reply within 1 day
-
[quality] Mutation testing discards the coverage of every script tests/helpers.mjs spawnsPossibly taken @hivecommons-hive claimed this today. Openagent/quality stage/040-covered-by-pr testing
Difficulty 4/5 3-5 days Newbie friendliness 25/100
cncf/endusers#1817 · 2 comments ·
Maintainers usually reply within 1 day
Similar issues
-
type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
Update to mocha 12.xOpen
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
rescript-lang/rescript#8996 ·
Maintainers usually reply within 1 day
-
check:passed logos:add
Difficulty 2/5 1-3 hours Newbie friendliness 68/100