How NPM Supply Chain Attacks Spread Through Dependencies

Farouk Ben. - Founder at OdownFarouk Ben.()
How NPM Supply Chain Attacks Spread Through Dependencies - Odown - uptime monitoring and status page

The Node Package Manager ecosystem faced a significant security incident in September 2025 when attackers compromised over 500 packages through a self-replicating worm dubbed "Shai-Hulud." This attack demonstrated how a single compromised developer account can cascade into a widespread supply chain breach affecting millions of applications worldwide.

This incident wasn't just another security headline. It exposed fundamental vulnerabilities in how developers trust and consume open-source packages, and how quickly automated attacks can spread through interconnected dependency trees.

Table of contents

Understanding NPM supply chain attacks

Supply chain attacks targeting package managers exploit the trust relationships between developers and open-source libraries. When you install an NPM package, you're not just pulling in that single library. You're bringing in its entire dependency tree, which can include dozens or even hundreds of other packages.

This creates a multiplicative attack surface.

Attackers have recognized that compromising a single popular package maintainer account can provide access to millions of downstream applications. The NPM registry processes over 2.6 billion downloads weekly for some packages, making it an attractive target for malicious actors seeking maximum impact.

The threat model has evolved from simple typosquatting to sophisticated social engineering campaigns. Modern attackers use credential phishing, session hijacking, and automated propagation mechanisms to maximize their reach before detection.

The Shai-Hulud attack mechanism

The September 2025 attack began with a targeted phishing campaign disguised as an NPM security alert. A developer clicked a malicious link and unknowingly provided their credentials to attackers. That single mistake triggered a chain reaction affecting hundreds of packages.

What made this attack different was its autonomous nature. After the initial compromise, the malware operated independently, spreading through the ecosystem without requiring constant attacker intervention.

The worm leveraged post-install scripts, a legitimate NPM feature that executes code automatically when a package is installed. These scripts normally handle tasks like compiling native modules or setting up configuration files. But in this case, they executed malicious payloads that scanned for credentials, exfiltrated data, and propagated to additional packages.

Initial compromise and credential harvesting

Once the malware gained a foothold on a developer's machine, it immediately began scanning the environment for sensitive credentials. The primary targets included:

  • GitHub Personal Access Tokens (PATs) stored in configuration files
  • AWS access keys and secret keys
  • Google Cloud Platform service account credentials
  • Microsoft Azure authentication tokens
  • NPM registry authentication tokens

These credentials were typically found in environment variables, configuration files, and credential management tools. The malware used file system scanning techniques to locate common storage locations like .env files, .aws /credentials, and .npmrc files.

After harvesting credentials, the malware established communication with command-and-control infrastructure. It uploaded stolen data to endpoints controlled by the attackers and also created public repositories named "Shai-Hulud" using the compromised GitHub accounts, essentially using GitHub itself as part of the exfiltration infrastructure.

This approach was clever because it blended malicious traffic with legitimate GitHub API calls, making detection more difficult.

Self-replication and autonomous propagation

The worm's self-replication mechanism set it apart from traditional supply chain attacks. Once installed in a development environment, the malware performed several automated operations:

First, it authenticated to the NPM registry using stolen credentials. This gave it the ability to publish new package versions under the compromised developer's account.

Second, it injected malicious code into packages the developer maintained. The injected code included the same propagation logic, creating a self-perpetuating cycle.

Third, it published these compromised versions to the NPM registry, where they became available for download by unsuspecting users.

The propagation speed was remarkable. Within 48 hours of the initial compromise, researchers had identified over 500 affected packages. The attack spread through both direct dependencies and nested dependency trees, meaning applications could be compromised even if they didn't directly include an affected package.

Malicious workflow injection

The attack included a sophisticated GitHub Actions workflow injection component. The malware created new branches in compromised repositories with names like "shai-hulud" and uploaded malicious workflow files to .github/workflows /shai-hulud-workflow.yml.

These workflows executed automatically during CI/CD pipelines, performing additional credential harvesting. The workflow files contained instructions to:

  1. Enumerate all secrets available in the GitHub Actions runtime environment
  2. Package those secrets into JSON payloads
  3. Transmit the data to attacker-controlled webhook endpoints

This technique was particularly effective because GitHub Actions workflows have access to repository secrets by design. Developers often store production credentials in these secret stores for deployment automation.

The malware also used the GitHub REST API to identify repositories where the compromised account had write access. It queried endpoints like /user/repos? affiliation=owner, collaborator, organization_member to build a target list, then systematically created malicious branches and uploaded workflow files to each repository.

Repository cloning and data exfiltration

Beyond credential theft, the attack included a comprehensive repository cloning operation. The malware targeted private repositories within organizations, creating mirror copies under attacker-controlled accounts.

The cloning process followed these steps:

The malware first verified it had valid authentication tokens with sufficient permissions to access private repositories. It then used API pagination to enumerate all repositories within target organizations, focusing specifically on private and internal repositories to maximize the value of stolen intellectual property.

