```html ``` Yesterday We Shipped a Malicious-Package Blocker. Today a Real npm Compromise Dropped. Here's the Receipt.
top of page

Yesterday We Shipped a Malicious-Package Blocker. Today a Real npm Compromise Dropped. Here's the Receipt.

  • Writer: Patrick Duggan
    Patrick Duggan
  • 1 hour ago
  • 4 min read

Yesterday afternoon we shipped a free tool called check-package: a single call your AI coding agent can make to ask us whether a dependency is malicious before it runs the install. One URL, no key, backed by an OSV-curated deny-list of a quarter-million named-bad packages. We said the whole point was to collapse the friction between "a supply-chain attack exists" and "your agent is protected from it."


Then, roughly a day later, the world handed us a test.



What dropped


On July 11, the official jscrambler npm package — the command-line client for a well-known JavaScript protection product, around sixty thousand downloads a month — was compromised. Not a lookalike, not a typosquat. The real package, trojanized at the source through an account or CI compromise, across five published versions: 8.14.0, 8.16.0, 8.17.0, 8.18.0, and 8.20.0.


The payload was not subtle. Every bad version dropped a 7.8-megabyte binary container carrying a Rust-compiled infostealer built for Linux, Windows, and macOS. It went after browser credentials, Bitwarden vault data, and Steam sessions, and it dug in with a Windows scheduled task and a macOS LaunchAgent. The attacker even evolved the technique in real time as defenders reacted — early versions used a preinstall hook, later ones moved the injection to require-time to slip past the standard ignore-scripts defense.


Credit where it belongs: Socket's scanners flagged the compromised package about six minutes after it was published, and their write-up is the source of the indicators below. The maintainers fought back and reclaimed the latest tag with clean releases at 8.15.0 and 8.22.0.



What we did with it


This is the part that matters to us, because it is the thing we said the tool was for.


We pulled the indicators, and this morning we ingested them into our feed: the five malicious versions as a version-scoped deny-list entry, plus the six file hashes — the two malicious JavaScript files, the poisoned package manifest, and the three native stealer payloads. High confidence, named, sourced. No command-and-control domains were disclosed in the analysis, so we did not invent any; the exfiltration rides over TLS to an undisclosed endpoint.


Then we asked our own tool the question a developer's agent would ask.


Check-package on jscrambler version 8.14.0 comes back malicious true, verdict block. Check-package on the clean 8.22.0 comes back malicious false, verdict review — because it is version-aware: it knows the package name was compromised but this specific version was not, so it does not block the fix, it just tells you to confirm your version. That distinction is the difference between a guardrail and a blunt instrument.


So the loop that we described yesterday as a design goal was, this morning, a measured fact: a real, named, in-the-wild supply-chain compromise went from public disclosure to blocked-by-our-tool in under twenty-four hours, with no key and no signup on the consuming side. Anyone whose agent calls check-package before installing is now protected against this specific attack, and so is anyone consuming the same deny-list as a CI build gate.



The indicators, plainly


For anyone hunting their own environment, the malicious jscrambler npm versions are 8.14.0, 8.16.0, 8.17.0, 8.18.0, and 8.20.0. The clean, safe versions are 8.15.0 and 8.22.0 — pin to 8.22.0 and audit any machine that installed one of the bad ones.



All six now live in our STIX feed, and the package entry now answers to check-package.



The honest part


Held to about ninety-five percent, as always. We did not detect this — Socket did, and they did it in six minutes, which is genuinely fast and worth saying out loud. Our contribution is narrower and specific: we take an intelligence signal like this one, turn it into a machine-actionable verdict, and make that verdict free to consume at the exact moment an agent is about to make the mistake. The deny-list is large and curated, but it is not the entire universe of bad packages, so this is a strong layer and not a force field. Absence from the list is not proof of safety; pin and review your dependencies regardless.


But the shape of the day is the argument. Yesterday the guardrail was a claim. Today a real infostealer rode a trusted package into sixty thousand downloads a month, and the same guardrail — free, one URL, running since yesterday afternoon — now stops it cold and knows not to punish the fix. The attackers understand that your AI agent is the way in. The distance between their next move and your protection is the number that matters, and this week that number was under a day.


The tool is at the base of our API, path /api/v1/mcp. Point your agent at it and tell it to check before it installs. It costs nothing, and jscrambler is the reason we built it.




Every indicator in this post is in the feed. Free.

1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.


bottom of page