Skip to content

Fix Security baseline gate: override brace-expansion in eslint's dependency tree - #473

Open
richard-devbot wants to merge 2 commits into
mainfrom
fix-eslint-security-advisory
Open

Fix Security baseline gate: override brace-expansion in eslint's dependency tree#473
richard-devbot wants to merge 2 commits into
mainfrom
fix-eslint-security-advisory

Conversation

@richard-devbot

@richard-devbot richard-devbot commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fixes Security baseline gate failing: eslint's transitive brace-expansion advisory #472 — CI's Security baseline job fails on main right now, independent of any PR. npm audit reports 5 high-severity advisories, all tracing to one root: a DoS/ReDoS bug in brace-expansion (GHSA-3jxr-9vmj-r5cp, GHSA-mh99-v99m-4gvg), reachable via eslint -> minimatch@3.1.5 -> brace-expansion@1.1.16.
  • npm audit's only reported fix was eslint@10 (isSemVerMajor: true) — tried it, but @eslint/js's ESLint-10 recommended config adds a new no-useless-assignment rule that flags 15 pre-existing dead-store patterns across src/. Too invasive for what's really a transitive-dependency-only issue (eslint is a devDependency, never installed by npm install rstack-agents).
  • Instead: added a root overrides entry (same mechanism this repo already uses for esbuild/protobufjs/ws) forcing brace-expansion to the patched 5.0.8 line. Confirmed this reaches eslint's own tree while — as the script's own comments document — leaving @earendil-works/pi-coding-agent's shrinkwrapped copy (5.0.6) untouched (npm honors a shrinkwrap absolutely; overrides can't reach it).
  • That shrinkwrapped copy is the only remaining high-severity finding, and it's exactly the node security-audit.mjs's BUNDLED_ROOTS/TOLERATED_BUNDLED_ADVISORIES allowlist already exists to tolerate. Added the second GHSA id to that allowlist — the gate is deliberately strict per-advisory-id (a newly-surfaced GHSA for an already-tolerated package still fails until consciously added), so this is a real, intentional decision, not a silent widening.

Test plan

  • npm run lint — unchanged (0 errors, same 4 pre-existing warnings), confirming minimatch@3.1.5 works fine against the newer brace-expansion at runtime
  • npm run typecheck — 0 errors
  • npm audit --json — only the already-tolerated bundled pi-coding-agent node remains; simulated the gate's own logic against the real audit output and confirmed 0 blocking
  • Full local test suite: same pre-existing failure count (locally, this Windows sandbox can't resolve bare npx/npm in spawn() without a shell — a known, unrelated environment limitation that also affects an unmodified main checkout identically; CI runs on Linux where this doesn't apply, same as the last two PRs)

Summary by CodeRabbit

  • Security

    • Updated security auditing to recognize an additional bundled brace-expansion advisory as tolerated.
    • Security checks now more reliably distinguish bundled vulnerabilities from issues requiring action.
  • Tests

    • Added automated coverage for advisory severity, dependency paths, allowlists, and blocking behavior.

…#472)

npm audit reported 5 high-severity advisories, all tracing to one root:
a DoS/ReDoS bug in brace-expansion (GHSA-3jxr-9vmj-r5cp,
GHSA-mh99-v99m-4gvg), reachable via eslint -> minimatch@3.1.5 ->
brace-expansion@1.1.16. npm's only reported fix was eslint@10
(isSemVerMajor), which pulls in a new no-useless-assignment rule
in @eslint/js's recommended config, flagging 15 pre-existing
dead-store patterns across src/ -- too invasive for a security-only
fix.

