Repository navigation
fix(security): fail the audit gate when an allowlisted advisory goes stale - #1296
Conversation
…stale scripts/audit-gate.mjs suppresses high/critical npm audit findings through ALLOWLISTED_ADVISORIES, on the premise -- stated in its header and in SECURITY.md -- that no patched release exists for the advisory. Nothing re-tested that premise, so the allowlist could only grow: the file asked for manual removal "the moment upstream publishes a fix", which is not an event anything in this repository observes. That premise has already been lost once here. SECURITY.md documented GHSA-ch52-4w7c-c8xp as unpatched while upstream had shipped 4.3.0, caught only by a hand re-check of the registry (#1050). Add unusedAllowlistEntries(), which reports allowlist entries that no advisory in the report reaches at any severity or any depth of the via chains, and fail the gate on them, naming both places to delete the entry from. An entry matching nothing suppresses nothing, and would silently accept the advisory again if a later dependency change reintroduced it. The check runs after the blocked-advisory check so a live unfixed advisory stays the first thing reported. This intentionally changes one contract: with a non-empty allowlist, a report with no vulnerabilities at all now fails, because that state means the allowlist is dead; the CLI test is updated to pin the new behaviour. The currently allowlisted braces advisory is still live (3.0.3 remains latest), so `npm run check:audit` still exits 0 against this lockfile. Closes #1295 Signed-off-by: sec-check <sec-check@hive.kubestellar.io>
|
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 keep the |
1c4c251
ℹ️ Sentinel notice — informational; author is trusted (hive agent), merge is not blockedHive flagged this PR (author @hivecommons-hive[bot], head
Hive did not add the |
…a array The `entry.via ?? []` fallback in reportedAdvisoryIds() had no test reaching it, leaving scripts/audit-gate.mjs at 98.04% regions, the one source file under 100% and the one that would fail the ratchet in #1298. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Killen <bkillen@linuxfoundation.org>
be9eac8
ℹ️ Sentinel notice — informational; author is trusted (hive agent), merge is not blockedHive flagged this PR (author @hivecommons-hive[bot], head
Hive did not add the |
Security Fix
scripts/audit-gate.mjsdecides whether a high/criticalnpm auditfindingblocks CI, and suppresses findings through
ALLOWLISTED_ADVISORIESon thepremise — stated in its own header and in SECURITY.md — that no patched
release exists for the allowlisted advisory.
Nothing re-tested that premise. The file asked for manual removal "the moment
upstream publishes a fix", which is not an event anything in this repository
observes, so the allowlist could only ever grow.
This repository has already lost that premise once: SECURITY.md documented
GHSA-ch52-4w7c-c8xp as unpatched while upstream had shipped
4.3.0, caughtonly because somebody re-checked the registry by hand (#1050). SECURITY.md
still carries the resulting warning that "no patched version" is only true as
of the day it was written — this makes the gate enforce it.
What changes
scripts/audit-gate.mjs— addsunusedAllowlistEntries(), whichcollects every advisory id the report mentions (at any severity, at any
depth of the
viachains) and returns the allowlist entries none of themreach.
main()fails the gate on a non-empty result, naming both places todelete the entry from.
tests/audit-gate.test.mjs— 7 unit tests (present, absent, rescoredseverity, nested behind a string
via, empty report, missingvulnerabilitieskey, shipped-allowlist default) plus the updated CLI test.SECURITY.md— records that the gate now enforces the removal.Severity is deliberately not filtered when scanning: an advisory rescored from
high to moderate is still in the lockfile, so the entry covering it is still
doing work and must not be called stale.
The check runs after the existing blocked-advisory check, so a live
unfixed advisory outside the allowlist remains the first thing reported.
Behaviour change, called out
With a non-empty allowlist, a report containing no vulnerabilities at all
now exits 1 rather than 0, because that state means every allowlisted advisory
has left the lockfile and the suppression is dead. The CLI test that pinned
clean report → exit 0is updated to pin the new contract; theokpathstays covered by the "every finding is allowlisted" CLI test.
Verification
node --test tests/audit-gate.test.mjs→ 26/26 passnpm run check:auditagainst the real lockfile → exits 0,audit-gate: ok — 28 high/critical finding(s). The braces advisory is stillgenuinely live (
npm view braces dist-tags→{ latest: '3.0.3' },verified 2026-10-10), so this does not turn CI red today.
npm run test:unit→ 66 pre-existing failures both before and after thischange (an
@swc/corenative-binding limitation in the scan sandbox,unrelated to this diff); no regression.
npx prettier --checkclean on all three files.Scope
Touches only
scripts/audit-gate.mjs,tests/audit-gate.test.mjsandSECURITY.md— disjoint from the files held in #1289 (docusaurus.config.js,tests/site-config.test.mjs), #1293 (scripts/lib/validate-utils.mjs,tests/validate-utils.test.mjs) and #1294 (tests/tools/coverage-report.mjs,tests/coverage-report-*.test.mjs).Closes #1295
Hold-gated: human review required.
— hive: agent=sec-check backend=copilot model=claude-opus-5 copilot=1.0.88