For each discovered repository, the attack created a corresponding repository in the attacker's GitHub account. These cloned repositories included a description containing "Shai-Hulud Migration" for tracking purposes.

After creation, the malware performed a full mirror clone, capturing not just the current code state but the entire Git history, including all branches, commits, and tags. This complete history could reveal sensitive information developers thought they had removed from current versions.

Perhaps most damaging, the malware then changed the visibility settings of these stolen repositories to public, exposing potentially sensitive source code and intellectual property to anyone on the internet.

Cryptocurrency theft operations

In addition to credential harvesting and code theft, certain variants of the attack included cryptocurrency theft mechanisms. These components targeted web applications that handled cryptocurrency transactions.

The malware injected code that hijacked web APIs related to cryptocurrency operations. When users attempted to send funds to legitimate addresses, the malicious code intercepted the transaction and substituted wallet addresses controlled by the attackers.

This attack vector was particularly insidious because it operated transparently to end users. From the user's perspective, they were interacting with a legitimate application and confirming transactions to their intended recipients. But behind the scenes, the malware redirected funds to attacker wallets.

The cryptocurrency theft component spread through popular JavaScript libraries used in web development, affecting both organizations and individual users who interacted with compromised applications.

Technical attack chain breakdown

Let's walk through the complete attack sequence from initial compromise to full propagation:

Phase 1: Social engineering A developer receives a phishing email disguised as an NPM security alert. The email contains a link to a fake login page that captures credentials when the developer attempts to authenticate.

Phase 2: Environment reconnaissance After obtaining credentials, the malware executes on the developer's machine and begins scanning for additional credentials and tokens. It searches common file locations and environment variables.

Phase 3: Credential exfiltration Harvested credentials are transmitted to attacker-controlled infrastructure through HTTPS requests to webhook endpoints, making the traffic appear legitimate.

Phase 4: GitHub repository compromise Using stolen GitHub PATs, the malware authenticates to the GitHub API and enumerates all accessible repositories. It creates malicious branches and injects workflow files into each repository.

Phase 5: Secret scanning The attack downloads and executes TruffleHog, a legitimate security tool designed to find credentials in Git repositories. But instead of alerting developers to security issues, the malware uses it to harvest additional secrets.

Phase 6: NPM package compromise The malware modifies packages the developer maintains, injecting malicious post-install scripts. These scripts contain the same propagation logic, enabling the worm to spread to anyone who installs the compromised package.

Phase 7: Publication Compromised package versions are published to the NPM registry under the legitimate maintainer's account, bypassing trust mechanisms that developers rely on.

Phase 8: Propagation When other developers install or update packages that depend on compromised libraries, the malware executes on their systems and repeats the entire cycle.

This multi-stage approach created exponential growth in the attack's reach. Each compromised developer account could potentially lead to multiple compromised packages, each of which could compromise dozens of downstream projects.

Affected regions and impact scope

Telemetry data indicated that the attack had global reach, but certain regions experienced higher concentrations of compromised systems. North America and Europe saw the most significant impact, likely due to the high concentration of software development activity in those regions.

The types of packages affected varied widely. Some were popular utility libraries with millions of weekly downloads. Others were less widely used but occupied critical positions in dependency chains, meaning they were included indirectly in many projects.

Packages related to:

  • Color manipulation utilities
  • Build system tools
  • Cryptographic functions
  • Development frameworks
  • Testing libraries

Organizations that rely on JavaScript for web application development were at highest risk. This includes companies building single-page applications, Node.js backend services, and hybrid mobile applications using frameworks like React Native or Electron.

One notable aspect of the attack was that it didn't discriminate based on package popularity. Both widely-used libraries and smaller utility packages were compromised, reflecting the automated nature of the propagation mechanism.

Detection and response strategies

Detecting supply chain compromises requires a multi-layered approach combining dependency analysis, credential monitoring, and network traffic inspection.

The first step is identifying whether your projects include affected packages. This requires examining package-lock.json or yarn.lock files to see the complete dependency tree, including nested dependencies that might not be obvious from your direct imports.

Many affected packages were deep in dependency chains. Your application might not directly require a compromised package, but one of your dependencies could pull it in transitively. You need tools that can flatten the dependency tree and check each entry against known compromised versions.

Artifact repositories and dependency caches present another challenge. Even if you update your package manifests to exclude compromised versions, cached copies might persist in CI/CD systems, container registries, or local node_modules directories.

Dependency auditing practices

Regular dependency auditing should be a standard practice, not just a response to active threats. The NPM CLI includes built-in tools for this purpose:

npm audit

This command checks your dependencies against a database of known vulnerabilities. But it only works if the vulnerabilities have been reported and cataloged. Zero-day supply chain attacks won't appear in these databases initially.

For more comprehensive protection, you need to:

  • Pin dependency versions to specific releases rather than using semantic version ranges
  • Review the actual code in your dependencies, especially for packages that update frequently
  • Monitor package maintainer changes, as account compromises often result in ownership transfers
  • Check package publication dates against when you last audited dependencies

