Skip to main content
84 npm Packages Poisoned Despite SLSA L3Incident
5 min readFor Security Engineers

84 npm Packages Poisoned Despite SLSA L3

On May 11, 2026, attackers published 84 malicious npm packages across 42 @tanstack repositories. Each package carried cryptographically valid SLSA Build Level 3 attestations. If your team relies on SLSA attestations as your primary supply chain defense, this incident should prompt a reevaluation of your security strategy.

What Happened

Attackers compromised the @tanstack publishing pipeline through a three-stage attack:

  1. Workflow Misconfiguration Exploit: A flaw in the GitHub Actions workflow allowed external influence over the build environment.
  2. Cache Poisoning: Attackers injected malicious code into the build cache, which was then incorporated into legitimate builds.
  3. OIDC Token Extraction: The compromised workflow exposed GitHub's OIDC tokens, which attackers used to authenticate to npm and Sigstore.

The result: malicious packages were published under the legitimate @tanstack identity, signed with valid Sigstore signatures, and carrying SLSA Build L3 attestations that passed all cryptographic verification checks.

Timeline

May 11, 2026

  • Attackers exploited GitHub Actions workflow misconfiguration.
  • Build cache was poisoned with malicious code.
  • OIDC tokens were extracted from the compromised workflow.
  • 84 malicious package versions were published to npm.
  • Packages were automatically signed via Sigstore.
  • SLSA Build L3 attestations were generated for all artifacts.

Which Controls Failed

Build Environment Isolation

SLSA Build Level 3 requires isolated builds, but the GitHub Actions runner environment failed to prevent:

  • External modification of the build cache.
  • Exposure of authentication credentials to the build process.
  • Cross-workflow contamination.

The isolation boundary assumed by SLSA L3 was effectively non-existent in this configuration. The standard requires that "the build service ensures that the build steps run in an isolated environment free of influence from other build instances," but GitHub Actions' shared runner architecture didn't enforce this for cache operations.

Source Verification

SLSA attestations prove that a specific source commit produced a specific artifact. They don't prove that:

  • The source commit itself is legitimate.
  • The build platform wasn't compromised.
  • The cache or dependencies used during the build are trustworthy.

In this attack, the attestations were technically correct—the malicious artifacts were produced from the specified commits using the specified workflows. The problem was that the workflow and build environment were compromised before the attestation process began.

Credential Scoping

The OIDC tokens provided by GitHub Actions have sufficient permissions to publish packages and sign artifacts. Once extracted, these tokens gave attackers everything they needed to publish under the @tanstack identity. There was no additional authorization check to ensure "this specific workflow run should only publish package X version Y."

What Standards Require

SLSA Build Level 3

SLSA Build L3 requires:

  • Isolated builds: "The build service ensures that the build steps run in an isolated environment free of influence from other build instances."
  • Provenance generation: Automated creation of provenance attestations.
  • Hermetic builds: "All transitive build steps, sources, and dependencies are fully declared up front."

The attack satisfied the provenance requirement but violated the isolation and hermeticity requirements. However, SLSA provides no enforcement mechanism—it's a framework for describing what happened, not for preventing what shouldn't happen.

NIST 800-53 Rev 5

SA-10 (Developer Configuration Management): Requires organizations to manage the configuration of the system under development and implement only organization-approved changes.

The cache poisoning attack violated this control. The build incorporated unapproved changes through a side channel (the cache) that wasn't covered by the source control approval process.

SA-15 (Development Process, Standards, and Tools): Requires organizations to follow a documented development process that includes security and privacy tracking of security flaws.

The workflow misconfiguration that enabled the attack represents a failure in secure development process documentation and review.

ISO/IEC 27001:2022

Control 8.31 (Separation of development, test and production environments): Requires organizations to separate development, test, and production environments to reduce the risks of unauthorized access or changes to the production environment.

The shared runner environment and cache infrastructure created insufficient separation between different build instances, allowing one compromised workflow to affect others.

Lessons and Action Items

1. Implement Build Platform Isolation

Action: Migrate to self-hosted runners with dedicated, ephemeral VM instances per build. Configure your CI/CD to:

  • Destroy and recreate the entire build environment for each run.
  • Disable cache sharing between workflows or repositories.
  • Use separate service accounts for different publishing targets.

Verification: Your build logs should show a fresh environment initialization for every run. No cache hits from previous workflows.

2. Add Policy-Based Publishing Controls

Action: Implement a policy layer between your build system and package registries:

  • Require manual approval for first-time package versions from a repository.
  • Enforce that package names match repository names.
  • Rate-limit publishing operations per repository.
  • Alert on publishing patterns that deviate from historical norms.

Verification: Attempt to publish a package from an unauthorized repository. The policy layer should block it even if the OIDC token is valid.

3. Verify Source Integrity Before Build

Action: Add pre-build verification that:

  • Checks commit signatures (require GPG-signed commits).
  • Validates that the commit is on an approved branch.
  • Confirms the commit has passed required reviews.
  • Scans the commit diff for suspicious patterns.

Verification: Your build should fail if you push an unsigned commit or bypass branch protection.

4. Scope OIDC Tokens to Specific Artifacts

Action: Configure your OIDC token claims to include:

  • Expected package name.
  • Expected version number.
  • Specific workflow file path and commit SHA.

Then configure your package registry to validate these claims before accepting uploads. npm supports custom subject claims in OIDC tokens—use them.

Verification: An OIDC token from your workflow should be rejected if used to publish a different package than the one specified in the token claims.

5. Monitor for Attestation Anomalies

Action: Build a monitoring system that tracks:

  • Number of packages published per day from each repository.
  • Sigstore certificate subject identities.
  • SLSA attestation issuer claims.
  • Time between commit and publish.

Alert when these metrics deviate from your baseline. The @tanstack attack published 84 packages in rapid succession—that's detectable.

Verification: Publish a test package outside normal hours or in unusual volume. Your monitoring should alert.

Conclusion

SLSA attestations tell you what happened. They don't prevent what shouldn't happen. Treat SLSA as an audit trail, not an access control mechanism. You still need policy enforcement at the boundaries: before the build starts, during artifact publication, and when packages are consumed.

The attack succeeded because the security controls stopped at cryptographic verification. The signatures were valid. The attestations were correct. The build platform was compromised. All three things can be true simultaneously.

Your defense needs to assume that any single layer—including SLSA attestations—can be bypassed or subverted. Build defense in depth: source verification, build isolation, policy enforcement, runtime monitoring. Each layer should catch what the others miss.

Topics:Incident

You Might Also Like