Instead: add a root `overrides` entry (this repo already uses the
same mechanism for esbuild/protobufjs/ws) forcing brace-expansion to
the patched 5.0.8 line. Verified this reaches eslint's own tree
(minimatch@3.1.5's brace-expansion now 5.0.8) while, as documented,
leaving @earendil-works/pi-coding-agent's shrinkwrapped copy (5.0.6)
untouched -- npm honors a shrinkwrap absolutely, so overrides can't
reach it regardless.

That shrinkwrapped copy is the only remaining high-severity finding,
and it's exactly the node this gate's BUNDLED_ROOTS/
TOLERATED_BUNDLED_ADVISORIES allowlist already exists to tolerate --
added the second GHSA id to that allowlist (the gate is deliberately
strict per-advisory-id, so a newly surfaced GHSA for an
already-tolerated package still fails until consciously added).

Verified: npm run lint unchanged (0 errors, same 4 pre-existing
warnings -- confirms minimatch@3.1.5 works fine with the newer
brace-expansion at runtime), npm run typecheck clean, gate logic
simulated against real npm audit output now reports 0 blocking.
@strix-security

strix-security Bot commented Jul 26, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for 780ed06.


Reviewed by Strix
Re-run review · Configure security review settings

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds a brace-expansion dependency override, refactors security-audit decision logic into exported functions, expands the tolerated advisory allowlist, guards script execution, and adds comprehensive tests.

Changes

Security audit baseline

Layer / File(s) Summary
Dependency and advisory configuration
package.json, scripts/security-audit.mjs
Adds the brace-expansion override and expands the exported bundled-advisory allowlist.
Reusable audit evaluation flow
scripts/security-audit.mjs
Exports bundled-path and advisory evaluation helpers, and moves audit execution into guarded main() logic.
Audit decision coverage
tests/security-audit.test.js
Tests bundled-path detection, advisory tolerance and blocking, severity filtering, advisory ID extraction, and the brace-expansion allowlist.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: richardsongunde

Poem

A rabbit checked the audit trail,
And found a brace within the warren.
“Bundled paths may pass,” it said,
“But wandering ones face the carrot.”
Tests now guard each burrow tight. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: pinning brace-expansion in ESLint's dependency tree to fix the security baseline gate.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-eslint-security-advisory

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix CI security baseline by overriding brace-expansion in ESLint tree

🐞 Bug fix ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Force patched brace-expansion version via npm overrides to unblock Security baseline gate.
• Update lockfile so ESLint’s minimatch chain resolves brace-expansion@5.0.8.
• Extend audit allowlist for shrinkwrapped bundled dependency to include newly surfaced GHSA.
Diagram

graph TD
  CI(["CI: Security baseline"]) --> AUD(["npm audit"]) --> GATE["scripts/security-audit.mjs"] --> OVR["package.json overrides"] --> LOCK["package-lock.json"]
  LOCK --> ESL["eslint → minimatch → brace-expansion@5.0.8"] --> OK["Gate passes"]
  LOCK --> BND["pi-coding-agent bundled brace-expansion@5.0.6"] --> ALW["Tolerated GHSA ids"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Upgrade ESLint major (eslint@10) and fix new lint violations
  • ➕ Eliminates the vulnerable transitive dependency without overrides
  • ➕ Aligns with upstream latest rules and ecosystem
  • ➖ Introduces new recommended rules causing non-trivial code churn (existing dead stores)
  • ➖ Higher risk/scope for what is effectively a devDependency-only audit issue
2. Update/replace the shrinkwrapped bundled dependency (pi-coding-agent)
  • ➕ Removes the last remaining high-severity advisory without allowlisting
  • ➕ Avoids relying on per-GHSA toleration over time
  • ➖ May require upstream release coordination or vendor changes
  • ➖ Potentially larger dependency and integration impact than a targeted override
3. Switch package manager/resolution mechanism (e.g., pnpm overrides/yarn resolutions)
  • ➕ Can offer more control/visibility over transitive dependency policies
  • ➕ May simplify future security remediation workflows
  • ➖ Tooling migration cost; impacts dev workflow and CI
  • ➖ Not necessary to address the immediate gate failure

Recommendation: The chosen approach (root-level npm overrides + explicit per-GHSA allowlisting for the unavoidable shrinkwrapped node) is the best short-term fix: it remediates the vulnerable ESLint dependency chain without a disruptive major ESLint upgrade, and keeps the security gate intentionally strict by requiring an explicit decision for each GHSA id. A follow-up should target the remaining shrinkwrapped brace-expansion by updating the bundled dependency upstream to eliminate the need for toleration.

Files changed (3) +24 / -27

Bug fix (1) +7 / -3
security-audit.mjsAllowlist additional brace-expansion GHSA for bundled shrinkwrap node +7/-3

Allowlist additional brace-expansion GHSA for bundled shrinkwrap node

• Extends the per-advisory-id allowlist for the bundled/shrinkwrapped brace-expansion instance to include GHSA-mh99-v99m-4gvg alongside the already tolerated GHSA-3jxr-9vmj-r5cp. Updates comments to document why the remaining finding is confined to the bundled root and why overrides cannot affect it.

scripts/security-audit.mjs

Other (2) +17 / -24
package-lock.jsonResolve brace-expansion to 5.0.8 and refresh dependent nodes +15/-23

Resolve brace-expansion to 5.0.8 and refresh dependent nodes

• Updates the lockfile so the eslint→minimatch chain no longer pulls brace-expansion@1.1.16, instead resolving brace-expansion@5.0.8. This also updates brace-expansion’s direct dependency (balanced-match) and removes concat-map from the resolved tree, reflecting the newer major line.

package-lock.json

package.jsonAdd npm override to pin brace-expansion to patched range +2/-1

Add npm override to pin brace-expansion to patched range

• Adds a top-level npm overrides rule forcing brace-expansion to >=5.0.8, consistent with existing overrides usage in the repo. This targets the transitive dependency causing the Security baseline gate failure without upgrading ESLint major.

package.json

@qodo-code-review

qodo-code-review Bot commented Jul 26, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 300 rules
✅ Skills: 17 invoked
  code-review-pr
  claude-api
  documentation-writing
  pptx
  docx
  performance-monitoring
  security-compliance
  cso
  plan-eng-review
  design-review
  prompt-engineering
  mcp-builder
  qa-testing
  code-patterns
  xlsx
  security-owasp
  testing-qa

Grey Divider


Remediation recommended

1. Node version mismatch 🐞 Bug ☼ Reliability
Description
The override pulls in brace-expansion@5.0.8 which declares Node "20 || >=22", but this repo declares
Node ">=18" and CI still runs a Node 18.x lane. This can cause install-time engine failures (in
stricter environments) or make the Node 18 lane brittle when the overridden dependency is exercised
(e.g., lint tooling).
Code

package-lock.json[R3569-3580]

    "node_modules/brace-expansion": {
-      "version": "1.1.16",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
-      "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
+      "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
+        "balanced-match": "^4.0.2"
+      },
+      "engines": {
+        "node": "20 || >=22"
      }
Relevance

●●● Strong

They’ve accepted Node version consistency fixes; engine mismatch could break Node 18 CI/install.

PR-#171

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The repo declares/support-tests Node 18, but the updated lockfile shows the overridden
brace-expansion now requires Node 20+.

package.json[41-43]
.github/workflows/ci.yml[13-17]
package-lock.json[3569-3580]
package.json[114-119]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`brace-expansion@5.0.8` is now forced into the root dependency tree, but it declares `engines.node = "20 || >=22"`, conflicting with this repo’s declared `engines.node >=18` and the CI matrix that still runs Node 18.

## Issue Context
Even if npm only warns by default, this becomes a hard failure in environments that enforce engines (or if the dependency starts using Node 20-only APIs).

## Fix Focus Areas
- package.json[41-43]
- package.json[114-119]
- .github/workflows/ci.yml[13-17]
- package-lock.json[3569-3580]

## What to change
Choose one:
1) If Node 18 is truly supported: use a patched `brace-expansion` version that supports Node 18, or scope the override so Node 18 paths don’t require Node 20-only packages.
2) If Node 18 is *not* supported in practice: update `package.json` engines and remove Node 18 from the CI matrix so the declared support matches reality.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unbounded override range ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The override uses ">=5.0.8", which allows future lockfile regenerations to select newer (including
potentially breaking) major versions of brace-expansion. It also forces minimatch@3.1.5 to run
against brace-expansion 5.x even though minimatch declares a 1.x range, creating an ongoing
transitive-compatibility risk.
Code

