Skip to content

Latest commit

 

History

History
98 lines (64 loc) · 4.14 KB

File metadata and controls

98 lines (64 loc) · 4.14 KB

OA008: Materialized vulnerable copy

Severity: critical  ·  Action: suggest (no auto-fix; investigate which parent is winning resolution)

What it catches

An override declared a floor (range or concrete pin), but a copy of the target package below that floor is still on disk. Your security pin is not effective everywhere. You are vulnerable and the override hasn't told you.

Example

{
  "overrides": {
    "@esbuild/linux-x64": ">=0.28.0"   // safe floor
  }
}

Installed tree (real-world example from hexmetrics):

node_modules/@esbuild/linux-x64@0.25.12                          <- VULNERABLE - below floor
node_modules/tsx/node_modules/@esbuild/linux-x64@0.28.0          <- OK

Output:

CRITICAL (1)
------------
  OA008  @esbuild/linux-x64
    package.json/overrides/@esbuild~1linux-x64
    Override floor not applied - vulnerable copy still on disk

(No fix: line: OA008 is suggest-only and carries no auto-fix patch.)

Why it matters

This is the post-install verification rule. Even when:

  • You wrote a correct override floor.
  • The override was syntactically valid in the right section (OA003 passes).
  • npm install ran without error.

...the resolver may have left a vulnerable copy on disk. The most common cause is the one OA006 flags: a parent package declares the target as an exact-version dependency and wins resolution against the override.

OA008 is critical severity because it represents a materialized security gap. Your CI passed, your override looks right in source, and you are still vulnerable on disk.

What it walks

OA008 walks every package.json under node_modules/, recursing through node_modules/<pkg>/node_modules/<inner>/... for every nesting level. It records every copy of every override target's package name, then compares versions against the override's floor.

For range floors like ">=0.28.0" or "^8.5.0", it uses semver.satisfies. For concrete-version pins like "8.5.15", it treats the pin itself as the floor (anything below is vulnerable).

What it does NOT flag

  • Floating-tag pins ("latest", "next"). The notion of "below the floor" is undefined for floating tags. (OA002 and OA007 handle those.)
  • Protocol-prefixed values (workspace:, file:, link:). Out of scope.
  • Override targets with no copies installed (nothing to compare against).
  • Nested-object override values. (OA005 territory.)

How to fix

OA008 carries no auto-fix patch. The finding's suggest action explains the investigation path:

# 1. Find which parent is pulling in the vulnerable copy:
npm ls @esbuild/linux-x64

# 2. Override that parent instead (see OA006):
#    "overrides": { "esbuild": ">=0.28.0" }

# 3. Flush the lockfile and reinstall:
rm -rf node_modules package-lock.json && npm install

# 4. Re-run the audit to confirm:
cve-lite overrides

If OA008 keeps firing after the parent-level override, the parent itself may have a transitive parent that's pinning the binary even more deeply. Walk the tree (npm ls) until you find the root of the chain and override at that level.

Why this is critical and not "just" high

Severity is critical because:

  1. The user actively believed they were protected. They wrote an override floor. They installed dependencies. The vulnerability is undetected by static analysis of package.json.
  2. No other tool catches this. pnpm audit reads version strings; npm audit reports CVEs against installed packages but doesn't cross-check against your override floor.
  3. The fix isn't always trivial. Sometimes the parent override (OA006-style) doesn't work either; you may need to upgrade or replace the parent entirely.

Complementary rules

  • OA006 flags the risky pattern that often leads to OA008. If both fire on the same target, you have a confirmed coupling-induced security gap (and the composite pass escalates a medium OA006 to high).
  • OA002 flags floating-tag pins which can't be checked by OA008.

References