My Vulnerability Scanner Remembered Yesterday's Clean Result

A dependency remediation session restored a lockfile that contained vulnerable packages and ran the repository's normal security check.

trunk check --filter=osv-scanner

It reported no issues.

Dependabot still showed open alerts. A direct OSV scan found three vulnerable packages in the lockfile.

The dependencies had traveled backward in time. The scanner result had not.

The green result contradicted the input

This happened during dependency remediation in a React Native package. Earlier commits had changed resolutions and produced a clean scan. A later adoption step restored a lockfile state that still contained known vulnerable versions.

Trunk returned the clean result from the earlier state.

The exact invalidation failure was in the orchestration layer observed during that session, not in OSV's vulnerability database. Running the underlying scanner against yarn.lock bypassed that layer and exposed the findings.

That distinction prevented the wrong diagnosis. Updating the advisory database would not fix a wrapper that had reused a result for different input bytes.

A security gate needs an input identity

“OSV passed” is incomplete evidence. A useful result needs to answer three questions:

  1. Which scanner and version ran?
  2. Which lockfile bytes did it read?
  3. Which configuration and ignore rules did it apply?

Without those fields, a cached result can be attached to the wrong dependency graph and still look authoritative.

At minimum, record the lockfile hash beside the result:

shasum -a 256 yarn.lock
osv-scanner scan -L yarn.lock --format json

The second command follows the current OSV-Scanner V2 usage. The incident used the scanner available through Trunk at that time, so its direct command shape differed. The principle is the same: run the scanner on the target lockfile without the suspect cache layer.

Make the cross-check disagree on purpose

A second green tool does not automatically increase confidence. It may share the same stale artifact, ignore file, or dependency extraction path.

This is the security-specific sequel to my broader “A Green Gate Only Proves What Its Reader Can See” draft. Here, the important boundary is the exact lockfile content presented to the scanner (the badge does not include that part).

The useful cross-check changes an evidence boundary:

  • Run the underlying scanner directly instead of through the wrapper.
  • Hash the lockfile that the scanner receives.
  • Inspect active ignore configuration near that lockfile.
  • Compare open Dependabot alerts as independent evidence, not as an infallible authority.

The scan also exposed an incomplete fix

The direct evidence did more than reveal stale caching. It showed that the adopted resolution block had omitted two dependency fixes.

One package, @babel/plugin-transform-modules-systemjs 7.29.0, was associated with a high-severity advisory in the recorded scan. fast-xml-builder 1.1.5 was associated with two advisories. The remediation moved them to the versions recorded as fixed in that session.

The same review also caught an over-broad undici resolution. It forced a dependency that wanted major version 7 down to 6. The final override targeted only the installed 6.x range that needed remediation, allowing the 7.x consumer to keep its own major version.

That is another reason to inspect the resolved graph rather than celebrate an empty report. A security override can remove one advisory while introducing an incompatible version selection elsewhere.

Cache busting is a diagnosis, not the contract

Touching a lockfile forced a fresh Trunk evaluation in the recorded incident. That was useful confirmation of the cache hypothesis.

It is not the verification strategy I would keep.

The durable gate is content-addressed evidence: hash the lockfile, run a scanner whose invocation names the target, and retain the finding output. A wrapper may still provide the normal developer experience, but a surprising result should be checked at the underlying boundary.

This does not mean every green scan is suspicious. It means a green scan that contradicts the known dependency graph deserves investigation before celebration.

If your security tool says “clean” immediately after you restore vulnerable dependencies, do not thank it for being fast. Ask which file it actually scanned.