Supply Chain Security

Software Supply Chain Attack at Scale: npm, PyPI, and Docker Hub Hit in 48 Hours

GitGuardian documented three distinct supply-chain campaigns striking npm, PyPI, and Docker Hub inside a single 48-hour window in April 2026. The simultaneity tells you more about attacker tooling than any single payload does.

Nayan Dey
Senior Security Engineer
7 min read

Between April 21 and April 23, 2026, GitGuardian documented three separate supply-chain campaigns landing on three different package ecosystems inside roughly 48 hours. One hit npm. One hit PyPI. One hit Docker Hub. They were not, as far as the public evidence goes, a single coordinated operation run from one command center. That is exactly what makes the episode worth sitting with.

When three unrelated-looking intrusions cluster this tightly across three registries, the interesting question is not "who did it." It is "why is this suddenly so easy to do in parallel." The answer says something uncomfortable about the state of registry security in 2026, and about how cheap it has become to weaponize the developer install step.

Three campaigns, one playbook

The campaigns differed in mechanics but converged on the same prize: secrets. Each one was built to harvest credentials out of developer machines and CI/CD runners — the GitHub tokens, cloud keys, SSH keys, and environment variables that quietly grant access to everything downstream.

The Docker Hub campaign, attributed by GitGuardian to a group it tracks as TeamPCP, compromised official Checkmarx KICS Docker images and VS Code extensions. Docker flagged suspicious activity on the affected repository on April 22 and Socket raised the alarm. Per GitGuardian, an obfuscated payload was built to harvest GitHub authentication tokens, AWS credentials, Azure and Google Cloud tokens, npm configuration files, SSH keys, and environment variables. It was reportedly the second Checkmarx-related attack by the same actor in two months — a detail that should bother anyone who assumes a clean-up means the threat is gone.

The npm campaign, dubbed CanisterSprawl by the researchers who found it (Socket and StepSecurity), abused a package called pgserve, a PostgreSQL server for Node.js. Malicious versions appeared on April 21 carrying a postinstall hook that fired on every install. According to GitGuardian, the script searched for npm publish tokens and, for each package the victim could publish, bumped the patch version, injected itself, and republished to npm. In other words, it was a worm. It used an Internet Computer Protocol canister as command-and-control infrastructure, which is the part that earned it the name and which makes takedown materially harder than pulling a single domain.

The PyPI campaign rode three consecutive releases of the xinference package, beginning April 22, and was surfaced by StepSecurity. It pulled SSH keys, cloud credentials, environment variables, and crypto wallets, then exfiltrated them as a plain, unencrypted tar.gz to a C2 server. GitGuardian linked it to the same TeamPCP cluster behind the litellm and telnyx PyPI compromises from March, though it noted the lack of encryption as a departure from prior tradecraft — enough of a wrinkle to raise the possibility of a copycat, even as the injection pattern stayed consistent.

The worm is the headline, not the count

It is tempting to read "three attacks in 48 hours" as a volume story. It isn't. Volume in open-source malware has been climbing for years; another busy week is not news.

The real signal is CanisterSprawl's self-propagation. A postinstall hook that finds a publish token, enumerates every package the victim can push to, and republishes itself across all of them is not a one-shot poisoning. It is a propagation mechanism. And the design explicitly contemplated jumping ecosystems: if the worm found a PyPI token sitting next to an npm token on the same developer's machine, it could carry itself from one registry into the other.

That cross-ecosystem reach is the line worth underlining. For years, defenders have implicitly treated npm, PyPI, and Docker Hub as separate threat surfaces with separate owners and separate tooling. A worm that treats them as one connected graph — linked through the credentials developers casually leave lying around — breaks that mental model. The registries are siloed. The secrets that unlock them are not.

What the simultaneity implies about tooling

Three campaigns from at least two distinct origins, all landing in the same window, all targeting secrets, all using the install or build step as the execution trigger. You do not get that pattern from a single brilliant attacker having a good week. You get it from commoditized tooling.

The components are now off-the-shelf. Typosquatting and account-takeover techniques for registries are well documented. Postinstall and build-time hooks are a legitimate, supported feature of every one of these ecosystems, which means the execution primitive is free. Credential-scraping payloads are modular and reusable; the TeamPCP material reportedly reused injection patterns across multiple packages and months. Resilient C2 — like the ICP canister behind CanisterSprawl — is increasingly available to anyone who wants it.

When every building block is cheap and reusable, the marginal cost of opening a second or third front drops toward zero. That is why three ecosystems got hit at once. Not coordination — convergence. Multiple actors independently reaching for the same commodity capabilities and pointing them at the same soft target: the developer's machine and the CI/CD pipeline behind it.

Defender implications

A few things follow directly, and none of them are new advice — which is rather the point. The techniques are old; the discipline is missing.

First, kill blind install execution. Every one of these campaigns relied on code running automatically at install or build time. Disable install scripts where you can (npm install --ignore-scripts and equivalents), pull dependencies through a vetted internal proxy, and treat any package that needs a postinstall hook as a thing that requires justification, not a default you wave through.

Second, assume your secrets are the actual target and design accordingly. All three campaigns went straight for tokens and keys. Short-lived, scoped credentials beat long-lived ones every time; OIDC-based, ephemeral CI credentials beat static tokens sitting in environment variables. A stolen credential that expired an hour ago is a non-event. A publish token with no expiry is a worm's fuel supply.

Third, pin and verify. Lockfiles, hash pinning, and provenance attestation turn a silent malicious republish into something your pipeline can refuse. CanisterSprawl worked by bumping patch versions and republishing — a floating version range walked straight into it; a pinned, hash-verified dependency would not have.

Fourth, watch the registries as one surface, not three. If your npm monitoring and your PyPI monitoring and your container scanning live in separate tools owned by separate teams, a cross-ecosystem worm will move through the seams between them. The attackers already think in terms of one connected credential graph. Defenders who still think in silos are giving up the same advantage the worm was built to exploit.

How Safeguard Helps

Safeguard treats npm, PyPI, and container registries as one supply-chain surface, not three disconnected feeds. Our AIBOM and provenance tooling flags unexpected republishes, postinstall execution, and missing attestation before a poisoned version reaches your build, and policy gates can block a deploy when a dependency's provenance does not check out. The reliability lives in our Multi-Agent TAOR Deep Think AI Engine — a verification and orchestration layer that runs above whatever model you bring (Griffin AI by default, or your own), so multi-agent cross-checking cuts the false positives that bury real findings like a malicious patch bump. If you want to see how that maps to your own pipeline, reach out.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.