Φ
Blog

NPM Supply Chain: When a Dependency Becomes an Attack Surface

Recent attacks show that the risk is no longer limited to malicious packages. It now spans CI/CD, tokens, IDEs, AI agents, and the entire software delivery process.

Matheus Alves

Modern software is built on layers of dependencies. A typical web product may rely on hundreds or thousands of direct and transitive packages, installation scripts, CI/CD pipelines, third-party actions, IDE extensions, publishing tokens, cloud credentials, and automations that run without human intervention.

For a long time, NPM supply-chain risk was treated as a relatively familiar problem: typosquatting, fake packages, abandoned dependencies, or compromised maintainer accounts. Those risks still exist. But recent incidents point to a more serious shift: the target is no longer just the package. The target is now the development process itself.

The TanStack incident, part of the campaign known as Mini Shai-Hulud, made this clear. On May 11, 2026, 84 malicious versions were published across 42 @tanstack/* packages. According to the official postmortem, the attack combined a dangerous pull_request_target pattern, GitHub Actions cache poisoning, and extraction of an OIDC token from runner memory.

The most important detail is that this was not a simple NPM token theft. The formal publishing workflow was not directly compromised either. The attack moved through a chain of trust that appeared legitimate.

That distinction changes how companies need to think about security.

What Is Happening

The Mini Shai-Hulud campaign affected well-known packages across the NPM and PyPI ecosystems, including projects connected to TanStack, Mistral AI, UiPath, and OpenSearch. The malware was designed to steal GitHub and NPM tokens, CI/CD secrets, cloud credentials, API keys, and other sensitive data from development environments.

The risk is not limited to a developer's machine. If the compromised environment can publish packages, access internal repositories, or run pipelines, the malware can move laterally across the organization and the open source ecosystem.

The technical analysis from StepSecurity emphasized the campaign's self-replicating behavior: a compromised environment can become a redistribution point for new malicious packages.

In the TanStack case, the malware could be triggered during commands such as NPM install, PNPM install, or yarn install against affected versions. The malicious script looked for credentials in common locations, including AWS and GCP metadata, Kubernetes tokens, Vault, .NPMrc, GitHub CLI, .git-credentials, and SSH keys.

OpenAI's public response to the incident also shows the practical scope of the problem. The company reported that two corporate devices were impacted by a common open source library related to the TanStack attack, with no observed evidence of impact to customer data, production systems, or core intellectual property, but with credential rotation and operational containment.

The point for smaller companies is direct: even mature organizations can be affected when a trusted dependency becomes an attack vector. The difference is detection, containment, and response speed.

The Problem Is Not Using Open Source

Open source is not the problem. The problem is consuming open source without governance, inventory, isolation, and a response process.

The discussion raised by Mitchell Hashimoto about dependencies and supply chain captures a reaction that is gaining ground among experienced engineers: reduce unnecessary dependencies, question automatic updates, and treat critical libraries as architecture decisions rather than invisible implementation details.

In another part of the discussion, Mitchell connects supply chain risk to the sustainability of the open source ecosystem. This is a structural issue: companies depend on maintainers who often work alone, with limited financial, operational, or security support, while their packages support entire commercial products.

This does not mean every company should fork every dependency. That approach creates maintenance cost, increases the risk of missing security patches, and diverges from upstream.

The right provocation is different: a critical dependency cannot be treated as an invisible commodity.

The question is not just "should we always update?" or "should we freeze everything?". The question is:

  • which dependencies are critical;
  • who owns them;
  • how we update them;
  • how we test them;
  • how we block a suspicious version;
  • how we respond if a package has already been installed in a sensitive environment.

Tools Like Socket Firewall Help, but They Do Not Solve the Problem Alone

Socket launched Socket Firewall as a free layer for blocking malicious packages at install time. The tool works as a wrapper around package manager commands and supports JavaScript/TypeScript with NPM, yarn, and PNPM, Python with pip and uv, and Rust with cargo.

In practice, developers run commands such as:

sfw NPM install
sfw PNPM install
sfw pip install
sfw cargo fetch

Under the hood, sfw starts a temporary HTTP proxy, intercepts subprocess traffic, and checks the Socket API before the artifact is downloaded, extracted, and installed.

This matters because the block happens before package execution, not only afterward in a late-stage analysis.

But there are important limitations. Socket itself explains that if the artifact is already in the local cache, there may be no new network request for Socket Firewall to block. The recommendation is to clear the package manager cache before starting to use the tool.

The free version also does not support custom registries, does not block unknown or not-yet-scanned versions, and does not offer a configurable allow-list. Tools like this are a useful defensive layer, especially on developer machines and in CI, but they should not be the only defense.

Socket's analysis of the compromised TanStack packages reinforces another important point: provenance, OIDC, and trusted publishing help, but they should not be interpreted as absolute security guarantees when a trusted runner starts executing malicious code.

What Companies Should Do Now

The first step is to treat dependency installation as code execution.

Lifecycle scripts, Git-based dependencies, native binaries, IDE extensions, and internal CLIs can execute code with access to the filesystem, environment variables, tokens, and local credentials.

1. Use Lockfiles and Reproducible Builds

Avoid installing floating versions in CI and production.

Use NPM ci, PNPM install --frozen-lockfile, or an equivalent command.

A lockfile does not eliminate supply-chain attacks, but it reduces the chance that a deployment automatically pulls a newly published version that has not yet been widely observed.

2. Create a Quarantine Window for Updates

When possible, configure a minimum release age before accepting new versions.

The idea is simple: do not automatically install a package published only minutes ago. Many attacks are detected in the first few hours, and this window can keep your company from being among the first victims.

3. Do Not Run Automatic Updates Straight Into Production

Tools such as Renovate and Dependabot are useful, but they should open PRs with context, tests, and review.

For critical dependencies, it is reasonable to require human review, a changelog, a diff of the published package, and behavior validation in an isolated environment.

4. Review Critical and Transitive Dependencies

Not every dependency carries the same weight.

Libraries used in build tooling, authentication, cryptography, deployment, infrastructure, observability, and cloud SDKs deserve special treatment.

In some cases, it makes sense to use an internal fork, a private mirror, or a reduced version tailored to the real use case.

5. Disable Install Scripts When Possible

postinstall, prepare, and other lifecycle scripts are frequent vectors.

Disabling scripts globally can break some packages, so the decision needs to be tested. A more practical approach is to block by default in sensitive environments and allow explicit exceptions.

6. Separate Trusted Workflows From Untrusted Workflows

Avoid running code from external pull requests in workflows with elevated permissions.

The TanStack postmortem showed how pull_request_target, shared cache, and id-token: write can combine into an attack chain.

Release workflows need to be isolated, minimal, and reviewed as part of the security surface.

7. Reduce CI/CD Permissions

Configure minimum permissions per job.

Do not leave id-token: write, cloud secrets, NPM tokens, or GitHub PATs available to jobs that do not need them.

Prefer short-lived, scoped credentials issued only at the moment they are needed.

8. Do Not Rely on Provenance Alone

Trusted publishing, OIDC, and Sigstore are important improvements.

But a package can still be published through an apparently legitimate path if the trusted runner executes malicious code before publishing.

Provenance is a useful signal. It is not a replacement for isolation, workflow review, permission control, and publication monitoring.

9. Control IDE Extensions and Local Tools

The developer environment has become part of the perimeter.

VS Code extensions, AI agents, CLIs, plugins, and productivity tools can access files, terminals, and credentials.

Companies should maintain an allow-list of extensions, review auto-update behavior, and monitor changes in sensitive directories.

10. Maintain an Inventory and a Response Plan

In a supply-chain incident, the company needs to answer basic questions quickly:

  • Which repositories use the affected package?
  • Which version is in the lockfile?
  • Did any CI runner install the malicious version?
  • Which secrets were available in that environment?
  • Was any internal package published after the infection?
  • Which caches need to be cleared?
  • Which credentials need to be rotated?

Without inventory, logs, and clear ownership, response turns into guesswork.

A Minimum Response Playbook

If your company installed a version affected by this kind of attack, reverting the package is not enough.

The minimum procedure should be:

  1. Identify every environment that installed the affected version.
  2. Isolate potentially compromised hosts.
  3. Clear package manager caches and CI/CD caches.
  4. Rotate every secret accessible from those environments.
  5. Review publish logs in NPM, GitHub Packages, PyPI, or internal registries.
  6. Review recent commits, especially automated or unusual commits.
  7. Rebuild artifacts from a clean environment.
  8. Validate lockfile and hash integrity.
  9. Document the incident and update controls to prevent recurrence.

The recommendation to rotate credentials is not excessive. In the TanStack case, the project itself recommended rotating AWS, GCP, Kubernetes, Vault, GitHub, NPM, and SSH credentials accessible from hosts that installed affected versions.

A Technical Decision Is Also a Business Decision

Supply-chain attacks are difficult because they exploit a real tension: companies need to ship quickly, but they depend on code, tools, and automations they do not fully control.

The answer is not to stop using open source.

It is also not to add one more scanner and call the problem solved.

The answer is operational maturity:

  • fewer unnecessary dependencies;
  • disciplined updates;
  • CI/CD with clear boundaries;
  • short-lived, scoped credentials;
  • development machines treated as sensitive environments;
  • monitoring of publications and artifacts;
  • tested response process;
  • technical ownership over architecture decisions.

Supply-chain security is part of software engineering. It is not just a security topic.

How Fidalgo IT Solutions Can Help

Fidalgo IT Solutions acts as an independent technical service provider for companies that need to build, operate, or improve production systems with less improvisation and more technical control.

The service can help your company review dependencies, CI/CD architecture, GitHub Actions permissions, token usage, deployment pipelines, cloud configuration, secrets, build environments, observability, and risks in legacy systems.

It can also structure a practical risk reduction plan:

  • dependency inventory;
  • update policy;
  • pipeline hardening;
  • AWS and CI/CD review;
  • incident response;
  • recommendations for safe use of open source tools, IDEs, AI agents, and internal automations.

If your company depends on software to operate, sell, serve customers, or scale processes, it is worth reviewing now how that software is built and delivered.