Severity: high (platform binaries) / medium (other targets) · Action: replace (multi-op: remove binary override + add parent override)
| Condition | Severity |
|---|---|
Target matches a platform-binary pattern (@esbuild/<platform>, @next/swc-<platform>, @img/sharp-<platform>, lightningcss-<platform>, etc.) |
high (binary-coupling failure mode is severe) |
Non-platform target (e.g. postcss, react), override not confirmed effective on disk |
medium (the override may not be taking) |
| Non-platform target AND OA008 also fires for the same target | high (escalated in the composite pass: confirmed failure on disk) |
Platform-binary detection is heuristic: any package whose name contains an OS segment (linux, darwin, win32, freebsd, android, etc.) as a hyphen- or slash-separated token. See src/overrides/detectors/platform-binary.ts.
An override whose target package has at least one installed parent that declares it as an exact-version dependency (not a range). The override is fighting the parent's pin. Depending on the package and the npm/pnpm version, the override may:
- Be honoured but emit
EOVERRIDEwarnings. - Be silently ignored, leaving the parent's pinned version on disk.
- Cause both versions to install side-by-side (defeating dedup, leaving the vulnerable copy on disk).
This was a headline finding from dogfooding against hexmetrics. It surfaced a class of override-hygiene bugs that no other tool catches.
OA006 consults the materialized node_modules tree before firing, the same way OA008 does. A flat overrides / pnpm.overrides / resolutions entry does collapse a transitively exact-pinned dependency in npm and pnpm - that is its entire purpose. So if the override target is installed at a version that satisfies the override, the override demonstrably won and OA006 stays silent: it is effective, not fragile, and proposing the parent-level rewrite would be harmful (it would force-pin the parent to clear a non-problem).
OA006 therefore fires only when the override is not confirmed effective on disk:
- a materialized copy violates the override (the parent's exact pin won resolution), or
- there is no materialized copy to prove the override took (e.g. a wrong-platform optional binary that was never installed).
The classic false positive this rule must avoid is the documented "every Next.js project needs a flat postcss override" pattern: next exact-pins postcss, but the flat override wins and node_modules/postcss ends up at the override's version. That override is working; OA006 must not cry wolf on it. (Calibrated per issue #37 after a HexOps fleet dogfooding sweep flagged it on 32 of 33 Next projects.)
Installed tree:
node_modules/esbuild@0.28.0
optionalDependencies: { "@esbuild/linux-x64": "0.28.0" } <- EXACT pin
node_modules/@esbuild/linux-x64@0.25.12 <- frozen by lockfile
Output:
HIGH (1)
--------
OA006 @esbuild/linux-x64
package.json/overrides/@esbuild~1linux-x64
Override on platform binary fights an exact-pinned parent
fix: applyable patch (2 ops)
The finding details explain the parent-level rewrite:
// instead of:
"overrides": { "@esbuild/linux-x64": "latest" }
// do this:
"overrides": { "esbuild": ">=0.28.0" }
// then: rm -rf node_modules package-lock.json && npm installPlatform binaries (@esbuild/<platform>, @next/swc-<platform>, @rollup/rollup-<platform>, @swc/core-<platform>, sharp prebuilts, lightningcss-darwin/linux/win32, etc.) are typically declared by their parent JS package as exact-version optionalDependencies. The version of the native binary must match the JS package's expectations byte-for-byte; a mismatch can crash at startup.
When you override just the binary without the parent:
- The override looks load-bearing: "we pinned the binary to the safe version".
- The actual install behaviour depends on npm/pnpm version, registry state, and the parent's manifest. Sometimes the override wins, sometimes the parent does.
- Even when the override wins today, a future
npm updateto the parent will silently re-introduce the parent's exact pin and undo your security work.
Static analysis of package.json alone misses this entirely: pnpm audit and most override readers look at version strings, not at the parent's declared constraints. OA006 cross-references the override target with the installed tree's parent manifests and surfaces the coupling.
| Override target | Likely parent | Why it's coupled |
|---|---|---|
@esbuild/<platform> |
esbuild |
Native bundler binary; version-locked to JS parent |
@next/swc-<platform> |
next |
Next.js compiler binary |
@rollup/rollup-<platform> |
rollup |
Native rollup binary |
@swc/core-<platform> |
@swc/core |
SWC compiler binary |
lightningcss-<platform> |
lightningcss |
CSS engine binary |
sharp prebuilts |
sharp |
Image processing binary |
cve-lite overrides --fix --rule OA006--fix applies the structural rewrite automatically as a multi-op patch: it removes the binary override entry and adds (or replaces) a parent override entry at >=<parent-installed-version>.
General pattern:
// remove the binary override:
"overrides": {
// "@parent/<platform>": "..." <- delete this
"parent": ">=<safe-version>" // <- add this
}Then flush the lockfile to pick up the new resolution:
rm -rf node_modules package-lock.json
npm install
cve-lite overrides # confirm OA006 + any OA008 are clearedWhy a floor (>=X.Y.Z) and not exact? Floors let the resolver pick newer-but-compatible versions on future installs, which is what you want for a security pin.
When multiple installed parents declare the override target exact, the detector picks the newest one (sorted descending by semver) as the suggested override target. That's the safer recommendation; newer parents likely have the safer binary too. The choice is deterministic across runs.
- OA006 flags the risky pattern: your override is fighting an exact-pinned parent.
- OA008 flags the materialized failure: a vulnerable version is currently on disk despite the override. The two together tell you whether the risk has actually bitten you yet. When both fire on the same target, the composite pass escalates a medium OA006 to high.
Rarely. The one legitimate case: you've forked the platform binary (your CI builds a patched binary you publish under your scope), and you genuinely want the override to substitute just the native artifact. Even then, prefer pinning the parent to a known-compatible version and using a custom registry mirror.
src/overrides/detectors/oa006-coupled-platform-binary.tssrc/overrides/detectors/platform-binary.ts- npm-package-json overrides (no caution about exact-pinned parents)