DEV Community

Cover image for The npm Worm That Keeps Coming Back — And Why Governments Are Finally Procuring a Fix
Gavriliuc Vlada
Gavriliuc Vlada

Posted on

The npm Worm That Keeps Coming Back — And Why Governments Are Finally Procuring a Fix

On August 28, 2026, a npm package called @7nohe/openapi-react-query-codegen — a TanStack Query codegen tool with over 150,000 weekly downloads — started shipping malware. Ten malicious versions went out in twenty minutes. If that timeline sounds familiar, it should: this is the same Shai-Hulud worm family that's been eating through the npm and PyPI ecosystems since September 2025, now on its latest variant, nicknamed Trinitite.

What's actually interesting here isn't just "another supply chain attack." It's how the attack got in, how little changed about the fix, and — maybe more relevant if you build software that governments end up buying — how regulators are starting to respond with actual procurement, not just guidance documents.

How Trinitite Got In

The compromised release workflow had a genuinely dumb weak point: it treated a pull request comment containing the literal string "npm publish" as authorization to publish a release. No check that the commenter was a maintainer. The attacker checked out the PR, and GitHub Actions OIDC did the rest, publishing straight through the project's own trusted, legitimate pipeline.

This is the pattern that's defined the whole Shai-Hulud campaign since the original TanStack compromise in May 2026 (CVE-2026-45321, CVSS 9.6): attackers aren't targeting the package anymore, they're targeting the pipeline. That May incident chained a pull_request_target trigger, GitHub Actions cache poisoning, and OIDC token extraction from runner process memory — and the packages it produced carried valid SLSA Build Level 3 provenance attestations. Read that again: a worm that produces validly signed, attested malicious packages. Provenance confirms where an artifact was built. It says nothing about whether attacker-controlled code executed inside that trusted environment.

Once installed, Trinitite runs a fairly elaborate obfuscation chain — an XOR-wrapped loader, a hidden binding.gyp execution path that fires even when you run npm install --ignore-scripts, AES-256-GCM encrypted payload blobs — before dropping into familiar Shai-Hulud territory: stealing GitHub, npm, PyPI, RubyGems, cloud, Vault, and Kubernetes credentials, then republishing itself through any package the stolen credentials can reach.

One detail that puts the scale in perspective: a report from early September found that the latest Shai-Hulud variant now scans 469 distinct credential locations across developer machines, CI/CD tooling, cloud configs, and even AI tool configs, up from 189 in earlier versions. The attackers aren't breaking trust relationships anymore. They're just harvesting the credentials that make those relationships work in the first place.

Why "Just Review Your Dependencies" Isn't Really an Answer Anymore

Every writeup on this campaign converges on roughly the same mitigation list: lock down GitHub Actions cache and fork PR behavior, restrict which workflows can mint OIDC publish tokens, don't trust a passing provenance check as proof of safety, treat every secret reachable from a build environment as already exposed.

All correct. All also things a single team can only partially control, because the actual risk isn't your code — it's the 500+ transitive dependencies you didn't write, sitting in a supply chain you can't fully see. That's exactly the gap a Software Bill of Materials (SBOM) is meant to close: a structured, machine-readable inventory of every component and dependency in a piece of software, so when the next Trinitite-style compromise hits, you can actually answer "are we exposed?" in minutes instead of days of manually grepping lockfiles.

SBOMs for traditional software are already a regulatory requirement in the EU under the Cyber Resilience Act. What's newer, and what makes this genuinely current, is that the same idea is now being extended specifically to AI systems — where the "dependency graph" includes not just packages but models, datasets, and fine-tuning pipelines, none of which fit cleanly into a traditional SBOM format.

A Government Is Already Procuring This

Here's where it stops being abstract. Germany's Federal Office for Information Security (BSI) has an open tender for a project called SBOM4AI, published August 28, 2026 — the same day Trinitite started shipping, though the timing there is coincidental rather than causal.

The scope is specific: take the "SBOM for AI – Minimum Elements" concept published under the G7 framework and turn it into an actual technical implementation — a system that automatically generates a machine-readable SBOM for AI systems, in a format usable by developers, auditors, and regulators, explicitly designed to support Cyber Resilience Act auditability requirements. Contract duration is 18 months, deadline for bids is September 28, 2026.

What I find worth paying attention to isn't the tender itself so much as what it signals: a national cybersecurity authority is treating "we don't have a standard, automatable way to know what's inside an AI system's supply chain" as a problem serious enough to fund directly, rather than waiting for the private sector or a nonprofit consortium to solve it. Given that AI coding assistants are themselves accelerating how fast new dependencies get pulled into codebases — often outside standard package managers entirely — that's not a bad instinct.

What This Actually Means for Your Pipeline

You don't need a government contract to take the lesson here. A few concrete things worth doing regardless of team size:

  • Generate an SBOM as part of your build, not as an afterthought. Tools like Syft, CycloneDX, or GitHub's own dependency graph can do this automatically; the point is having it before an incident, not scrambling to reconstruct it during one.
  • Stop trusting provenance as a safety signal. SLSA attestations tell you where something was built. They don't tell you the build wasn't compromised in-flight, as Trinitite proved twice now.
  • Isolate fork PR workflows from cache and publish permissions. The pull_request_target and comment-triggered-publish patterns behind both major TanStack incidents are avoidable with a few lines of workflow config.
  • Treat any secret reachable from a CI runner as already leaked. Rotate on a schedule, not just on suspicion.

Trinitite won't be the last variant. The people behind the original TeamPCP toolkit were reportedly arrested in Australia shortly before this wave shipped, using the same core malware with new keys and new graffiti strings — which tells you the tooling outlives the individuals running it. The realistic goal isn't preventing the next worm. It's making sure that when it lands, you can answer "what do we actually have deployed, and what depends on it" faster than the worm can spread.

Top comments (0)