GitHub flagged two high-severity Dependabot alerts on this project. Both npm audit and the standard reflex — "there's a fix available, take it" — pointed the same direction. Neither of those, on their own, told me whether taking the suggested fix would actually fix anything.
What the audit said
6 high severity vulnerabilities
extract-zip <=2.0.1
Severity: high
extract-zip allows arbitrary file writes through symlink archive entries
fix available via `npm audit fix --force`
Will install @lhci/cli@0.12.0, which is a breaking change
Six flagged packages, but they all trace back to one root: extract-zip, a transitive dependency pulled in by puppeteer-core, which is pulled in by lighthouse, which is pulled in by @lhci/cli — the Lighthouse CI tool this project uses as a dev dependency to run performance audits. extract-zip has two separate CVEs, both about symlink handling during archive extraction: a malicious zip file can write files outside the intended extraction directory.
npm's suggested fix was @lhci/cli@0.12.0 — a downgrade from the 0.15.1 already installed, flagged as a semver-major change.
The part that matters: checking what 0.12.0 actually fixes
The instinct here is to just run the suggested fix and move on. Before doing that, I checked two things directly instead of trusting the tool's suggestion at face value:
npm view @lhci/cli versions --json
# ... 0.13.0, 0.14.0, 0.15.0, 0.15.1 ← current, and still in the vulnerable range
npm view extract-zip versions --json
# ... 1.7.0, 2.0.0, 2.0.1 ← the latest release, and it's still <=2.0.1
extract-zip's own most recent published version is 2.0.1 — which is inside its own vulnerable range. There is no newer, patched release. The advisory has been open against this package with no fix ever shipped upstream. npm's suggested downgrade to @lhci/cli@0.12.0 doesn't route around a vulnerable extract-zip — it just happens to pull in an older puppeteer-core that, at the time that advisory range was written, didn't yet depend on the vulnerable path. It's not a fix. It's a coincidental gap in the dependency graph from an older snapshot in time, and it comes with the real cost of losing three minor versions of Lighthouse CI's own features and fixes.
What I actually did instead of running the "fix"
Nothing, to the dependency tree — and that's a deliberate decision, not a skipped step. A few things narrowed the actual risk down before I was comfortable leaving it:
@lhci/cliis adevDependency. It never ships in the production bundle or runs in front of a real user; it only executes locally and in CI, against URLs this project controls.- The vulnerability class — arbitrary file writes via a malicious zip's symlink entries — requires
extract-zipto actually extract an attacker-supplied archive. Lighthouse CI doesn't extract untrusted archives as part of its normal operation; the exposure would require a specifically crafted malicious input reaching that code path, which isn't part of this project's CI flow. - Downgrading three minor versions to "fix" an issue that isn't actually fixed in the target version is a worse trade than leaving a documented, scoped, dev-only exposure in place.
The lesson, generalized
"A fix is available" and "the fix fixes the thing" are different claims, and tooling reports the first one, not the second. npm audit fix is doing exactly what it's supposed to — flagging that a version outside the known-vulnerable range exists — but it can't know that the underlying package's maintainers never actually patched the CVE, and a lower version number sometimes tells you more about when a dependency graph happened to snapshot a smaller subtree than about which version is actually safe. For a high-severity alert on a dev-only tool, the right first move isn't "run the suggested fix" or "ignore the alert" — it's five minutes with npm view <package> versions to check whether the suggested fix is actually downstream of a real patch, or just an older commit that hasn't caught up to the vulnerability yet.
