Skip to main content
OIDC Tokens Hijacked to Ship Signed MalwareIncident
4 min readFor DevOps Leaders

OIDC Tokens Hijacked to Ship Signed Malware

On February 28, 2025, security researchers at Endor Labs discovered that attackers had published malicious versions of popular JavaScript packages—including TanStack Query and Mistral AI's SDK—using stolen credentials and valid cryptographic signatures. The packages passed all standard verification checks because they were legitimately signed, yet they contained malware.

This wasn't a compromised maintainer account or a typosquatting campaign. The threat group, tracked as TeamPCP, hijacked OpenID Connect tokens from CI/CD pipelines and used them to publish packages that npm's infrastructure accepted as authentic. The attack, named Shai-Hulud, compromised over 160 npm packages and an unknown number on PyPI.

Attack Timeline

February 27-28, 2025: Attackers published malicious versions of multiple packages, including TanStack Query and Mistral's JavaScript SDK. Each package included valid SLSA Build Level 3 provenance attestations—cryptographic proof that the package was built by the legitimate project's CI/CD pipeline.

February 28: Endor Labs detected the compromised packages and notified affected maintainers. The malicious versions were removed from npm within hours.

Post-incident analysis: Researchers determined that the attackers had stolen OIDC tokens—short-lived credentials that GitHub Actions and other CI platforms use to authenticate to package registries. With valid tokens, the attackers could publish packages that appeared to come from the legitimate build pipeline.

Identifying Control Failures

The attack succeeded because multiple defensive layers either didn't exist or failed:

Token lifecycle management: The stolen OIDC tokens remained valid long enough for attackers to use them. Your CI/CD platform issues these tokens automatically when a workflow runs, and they're designed to be short-lived. However, "short-lived" might mean 15 minutes to an hour—plenty of time if an attacker can exfiltrate the token during a workflow run.

Runtime monitoring in CI/CD: The pipelines that generated these tokens had no behavioral detection. A normal TanStack build publishes one package version. An attacker publishing dozens of versions in rapid succession should trigger alerts. It didn't.

Package content verification: npm verified the cryptographic signature but not the package contents. The signature proved the package came from TanStack's pipeline—it didn't prove the package was safe. No automated system checked whether the newly published version contained credential-stealing code that the previous version didn't.

Dependency pinning: Downstream users who installed these packages likely used version ranges (^5.0.0) rather than exact versions. When the malicious version was published, npm install pulled it automatically.

Standards and Requirements

NIST 800-53 Rev 5, SA-10 (Developer Configuration Management): Requires organizations to "employ integrity verification tools to detect unauthorized changes to software and information." The control explicitly calls out the need to verify that software components haven't been tampered with during the build and deployment process. Cryptographic signatures satisfy the "integrity verification" requirement, but only if you verify what was signed. In this case, the signature verified the publisher's identity—not the package contents.

SLSA Build Level 3: Provides provenance attestation—a signed statement about how and where a package was built. The Shai-Hulud packages had valid Level 3 attestations because they were built by the legitimate pipeline. The standard doesn't require verifying that the build output matches expectations. That's the gap.

ISO/IEC 27001:2022, Control 8.31 (Separation of Development, Test, and Production Environments): Requires separation between environments and controlled promotion between them. If your CI/CD pipeline can publish directly to a production package registry without human review, you're not meeting this control's intent. The malicious packages went from build to public registry with no checkpoint.

PCI DSS v4.0.1, Requirement 6.3.2: For organizations processing payment data, this requirement mandates that custom code is reviewed before release to production. While this applies specifically to payment applications, the principle extends to any code that handles sensitive data. If your package registry publishes automatically from CI/CD, you have no review gate.

Actionable Steps for Your Team

Implement lockfile-only installs: Configure your package manager to install only the exact versions specified in your lockfile. In npm: npm ci instead of npm install. In pip: pip install --require-hashes -r requirements.txt. This prevents automatic upgrades to compromised versions.

Add behavioral analysis to your CI/CD pipeline: Monitor for anomalies in your build and publish workflows. Alert on: multiple package versions published in a short time window, builds triggered outside normal hours, publish actions from unexpected geographic locations, or tokens used to publish packages they've never published before.

Scope your OIDC tokens tightly: GitHub Actions and other platforms let you configure OIDC token claims. Limit each token to the specific action it needs to perform. A token issued during a TanStack build should only be able to publish TanStack packages—not arbitrary packages from the same organization.

Implement a publish approval gate: Require human approval before publishing to your package registry. This breaks the direct CI/CD-to-registry path and gives you a checkpoint to verify that the package contents match expectations. For open-source projects, this might mean requiring two maintainers to approve each release.

Monitor your published packages: Run automated content scanning on packages after they're published. Compare each new version to the previous version and alert on unexpected changes: new network connections, file system access, credential access APIs, or obfuscated code.

Rotate tokens aggressively: Even short-lived OIDC tokens can be stolen if an attacker compromises your CI/CD environment. Configure your tokens to expire after minutes, not hours. If your workflow needs a token for an extended operation, break the operation into smaller steps with separate tokens.

The Shai-Hulud attack didn't exploit a vulnerability in npm's security model. It exploited the fact that "cryptographically signed by the legitimate publisher" and "safe to install" are not the same thing. Your verification process needs to check both.

Topics:Incident

You Might Also Like