## TL;DR
npm audit asks the configured registry for vulnerability metadata, and your laptop and CI are asking different registries, or the same registry at different times. A mirror with stale advisory metadata reports fewer (or older) vulnerabilities. Compare npm config get registry on both sides, clear the cache, pin both to the same registry, and rerun. The count that matters is the one from the registry you actually publish from.

## The query

```text
npm audit reports 0 vulnerabilities locally but CI reports 42 - registry mirror drift between runs
```

## Use this when

- npm audit counts differ between local and CI on the same commit
- CI uses a registry mirror, proxy, or Artifactory-style virtual repo
- The lockfile is identical in both places (rule out lockfile drift first)

## Not for

- Different counts from different lockfiles (commit the lockfile)
- npm audit failing outright in CI (a network or auth problem)
- Disagreeing with the audit results themselves (triage, not plumbing)

## Steps

### 1. Rule out lockfile drift

```bash
git status --porcelain | grep -E "package-lock|yarn.lock" ; git stash list | head -3
```

Expected output: no uncommitted lockfile changes locally. If the lockfiles differ, that is your answer, not the registry.

### 2. Compare registry configuration

```bash
npm config get registry
```

Run it locally and in CI (add it as a debug step). Expected output: the two URLs. If they differ, you have found the drift.

### 3. Check the mirror's freshness

If CI points at a mirror, check when the mirror last synced its metadata. A mirror that syncs packages but lags on advisory metadata produces exactly this symptom: installs work, audits lie.

Expected output: a sync timestamp. Hours or days old explains the gap.

### 4. Clear caches and rerun both sides

```bash
npm cache clean --force && npm audit
```

Expected output: fresh metadata on both sides. If the counts now agree, stale cache or stale mirror data was the cause.

### 5. Pin both environments to one registry

Set the registry explicitly in .npmrc or the CI config so local and CI cannot diverge again. Verify: a subsequent commit produces identical audit counts in both places.

## Variant phrasings

### npm audit different results local vs ci
The short symptom search.

### npm audit 0 locally 42 in ci registry mirror
The cause-first search.

Compatibility: npm 7 and later (npm audit against the configured registry). Applies to any mirror or proxy setup.

## Why it happens
npm audit is not computed locally; it sends your dependency tree to the registry's audit endpoint and reports what comes back. Two different registries, or one registry at two different sync points, answer from two different advisory snapshots. The local run is not "wrong" and CI is not "wrong"; they asked different oracles.

## Edge cases / pitfalls

- Some mirrors proxy the audit endpoint to the public registry live. Those do not drift; the drift comes from mirrors that snapshot metadata.
- npmrc files layer (project, user, global, env). Check all of them; CI often injects a registry via environment variable that overrides the project file.
- A count of zero locally is the suspicious one. Treat "0 vulnerabilities" as guilty until proven innocent: verify the registry is reachable and the audit endpoint responded.
- Lock the CI audit to the same registry you deploy from. Auditing against a mirror you do not ship from is auditing a hypothetical.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_0GPuZOdMhZtHUPp4EfxWDg
