Skip to content

fix(security): fail the audit gate when an allowlisted advisory goes stale - #1296

Merged
mrbobbytables merged 2 commits into
mainfrom
sec/audit-gate-stale-allowlist
Oct 11, 2026
Merged

mrbobbytables merged 2 commits into
mainfrom
sec/audit-gate-stale-allowlist

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Security Fix

scripts/audit-gate.mjs decides whether a high/critical npm audit finding
blocks CI, and suppresses findings through ALLOWLISTED_ADVISORIES on the
premise — 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, caught
only 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 — adds unusedAllowlistEntries(), which
    collects every advisory id the report mentions (at any severity, at any
    depth of the via chains) and returns the allowlist entries none of them
    reach. main() fails the gate on a non-empty result, naming both places to
    delete the entry from.
  • tests/audit-gate.test.mjs — 7 unit tests (present, absent, rescored
    severity, nested behind a string via, empty report, missing
    vulnerabilities key, 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 0 is updated to pin the new contract; the ok path
stays covered by the "every finding is allowlisted" CLI test.

Verification

  • node --test tests/audit-gate.test.mjs → 26/26 pass
  • npm run check:audit against the real lockfile → exits 0,
    audit-gate: ok — 28 high/critical finding(s). The braces advisory is still
    genuinely 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 this
    change (an @swc/core native-binding limitation in the scan sandbox,
    unrelated to this diff); no regression.
  • npx prettier --check clean on all three files.

Scope

Touches only scripts/audit-gate.mjs, tests/audit-gate.test.mjs and
SECURITY.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

…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>
@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 keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author
1c4c251

ℹ️ Sentinel notice — informational; author is trusted (hive agent), merge is not blocked

Hive flagged this PR (author @hivecommons-hive[bot], head 1c4c25161fdc) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 1 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • SECURITY.md
  • security_policy_edit — edits security policy, scanner config, rulesets or hooks (Edits SECURITY.md, dependabot/CodeQL config, rulesets or git hooks)
    • SECURITY.md

Hive did not add the sentinel-alert label because this author is trusted. The finding remains recorded for audit and the dashboard Security tab; set sentinel.trusted_authors_block: true to require the blocking label for trusted authors too.

…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>
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author
be9eac8

ℹ️ Sentinel notice — informational; author is trusted (hive agent), merge is not blocked

Hive flagged this PR (author @hivecommons-hive[bot], head be9eac8de8dc) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 1 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • SECURITY.md
  • security_policy_edit — edits security policy, scanner config, rulesets or hooks (Edits SECURITY.md, dependabot/CodeQL config, rulesets or git hooks)
    • SECURITY.md

Hive did not add the sentinel-alert label because this author is trusted. The finding remains recorded for audit and the dashboard Security tab; set sentinel.trusted_authors_block: true to require the blocking label for trusted authors too.

@mrbobbytables
mrbobbytables added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit 74fd8ad Oct 11, 2026
7 checks passed
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] audit-gate allowlist never expires: a fixed advisory stays suppressed with nothing to detect it

1 participant