package.json[R114-118]

  "overrides": {
    "esbuild": ">=0.28.1",
    "protobufjs": ">=7.6.4 <8",
-    "ws": ">=8.21.0"
+    "ws": ">=8.21.0",
+    "brace-expansion": ">=5.0.8"
Relevance

●● Moderate

No precedent on pinning overrides; repo already uses unbounded ">=" overrides, so change is
subjective.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new override is unbounded and the lockfile shows minimatch depends on brace-expansion ^1.1.7,
demonstrating the override is crossing a major range boundary.

package.json[114-119]
package-lock.json[4994-5005]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The override `"brace-expansion": ">=5.0.8"` is open-ended and can float to future major releases when the lockfile is regenerated. It also overrides `minimatch@3.1.5`’s declared dependency range (`^1.1.7`), so the repo is relying on compatibility that npm is no longer enforcing.

## Issue Context
Right now the lockfile pins `brace-expansion` to `5.0.8`, but the manifest range increases the chance of unexpected breakage on routine dependency maintenance.

## Fix Focus Areas
- package.json[114-119]
- package-lock.json[4994-5005]

## What to change
- Prefer pinning to an exact version (`"5.0.8"`) or a bounded range (`"^5.0.8"`).
- Consider scoping the override to only the eslint/minimatch subtree (npm overrides support nested overrides) so you don’t globally replace every consumer’s `brace-expansion` with a potentially incompatible major.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. security-audit.mjs change lacks tests ✓ Resolved 📘 Rule violation ▣ Testability
Description
This PR changes the Security baseline gate behavior by expanding TOLERATED_BUNDLED_ADVISORIES to
accept an additional GHSA ID, but no automated tests were added/updated in the same changeset to
cover this new allowlist behavior. Without tests, future refactors may unintentionally
broaden/narrow the gate logic and break CI or weaken security controls silently.
Code

scripts/security-audit.mjs[R31-42]

+// - brace-expansion GHSA-3jxr-9vmj-r5cp + GHSA-mh99-v99m-4gvg (both DoS):
+//   pinned 5.0.6 by pi's shrinkwrap, both advisories confined to that one
+//   bundled node (verified: eslint's own brace-expansion moved to the
+//   patched 5.0.8 after #472's eslint 9->10 bump, so only the shrinkwrapped
+//   copy remains on the vulnerable <=5.0.7 line); every non-shrinkwrapped
+//   path in our tree is on the fixed line.
// - protobufjs / ws: previously tolerated by name while their advisories were
//   live in the bundled subtree; currently dormant, so no ids are listed — if
//   one refires, the gate fails loudly and the specific GHSA gets re-added.
const TOLERATED_BUNDLED_ADVISORIES = new Map([
-  ['brace-expansion', new Set(['GHSA-3jxr-9vmj-r5cp'])],
+  ['brace-expansion', new Set(['GHSA-3jxr-9vmj-r5cp', 'GHSA-mh99-v99m-4gvg'])],
]);
Relevance

●● Moderate

They recently changed security-audit allowlist logic, but no evidence they require tests for
allowlist updates.

PR-#439

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1587034 requires that non-trivial behavior changes include accompanying automated
tests in the same changeset. The diff shows the gate behavior was changed by adding
GHSA-mh99-v99m-4gvg to the tolerated advisory IDs in scripts/security-audit.mjs, but no test
changes are present in the PR diff.

Rule 1587034: Require tests in the same changeset as behavior modifications
scripts/security-audit.mjs[31-42]
.github/workflows/ci.yml[97-101]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR updates `scripts/security-audit.mjs` to tolerate an additional `brace-expansion` advisory ID, which changes CI gate behavior, but there is no corresponding test change in this PR to lock in the intended behavior.

## Issue Context
The `security-baseline` CI job runs `node scripts/security-audit.mjs`, so changes to this script are executable behavior changes and should be covered by automated tests.

## Fix Focus Areas
- scripts/security-audit.mjs[31-42]
- tests/security-audit.test.js[1-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Incorrect audit script comment ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The updated comment claims eslint’s brace-expansion moved to 5.0.8 due to an “eslint 9->10 bump”,
but this PR keeps eslint at ^9 and makes the change via npm overrides. This mismatch can mislead
future debugging of the security baseline gate.
Code

scripts/security-audit.mjs[R31-36]

+// - brace-expansion GHSA-3jxr-9vmj-r5cp + GHSA-mh99-v99m-4gvg (both DoS):
+//   pinned 5.0.6 by pi's shrinkwrap, both advisories confined to that one
+//   bundled node (verified: eslint's own brace-expansion moved to the
+//   patched 5.0.8 after #472's eslint 9->10 bump, so only the shrinkwrapped
+//   copy remains on the vulnerable <=5.0.7 line); every non-shrinkwrapped
+//   path in our tree is on the fixed line.
Relevance

●●● Strong

Misleading comment is a straightforward maintainability fix; likely to be accepted when pointed out.

PR-#439

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The comment explicitly references an ESLint bump, but package.json shows ESLint is still ^9.0.0 and
the PR change is an override entry.

scripts/security-audit.mjs[31-36]
package.json[101-106]
package.json[114-119]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The comment in `scripts/security-audit.mjs` attributes the brace-expansion change to an ESLint 9→10 bump, but the repo is still on ESLint `^9.0.0` and the actual mechanism is a root `overrides` entry.

## Issue Context
This is documentation-only, but it directly affects maintainers’ ability to reason about why the vulnerability is (or isn’t) present.

## Fix Focus Areas
- scripts/security-audit.mjs[31-36]
- package.json[101-106]
- package.json[114-119]

## What to change
Rewrite the comment to say the non-shrinkwrapped tree is fixed due to the root `overrides` forcing `brace-expansion@5.0.8`, while the shrinkwrapped `@earendil-works/pi-coding-agent` copy remains pinned and tolerated by advisory id.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread scripts/security-audit.mjs
Comment thread package-lock.json
Comment on lines 3569 to 3580
"node_modules/brace-expansion": {
"version": "1.1.16",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
"balanced-match": "^4.0.2"
},
"engines": {
"node": "20 || >=22"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Node version mismatch 🐞 Bug ☼ Reliability

The override pulls in brace-expansion@5.0.8 which declares Node "20 || >=22", but this repo declares
Node ">=18" and CI still runs a Node 18.x lane. This can cause install-time engine failures (in
stricter environments) or make the Node 18 lane brittle when the overridden dependency is exercised
(e.g., lint tooling).
Agent Prompt
## Issue description
`brace-expansion@5.0.8` is now forced into the root dependency tree, but it declares `engines.node = "20 || >=22"`, conflicting with this repo’s declared `engines.node >=18` and the CI matrix that still runs Node 18.

## Issue Context
Even if npm only warns by default, this becomes a hard failure in environments that enforce engines (or if the dependency starts using Node 20-only APIs).

## Fix Focus Areas
- package.json[41-43]
- package.json[114-119]
- .github/workflows/ci.yml[13-17]
- package-lock.json[3569-3580]

## What to change
Choose one:
1) If Node 18 is truly supported: use a patched `brace-expansion` version that supports Node 18, or scope the override so Node 18 paths don’t require Node 20-only packages.
2) If Node 18 is *not* supported in practice: update `package.json` engines and remove Node 18 from the CI matrix so the declared support matches reality.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread package.json Outdated
Comment thread scripts/security-audit.mjs Outdated
Qodo flagged four issues on the eslint/brace-expansion security fix:
- no test coverage for the TOLERATED_BUNDLED_ADVISORIES allowlist change
- brace-expansion@5.0.8 declares engines.node "20 || >=22", excluding the
  Node 18 CI lane
- the ">=5.0.8" override is unbounded and can float to a future major
- the script comment mis-attributed the version bump to an eslint 9->10
  bump that never happened (the real mechanism is the root override)

Fix: bound the override to an exact "5.0.8" pin; export the pure
tolerate/block decision logic from security-audit.mjs (evaluateAdvisories,
isFullyBundled, advisoryIds) behind a main-guard so it's unit-testable
without shelling out to npm audit, and add tests/security-audit.test.js
covering the tolerate/block/allowlist-miss/severity-threshold paths, plus
a pinned-allowlist regression test; correct the stale comment to document
the real mechanism and the accepted Node 18 engines trade-off (no
brace-expansion release fixes both GHSAs while keeping Node 18 support;
it's a devDependency-only path and no engine-strict is set, so this
doesn't fail CI in practice).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/security-audit.mjs`:
- Around line 48-52: Update advisoryIds to fail closed for malformed advisory
objects: retain valid URL-derived IDs, but produce a non-tolerated result for
any object entry lacking a usable url instead of filtering it out. Ensure
callers of advisoryIds, including the additional referenced path, block the
report when such an unidentified entry is present.

In `@tests/security-audit.test.js`:
- Around line 59-72: Extend the security tests near the existing bundled
advisory case with a mixed-GHSA scenario for brace-expansion: include both the
allowlisted GHSA-3jxr-9vmj-r5cp and a new, non-allowlisted ID, then call
evaluateAdvisories with the same bundled configuration and assert the advisory
is blocking rather than tolerated. Keep the existing single-new-ID regression
intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8921db52-b91e-4e5f-adcd-b0207efd2798

📥 Commits

Reviewing files that changed from the base of the PR and between cce8808 and 41ba8f5.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • package.json
  • scripts/security-audit.mjs
  • tests/security-audit.test.js

Comment on lines +48 to 52
export function advisoryIds(info) {
return (info.via ?? [])
.filter((entry) => typeof entry === 'object' && entry?.url)
.map((entry) => String(entry.url).split('/').pop());
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when an advisory entry cannot be identified.

advisoryIds drops object entries without url. A bundled report containing one allowlisted GHSA plus an unparseable advisory object is therefore tolerated. Treat malformed object entries as non-tolerated and block the advisory instead of filtering them out. As per coding guidelines, “validator restrictions must fail closed.”

Also applies to: 90-94

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/security-audit.mjs` around lines 48 - 52, Update advisoryIds to fail
closed for malformed advisory objects: retain valid URL-derived IDs, but produce
a non-tolerated result for any object entry lacking a usable url instead of
filtering it out. Ensure callers of advisoryIds, including the additional
referenced path, block the report when such an unidentified entry is present.

Source: Coding guidelines

Comment on lines +59 to +72
test('blocks a bundled advisory whose id is NOT on the allowlist — a new GHSA forces a conscious decision', () => {
const vulns = {
'brace-expansion': adv({
ids: ['GHSA-brand-new-id'],
nodes: [`${BUNDLED_ROOT}brace-expansion`],
}),
};
const { blocking, tolerated } = evaluateAdvisories(vulns, {
toleratedBundledAdvisories: new Map([['brace-expansion', new Set(['GHSA-3jxr-9vmj-r5cp'])]]),
bundledRoots: [BUNDLED_ROOT],
});
assert.equal(tolerated.length, 0);
assert.equal(blocking.length, 1);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add a mixed-GHSA mutation regression.

Add a bundled brace-expansion case with one allowlisted ID and one new ID, asserting it blocks. The current suite would not catch an everysome mutation in evaluateAdvisories. As per coding guidelines, tests must include “mutation-oriented tests for security.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/security-audit.test.js` around lines 59 - 72, Extend the security tests
near the existing bundled advisory case with a mixed-GHSA scenario for
brace-expansion: include both the allowlisted GHSA-3jxr-9vmj-r5cp and a new,
non-allowlisted ID, then call evaluateAdvisories with the same bundled
configuration and assert the advisory is blocking rather than tolerated. Keep
the existing single-new-ID regression intact.

Source: Coding guidelines

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security baseline gate failing: eslint's transitive brace-expansion advisory

2 participants