Supply-chain research

A package with 147 million weekly downloads shipped a preinstall hook it never had

On 4 August 2026, version 11.1.6 of file-entry-cache added a preinstall script and a 727KB obfuscated source file to a package that had neither. npm removed the version the same day. Here is exactly what our scanner saw, what we can and cannot say about it, and how to check whether it reached your builds.

Detected 4 August 2026 — the day the version was published, and the day npm removed it Nithic Research · written up 18 September 2026 · part of our retrospective backlog
147Mweekly downloads at the time of detection
727,662characters on the longest single line
1version affected — 11.1.6
1h 30mfrom our detection to npm removing it

What changed

file-entry-cache is a small, old, extremely widely depended-upon npm package — the kind that arrives in your node_modules because something else you installed wanted it. It does not normally run code at install time, and it does not normally ship obfuscated source.

Version 11.1.6 did both. Our scanner compares each new version against its predecessor rather than judging it in isolation, and the delta is the whole story here: these are capabilities the package did not previously have.

SignalEvidence
Install hook"preinstall": "node setup.mjs"
Minified source outside a build directorylongest line 727,662 characters
javascript-obfuscator string-array rotationself-defending obfuscation, the tool's characteristic rotating string table

A preinstall script runs automatically, before anything is built or audited, with the permissions of whoever ran npm install — a developer laptop or a CI runner holding deploy credentials. Obfuscation is not itself malicious; plenty of legitimate packages ship minified bundles. What makes this combination worth acting on is that all three appeared at once, in a package that had shipped neither for years.

What we are not claiming. We have not published an analysis of what the obfuscated code does, and we are not naming a responsible party. A package that has been maintained cleanly for years and suddenly gains an install hook is far more often a stolen publishing credential than a maintainer decision — the person whose name is on the release is usually the first victim, not the author. The finding here is the anomaly and its timing.

How we found it, and when

We analyse new versions from the public registries continuously and compare each against the version before it. The timeline, in UTC on 4 August 2026:

Time (UTC)Event
10:19:39We grade 11.1.6 malicious on the delta above
11:48:03Our takedown watcher confirms the version is still on npm
11:52:08Next poll: the version is gone

So npm removed it somewhere inside a four-minute window, between 1h28m and 1h33m after we flagged it. We are giving the window rather than a single removal time because we only know what our polling observed — the registry does not announce the moment it acts, and quoting 11:52:08 as “the time npm removed it” would be reporting our poll schedule as if it were their decision. At the point we recorded the finding, no public advisory covered it.

One has since been published: OSV lists MAL-2026-11970, “Malicious code in file-entry-cache (npm)”. We are noting that deliberately — our detection came first, but the independent advisory is what turns our signal-level finding into a confirmed one, and a write-up that quietly omitted it would be selling the detection harder than the evidence warrants.

We are publishing now, well after the fact, because the affected version is already gone from the registry — the remaining value is to the people who installed it in the window it was live, or who have it pinned in a lockfile.

Check whether it reached you

Search your lockfiles and installed tree for the exact version:

grep -n "file-entry-cache" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
npm ls file-entry-cache

If you see 11.1.6, that install ran setup.mjs as a preinstall step. Any long-lived credential that was present in that environment — npm tokens, cloud keys, CI secrets, SSH keys — should be treated as exposed and rotated. Reinstall on a version other than 11.1.6; npm has removed it, so a fresh resolve will not select it.

If you do not see 11.1.6, no action is needed. The package itself remains fine; a single version was affected.

Why the delta matters more than the signal

Every individual signal here is common in benign software. Minified files are everywhere. Install hooks are used by legitimate native modules. The javascript-obfuscator library is a commercial product with paying customers who are not attackers. Scanning for any one of them produces mostly false positives, which is why an alert built on obfuscation alone teaches people to ignore alerts.

What is rare is a package acquiring all three in a single version after years without them. That is not a property of the code; it is a property of the change. It is also why the question we ask of every new release is not "does this look dangerous" but "is this package still doing what it was doing yesterday".

Detection, the version-delta analysis and the timeline are ours. The affected version was removed from npm on the same day we flagged it; we have not attributed it to anyone and have not published the payload. More research at nithic.ai/research.