Some organizations implement additional verification steps:

  • Running packages in sandboxed environments before deployment
  • Analyzing package behavior for suspicious network connections or file system access
  • Maintaining private NPM registries with vetted packages
  • Using software bill of materials (SBOM) tools to track all components in production systems

Credential rotation procedures

After any potential exposure, rotating credentials is non-negotiable. But effective rotation requires more than just changing passwords.

For GitHub Personal Access Tokens:

  1. Revoke all existing PATs from your GitHub account settings
  2. Generate new tokens with minimal required permissions
  3. Update all systems that use these tokens for authentication
  4. Enable GitHub's secret scanning alerts to detect if tokens are committed to repositories

For cloud service credentials:

  1. Rotate access keys and secret keys for AWS, GCP, and Azure
  2. Review IAM policies to ensure compromised credentials didn't result in permission escalations
  3. Check CloudTrail (AWS) or equivalent audit logs for unauthorized API calls
  4. Implement temporary credentials where possible instead of long-lived access keys

For NPM tokens:

  1. Revoke existing authentication tokens from npmjs.com account settings
  2. Generate new tokens with appropriate scope limitations
  3. Enable two-factor authentication on your NPM account
  4. Review all packages you maintain for unauthorized version publishes

The rotation process should happen immediately upon suspicion of compromise, not after confirming it. The cost of unnecessarily rotating credentials is minimal compared to the potential damage from delayed response.

Network monitoring and anomaly detection

Network traffic analysis can reveal compromise indicators that file-based scanning might miss. The Shai-Hulud attack communicated with specific domains for exfiltration:

  • Outbound connections to webhook.site domains
  • Unusual GitHub API traffic patterns
  • High-volume data transfers to unfamiliar endpoints

Implementing network monitoring involves:

Firewall log analysis: Review logs for connections to suspicious domains. The attack used webhook services for data exfiltration, which can be blocked at the network perimeter.

API call pattern detection: Normal GitHub API usage follows predictable patterns. Automated attacks generate high-frequency API calls that deviate from typical developer behavior.

Data transfer volume monitoring: Large repository cloning operations create significant outbound traffic. Baseline your normal traffic patterns and alert on anomalies.

DNS query monitoring: Track DNS requests for unusual domains. The attack infrastructure often uses dynamically generated domain names or lesser-known hosting providers.

For organizations with mature security operations, implementing these monitoring capabilities through SIEM (Security Information and Event Management) systems allows correlation of events across multiple data sources.

Long-term prevention measures

Reactive response to supply chain attacks is necessary, but prevention is better. Building resilient development practices reduces your attack surface.

Implement phishing-resistant MFA: Password-based authentication alone is insufficient. Use hardware security keys or biometric authentication that can't be phished through fake login pages.

Harden GitHub security:

  • Remove unused GitHub Apps and OAuth applications
  • Audit repository webhooks for suspicious endpoints
  • Enable branch protection rules to prevent unauthorized code changes
  • Activate GitHub Secret Scanning alerts
  • Configure Dependabot security updates for automated vulnerability patching

Establish package vetting processes: Don't blindly trust new dependencies. Before adding a package to your project:

  • Review the package's GitHub repository for red flags (few contributors, recent ownership changes, unusual commit patterns)
  • Check the package's download statistics and community adoption
  • Examine the actual source code, particularly install scripts
  • Verify the package maintainer's identity and reputation

Use dependency pinning: Instead of accepting any version that satisfies a semantic version range, pin exact versions in your package-lock.json. This prevents automatic updates to compromised versions.

Implement continuous security scanning: Integrate security scanning into your CI/CD pipeline so that every build checks for known vulnerabilities and suspicious dependency changes.

Maintain offline backups: Keep versioned backups of your dependencies in private artifact repositories. If the public NPM registry is compromised, you can continue building with known-good versions.

Monitoring your infrastructure

Supply chain attacks are just one category of threats that can impact application availability and security. Comprehensive monitoring helps detect issues before they become critical failures.

Website and API monitoring tools track uptime, performance, and security characteristics across your infrastructure. These systems can alert you to anomalies that might indicate compromise, such as unexpected downtime, performance degradation, or SSL certificate issues.

For organizations managing multiple services, status pages provide transparency during incidents. When a supply chain attack forces you to take systems offline for remediation, communicating clearly with users reduces frustration and maintains trust.

SSL certificate monitoring prevents outages caused by expired certificates. While not directly related to supply chain security, maintaining valid certificates is part of a comprehensive security posture.

Odown provides integrated monitoring for uptime, SSL certificates, and public status pages. By continuously checking your infrastructure and alerting on issues, monitoring tools help you maintain security and availability even when responding to supply chain compromises that require taking systems offline for updates or credential rotation.

Regular monitoring isn't just about catching attacks in progress. It establishes baseline behavior patterns that make anomalies easier to spot. When your systems suddenly start behaving differently, you'll know immediately rather than discovering the problem weeks later through customer complaints or security breach notifications.