Skip to content

fix: reject non-https URLs in data/metrics.json (scripts/validate-metrics.mjs) - #304

Open
kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
sec/validate-metrics-url-scheme
Open

kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
sec/validate-metrics-url-scheme

Conversation

@kubestellar-hive

Copy link
Copy Markdown
Contributor

Security Fix

scripts/validate-metrics.mjs is the only gate on data/metrics.json, and it checked every URL field for presence but never for scheme. Every one of those values is rendered directly into an <a href> on the published site, so a javascript: value passed npm run validate:metrics and was emitted verbatim into the built HTML.

Six sinks were unguarded:

field rendered at
metrics[].sourceUrl src/components/MetricsDashboard/index.js:33
series.*.sourceUrl src/components/MetricsDashboard/index.js:39
breakdowns.*.sourceUrl src/components/MetricsDashboard/index.js:50
referenceArchitectureLifecycle.sourceUrl src/components/MetricsDashboard/index.js:19
sources.architectures.repository src/components/ReferenceArchitectures/index.js:26 and, concatenated into commitUrl, :30
sources.*.sourceUrl provenance value, never validated

sources.*.repository is string-concatenated (`${repository}/commit/${revision}`), so a javascript: value survives the concatenation as a javascript: URL.

scripts/validate-awards.mjs already performs the equivalent check for the sibling file data/awards.json; this brings validate-metrics.mjs in line.

What changed

scripts/validate-metrics.mjs gains a checkUrl() helper that parses with new URL (so relative and unparseable values are rejected too) and requires the https: scheme, wired into all six sinks.

  • Absent values are skipped, so the existing presence checks remain the single source of "missing".
  • Every pre-existing error message and its path are byte-identical. The two Object.values loops became Object.entries only so the new error can name the offending key.
  • The current data/metrics.json passes unchanged — all six live values are already https://.

Verification

$ npm run validate:metrics
Validated 2 metrics                       # real repo data, exit 0

# with metrics[0].sourceUrl and sources.architectures.repository poisoned:
$ npm run validate:metrics
2 error(s) in metrics:
  [error] sources.architectures: repository must use https, got javascript:
  [error] cncf-projects: sourceUrl must use https, got javascript:
$ echo $?
1

$ node --test tests/validate-metrics-urls.test.mjs tests/validate-metrics.test.mjs tests/validators-smoke.test.mjs
# pass 27, fail 0

Files and coordination

This PR claims exactly two files:

  • scripts/validate-metrics.mjs — the fix
  • tests/validate-metrics-urls.test.mjs — new file, 9 tests

No other open PR touches scripts/validate-metrics.mjs. The new tests deliberately live in a new file rather than in tests/validate-metrics.test.mjs, which open PR #263 is editing, so the two do not conflict. #287 (tests/metrics-data.test.mjs) and #239 (tests/projects-born-data.test.mjs) are likewise test-only and in different files.

Closes #303


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

validate-metrics.mjs checked every URL field in data/metrics.json for
presence but never for scheme, while every one of those values is
rendered directly into an <a href> by MetricsDashboard and by the
SyncStatus block in ReferenceArchitectures. A javascript: value in
metrics[].sourceUrl, series.*.sourceUrl, breakdowns.*.sourceUrl,
referenceArchitectureLifecycle.sourceUrl or sources.*.repository passed
npm run validate:metrics and was emitted verbatim into the built HTML.

sources.*.repository is also string-concatenated into a commit URL, so a
javascript: value there survives the concatenation as a javascript: URL.

Adds a checkUrl() helper that parses with new URL and requires the https
scheme, wired into all six sinks. Absent values are skipped so the
existing presence checks remain the single source of 'missing', and
every pre-existing error message and path is unchanged.

Closes #303

Signed-off-by: kubestellar-hive[bot] <kubestellar-hive@hive.kubestellar.io>
@kubestellar-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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sec-check] validate-metrics.mjs never checks URL schemes: a javascript: sourceUrl in data/metrics.json passes the gate and is rendered as an href

0 participants