تخطي إلى المحتوى الرئيسي
Cyber News Unit 42 3 days ago

The npm Threat Landscape: Attack Surface and Mitigations (Updated July 15)

Un
Unit 42

Executive Summary

The security of the npm ecosystem reached a critical inflection point in September 2025. The Shai-Hulud worm, a self-replicating malware that automated the compromise and redistribution of malicious packages, marked the end of the “nuisance” era of npm attacks and the beginning of a high-consequence threat landscape.

Since that watershed moment, Unit 42 has tracked an aggressive acceleration in the frequency and technical depth of supply chain compromises. Attacks have evolved from a series of isolated typosquatting incidents into systematic campaigns by various threat actors to weaponize the trust that powers modern software development.

April 2026 Campaigns

We have seen two campaigns in April: the first started April 22, 2026 and included the string Shai-Hulud: The Third Coming. The second started April 29, 2026 and is known as Mini Shai-Hulud.

May 2026 Campaigns

In May 2026, the Mini Shai-Hulud campaign continued with two new waves attributed to TeamPCP. These campaigns introduced two unique elements. One campaign used a credential-free initial access technique. The other campaign generated the highest single-hour package count of any Shai-Hulud worm to date. Copycat activity has made future attribution to TeamPCP more difficult.

June 2026 Campaign

A new supply chain attack on June 1, 2026 compromised at least 32 packages published under the @redhat-cloud-services npm namespace. The attacker bypassed code review entirely, pushing a payload named Miasma.

July 2026 Campaign

Attackers compromised the release pipelines of four core AsyncAPI GitHub repositories on July 14, 2026. In a campaign calling itself miasma-train-p1, they published five trojanized packages to npm:

  • @asyncapi/generator@3.3.1
  • @asyncapi/specs@6.11.2
  • @asyncapi/specs@6.11.2-alpha.1
  • @asyncapi/generator-helpers@1.1.1
  • @asyncapi/generator-components@0.7.1

The payload appears to be a descendant of the Miasma remote access Trojan (RAT).

The New Baseline for npm Threats

The Shai-Hulud incident proved that the npm registry could be used as a force multiplier for malware distribution. In the months following, we have observed three core shifts in adversary TTPs:

  • Wormable propagation: Malicious payloads now prioritize the theft of npm tokens and GitHub Personal Access Tokens (PATs) to automatically infect and republish legitimate packages, as seen in the March 2026 Axios compromise.
  • Infrastructure-level persistence: Attackers are no longer just stealing data; they are embedding themselves into continuous integration/continuous delivery (CI/CD) pipelines to attain long-term, undetectable access to enterprise environments.
  • Multi-stage payloads: Following the September 2025 template, current attacks often deploy dormant “sleeper” dependencies that only activate under specific environmental conditions to evade automated scanners.

npm Attacks Seen As a Whole

npm compromises have common themes. In the post-Shai-Hulud era, we believe it is helpful to consider the attack surface as a whole.

This article will combine:

  1. Details of major incidents: Real-time analysis of significant package compromises (e.g., Shai-Hulud 2.0, Axios, Chalk/Debug)
  2. Cross-campaign correlation: Identifying common infrastructure or code snippets that link disparate attacks to the same threat actors
  3. Remediation playbooks: Actionable guidance for rotating credentials and purging malicious dependencies from local and cloud-based caches

Shai-Hulud: A New Wave

A malicious npm package published as @bitwarden/cli version 2026.4.0 was identified as part of a broader supply-chain campaign attributed to TeamPCP. The package impersonates the legitimate Bitwarden command-line interface (CLI) password manager. Upon installation, it executes a multi-stage payload that steals credentials from cloud providers, CI/CD systems and developer workstations. It then self-propagates by backdooring every npm package the victim can publish. It has been noted that inside public GitHub repositories that were published contained the string “Shai-Hulud: The Third Coming.”

Attackers deployed the same payload across multiple Checkmarx distribution channels, indicating a coordinated campaign to weaponize compromised developer tooling credentials to maximize the area of impact:

  • Docker Hub images
  • GitHub Actions
  • VS Code extensions

Palo Alto Networks customers are better protected from the threats described in this article through the following products and services:

The Unit 42 Incident Response team can also be engaged to help with a compromise or to provide a proactive assessment to lower your risk.

Related Unit 42 Topics Supply Chain, Credential Harvesting, Obfuscation, Backdoor

July 2026 - Miasma Expansion or Potential Copycat?

On July 14, 2026, attackers compromised the release pipelines of four core AsyncAPI GitHub repositories, publishing five trojanized packages to npm:

  • @asyncapi/generator@3.3.1
  • @asyncapi/specs@6.11.2
  • @asyncapi/specs@6.11.2-alpha.1
  • @asyncapi/generator-helpers@1.1.1
  • @asyncapi/generator-components@0.7.1

The campaign calls itself miasma-train-p1, and the payload appears to be a descendant of the same Miasma RAT deployed in the June 2026 Red Hat supply chain operation. However, the initial access was different this time. Rather than a compromised employee account compromising the GitHub repository, the attackers exploited a process gap in the CI/CD pipeline itself.

The AsyncAPI repositories maintained strict branch protections and peer-review mandates on their primary main branches. However, pre-production release branches, specifically next and schema, were left unprotected. The threat actors pushed malicious commits directly to these shadow release branches that bypassed all human review (e.g., Commit 3eab3ec9304aa26081358330491d3cfeb55cc245 by attacker GitHub ID 148100). This commit triggered automated GitHub Actions build and release workflows.

The injected code ran inside the Continuous Integration (CI) runner itself, harvesting NPM_TOKEN and GITHUB_TOKEN environment secrets, then used the stolen npm token to programmatically publish backdoored package versions to the trusted @asyncapi scope on the public registry.

In contrast to the previous Miasma payload, this version’s architecture has changed. When a developer runs npm install on a compromised package, a backdoored source file executes, such as index.js, validator.js or utils.js.

To evade static code-integrity audits, the file exports a legitimate-looking schemas object with version-keyed JSON references. However, upon import, its main() function triggers a detached child process running an obfuscator.io-obfuscated script. That script determines the operating system via process.platform and creates a platform-specific persistence directory disguised as a legitimate NodeJS data folder:

  • %LOCALAPPDATA%\NodeJS on Windows
  • ~/Library/Application Support/NodeJS on macOS
  • ~/.local/share/NodeJS on Linux
  • ~/.config/node as a fallback

The payload then fetches the Stage-2 Miasma RAT from the InterPlanetary File System (IPFS) via a hard-coded content identifier (CID) Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf or QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9. It then writes the RAT as sync.js and spawns it with detached: true, stdio: 'ignore' and windowsHide: true.

The parent process calls child.unref() and exits cleanly, giving the perception that nothing is wrong. The RAT is now running headlessly in the background.

Once executing, the Miasma RAT writes an operational lockfile, ~/.config/.miasma/run/node.lock. It does so to prevent redundant instances and to establish persistence via a user-scoped systemd service (miasma-monitor.service on Linux and macOS, or a miasma-monitor Run key on Windows).

To bypass automated system audits, the RAT writes its host-tracking identity cache to paths that mimic legitimate OS application storage:

  • ~/Library/Application Support/com.apple.spotlight/index-v2.cache on macOS (mimicking the Spotlight search index)
  • ~/.cache/mesa_shader_cache/gl_cache.bin on Linux (mimicking the Mesa OpenGL shader cache)
  • %HOME%\AppData\Roaming\Microsoft\CryptnetUrlCache\Content\msrt.dat on Windows (mimicking the Cryptnet certificate cache)

Credential theft targets are consistent with the June campaign:

  • GitHub tokens
  • npm tokens
  • SSH keys
  • Cloud provider credentials
  • Kubernetes service-account tokens
  • CI/CD secrets

Perhaps the most notable escalation is the command-and-control (C2) infrastructure. During the June Red Hat incident, the variant used a straightforward central C2 server. This campaign layers a decentralized fallback network on top of its primary C2 at 85.137.53[.]71. The RAT regularly polls hxxp://85.137.53[.]71:8080/api/v1/beacon for task commands. It also exfiltrates harvested credentials via HTTP POSTs to hxxp://85.137.53[.]71:8080/api/v1/file-result, forwarded to a dedicated upload listener on port 8081.

If the primary C2 IP address was blocked, the RAT accessed the public Ethereum RPC gateway at ethereum-rpc[.]publicnode[.]com to examine an on-chain smart contract (0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710), which functioned as a decentralized registry for the active C2 address. This contract was launched by the adversary wallet 0x92d4C5413e4F7B258a114964101F9e1C6d64C6Ba and included a backup contract located at 0x1969ab05d67b67fdcaa26240f738ccb077e1cd84.

If that was also blocked, the RAT established communication with public Nostr relays (wss://relay.damus[.]io and wss://relay.nostr[.]com/) as out-of-band backup channels. Finally, it implemented a BitTorrent DHT bootstrap routine (using router.bittorrent[.]com:6881 and dht.transmissionbt[.]com:6881) to join a peer-to-peer network and discover alternate controllers.

This was a highly redundant, resilient and evasive C2 architecture designed to survive standard domain and IP-level mitigation strategies. Blocking any single layer does not kill the implant.

On July 14, 2026, Unit 42 researchers analyzed a compromised macOS developer machine on which the developer opened a project workspace in GitHub Copilot. When the copilot parsed the workspace and triggered automated dependency loading, it imported the trojanized @asyncapi/specs@6.11.2 package. This silently launched the Stage-1 loader, which fetched Miasma sync.js from IPFS and spawned it under Homebrew Node.js v22, initiating active beaconing to 85.137.53[.]71:8080.

The developer did not run npm install manually. The tooling did it for them.

The campaign also features self-attributed configurations that suggest this is merely the first wave of a broader, phased rollout. The worm's self-propagation capability is limited to four hops via a hard-coded generation cap (maxGen = 4). Additionally, its rollout approach leverages a default canary deployment strategy (batch.defaultStrategy = CANARY), which initially infects 5% of potential targets before scaling up in waves of 100.

This is not runaway malware. It is rate-limited by design to manage exposure and avoid triggering widespread detection during the initial spread.

Attribution remains the same open question as with the June 2026 campaign. The Miasma campaign shares infrastructure hosting patterns with TeamPCP, including the same Dutch autonomous system (AS43641/VSYS-AMS) used in prior operations against AntV, TanStack and Red Hat. With the addition of this miasma-train-p1 campaign identifier it can be tied directly to the lineage that includes Mini Shai-Hulud and the June Red Hat compromise.

It is difficult to determine whether TeamPCP threat actors are directly behind this campaign. The Mini Shai-Hulud source code has been public since May 12 and nothing in this operation requires insider access to TeamPCP tooling.

June 2026 - Mini Shai-Hulud Spreads the Blight

On June 1, 2026, a new supply chain attack compromised at least 32 packages published under the @redhat-cloud-services npm namespace, with the malicious versions cumulatively averaging approximately 80,000 weekly downloads. The root cause was a compromised Red Hat employee GitHub account, used to push malicious orphan commits to multiple RedHatInsights repositories, bypassing code review entirely.

The attacker triggered GitHub Actions workflows to request OpenID Connect (OIDC) tokens, publishing Trojanized packages with valid SLSA provenance. The certificate was accurate, the packages really were built by that pipeline. It just also happened to have malware injected into it at the time.

The payload is called Miasma. It is named after the description that the malware stamps on attacker-created GitHub repositories, "Miasma: The Spreading Blight." The threat is derived from the Mini Shai-Hulud malware open-sourced by TeamPCP on May 12, with substantially identical tradecraft.

The analyzed sample replaced a normal approximately 200 KB index.js with a 4.29 MB obfuscated payload. This is a 25x size increase that is itself a reliable detection signal.

Stolen credentials include:

  • GitHub tokens, npm tokens and SSH keys
  • AWS, GCP and Azure credentials and cloud identities
  • Kubernetes service-account tokens and HashiCorp Vault secrets
  • CI/CD secrets from GitHub Actions, CircleCI and related platforms

Attribution remains uncertain. The TTPs are consistent with TeamPCP, but the public release of the Mini Shai-Hulud source code means any competent actor can replicate the same attack. What is certain is the trend, which is that one compromised account and one CI pipeline delivered 32 trojanized packages automatically to every developer who ran npm install. Then the registry does the rest.

May 2026 - Mini Shai-Hulud Continues

Two further waves in May 2026 continued the Mini Shai-Hulud campaign:

  • The first introduced a fundamentally new initial-access technique that requires no stolen credential and produced the first malicious npm packages with valid supply chain levels for software artifacts (SLSA) provenance
  • The second demonstrated the largest single-hour package count of any Shai-Hulud wave

Both are attributed to TeamPCP, though the public release of the worm's source code on May 12 has already spawned separate copycat activity, complicating future attribution.

May 11, 2026: Mini Shai-Hulud Strikes Again

On May 11, TeamPCP launched a coordinated supply chain attack across the npm and PyPI ecosystems. The initial vector was TanStack's GitHub Actions CI pipeline. Within six minutes, 84 malicious package artifacts were published across 42 @tanstack/* packages.

The worm's self-propagation mechanism then expanded rapidly. By end of day, we had documented 373 malicious versions across 169 npm packages plus compromised PyPI packages.

The affected scope went well beyond TanStack. The worm's self-propagation spread the compromise to packages across multiple industries and ecosystems:

  • Enterprise infrastructure: @opensearch-project/opensearch (the official OpenSearch JavaScript client; versions 3.5.3–3.8.0) and 57 @uipath/* enterprise automation packages
  • AI tooling: @mistralai/mistralai and its Azure/GCP variants, which is the official Mistral AI TypeScript client
  • Specialized ecosystems: 19 @squawk/* aviation data packages, intercom-client@7.0.4 (customer messaging) and dozens of others across @tallyui, @draftlab, @beproduct, @mesadev and several unscoped packages

@tanstack/react-router alone receives over 12.7 million weekly downloads. We estimate 520 million cumulative downloads were in the affected window. Palo Alto Networks provides XDR and XQL queries to detect this activity.

A New Initial Access: No Stolen Credential Required

Every prior Shai-Hulud wave began with a stolen or phished credential. The TanStack attack needed neither. Instead, three GitHub Actions weaknesses were chained, none of which was sufficient alone.

Step 1: Pwn Request

On May 10, the attacker created a fork of TanStack/router under the account zblgg/configuration, deliberately named to avoid appearing in fork-list searches. A malicious commit was authored under the spoofed identity claude <claude@users.noreply.github.com>, impersonating the Anthropic Claude GitHub App, and prefixed [skip ci] to suppress automated CI on push.

A pull request (PR #7378) against TanStack/router#main then triggered bundle-size.yml — a workflow that used the pull_request_target trigger and checked out the fork's merge ref. This gave the fork's code execution in the base repository's runner context, with full access to its cache scope.

The threat actors used Bun, which is a lightweight JavaScript runtime and package manager alternative to Node.js and npm as shown in Figure 1. The attack used Bun to execute the malicious payload tanstack_runner.js. This in turn attempted to enumerate the system for sensitive credentials, including invoking the GitHub CLI to capture the GitHub authentication token (gh auth token).

Figure 1. Mini Shai-Hulud TanStack execution chain on Windows.
Attribute Detail
Package @bitwarden/cli@2026.4.0
Trigger preinstall lifecycle script
Runtime Bun v1.3.13 (downloaded during install)
C2 server audit.checkmarx[.]cx:443 (94.154.172[.]43)
C2 path /v1/telemetry
Fallback C2 Dynamic, fetched via GitHub Search API dead drop
Exfiltration HTTPS POST (encrypted) + GitHub public repos
Attribution TeamPCP (@pcpcats)
Platform Targeted Files
Linux ~/.ssh/id_*, ~/.ssh/keys, .git/config, ~/.npmrc, .npmrc, .env, ~/.claude/mcp.json, ~/.claude.json, ~/.kiro/settings/mcp.json
macOS ~/.aws/credentials, .git/config, ~/.npmrc, .npmrc, .env, ~/.claude.json, .claude.json, ~/.kiro/settings/mcp.json, .kiro/settings/mcp.json
Windows Credential store paths, config.ini
tcp://85.137.53[.]71 Central C2 node. Hosts beacon, exfil, and proxy management.
hxxp://85.137.53[.]71:8080 Port 8080 HTTP C2 beacon.
hxxp://85.137.53[.]71:8080/api/v1/beacon Contacted by Stage-2 sync.js (73b44b87...).
hxxp://85.137.53[.]71:8080/api/v1/file-result Used for file and credential exfiltration. Has four VT detections.
hxxp://85.137.53[.]71:8081 Port 8081 exfil listener.
hxxp://85.137.53[.]71:8091 Port 8091 proxy control.
fqdn://ipfs[.]io Abused to deliver Stage-2 payloads.
fqdn://rentry[.]co Used to exfiltrate tokens/keys.
fqdn://ethereum-rpc.publicnode[.]com Public node gateway to query C2 smart contracts.
fqdn://relay.damus[.]io Out-of-band decentralized C2 fallback.
fqdn://relay.nostr[.]com Out-of-band decentralized C2 fallback.
fqdn://router.bittorrent[.]com DHT bootstrap node on port 6881.
fqdn://dht.transmissionbt[.]com DHT bootstrap node on port 6881.
0x12c37A86a0Ed0beBe5d1d6a43E42f07860eAc710 Mainnet contract dead-drop.
0x1969ab05d67b67fdcaa26240f738ccb077e1cd84 Secondary mainnet fallback contract.
0x92d4C5413e4F7B258a114964101F9e1C6d64C6Ba Wallet that created and updated contracts.
73b44b8724d31f80859018c988e9b033155c5fd8225205a914eda1a11b78a841 Loader inside @asyncapi/specs@6.11.2. Spawns detached node child.
f7367ce5509f536a406deecdbb577c60e8585cb2ab77058a86bde6188a609cfd Loader inside @asyncapi/specs@6.11.2-alpha.1.
9b2e65db653ca8575c9b10eefb9a80c6006404812c2ec212bf5675e3c690233b @asyncapi/specs@6.11.2. Verified by REF06.
d425e4583cc6185d41e95c45eda00550045a5d1919b9a012236a4520d009dbd7 @asyncapi/specs@6.11.2-alpha.1. Verified by REF06.
bfaeb987faa6de2b5a5eb63b1233d055215b09b0349a9394f2175fd7cdf385e4 @asyncapi/generator@3.3.1. Verified by REF06.
34014776d3d3ff11bc4439b02fd7ac0f02a887eb3a052eeafff236e2f6db8ad1 @asyncapi/generator-helpers@1.1.1. Verified by REF06.
082d733db0687dcd768104972b065d4b58cb1e6043688c6c20fa3702337f36ab @asyncapi/generator-components@0.7.1. Verified by REF06.
22bf76fe317ea6769bd38619bd440e42d119bd6b Inside @asyncapi/generator. Sourced from REF04.
a7e18d96efd3cdb127ef4cdcad9e3ad26c482bf2 Inside @asyncapi/generator-helpers. Sourced from REF04.
9890950adcbc2478e7a080234f053214adbad44e Inside @asyncapi/generator-components. Sourced from REF04.
c70e105e212ff3c1daa04bb2a62507717f296b0b Inside @asyncapi/specs. Sourced from REF04.
c8cb3f6d5b90c46686d2bf531dc1a5786e27edc5 Core Miasma RAT binary. Sourced from REF04.
540028bbd229cc8ce0f531f84e11296870f9b54faa231abb6f5da8557ae3df31 Downloaded from C2. Sourced from C2 relations.
QmQobZSp1wRPrpSEQ56qnyq7ecZh5Bg5k1fnjt4SUwwHb9 Delivers sync.js.
Qmet4fhsAaWMBUxNDfREHwgiyDeSWy4YSYs9wiKUW5jGyf Delivers sync.js specs/react-sdk variant.
ssl://0432fa4ba871877d94081fe83323fa24dfa1491e9de8725cbab7b734de9e9be3b233ef6742fd6264437c9532223d687b05fa540b70af6a516b8539af84d0eeb48e Used to sign/verify C2 instructions.
3eab3ec9304aa26081358330491d3cfeb55cc245 Pushed to asyncapi/generator next branch.
148100 Account used to commit backdoored code.
Indicator Type
audit.checkmarx[.]cx C2 domain
94.154.172[.]43 C2 IP address
checkmarx[.]cx Attacker-controlled domain
91.195.240[.]123 Attacker IP address
Indicator Type
helloworm00/hello-world Dead drop repository
bc544f455d7c06c8a1f3446160a6d9a4a8236b11 Dead drop commit SHA1 hash
helloworm00@proton[.]me Attacker email address
Commit messages matching LongLiveTheResistanceAgainstMachines:* Exfiltration staging
Public repositories named <dune-word>-<dune-word>-<3digits> with description "Checkmarx Configuration Storage" Exfiltration repositories
Indicator Type SHA256 hash
bw_setup.js Bootstrap script f35475829991b303c5efc2ee0f343dd38f8614e8b5e69db683923135f85cf60d
bw1.js Obfuscated payload 18f784b3bc9a0bcdcb1a8d7f51bc5f54323fc40cbd874119354ab609bef6e4cb
package.json Malicious manifest 167ce57ef59a32a6a0ef4137785828077879092d7f83ddbc1755d6e69116e0ad
setup.mjs in infected packages Worm payload
Unexpected bun process execution Runtime indicator
.github/workflows/format-check.yml on transient branches Workflow injection
format-results workflow artifact Secret exfiltration
Indicator Type
@bitwarden/cli@2026.4.0 Malicious package
New preinstall: "node setup.mjs" in package.json Injected hook
Affected Package Versions
@redhat-cloud-services/chrome 2.3.1, 2.3.2
@redhat-cloud-services/compliance-client 4.0.3, 4.0.4, 4.0.6
@redhat-cloud-services/config-manager-client 5.0.4, 5.0.5, 5.0.7
@redhat-cloud-services/entitlements-client 4.0.11, 4.0.12, 4.0.14
@redhat-cloud-services/eslint-config-redhat-cloud-services 3.2.1, 3.2.2, 3.2.4
@redhat-cloud-services/frontend-components 7.7.2, 7.7.3, 7.7.5
@redhat-cloud-services/frontend-components-advisor-components 3.8.2, 3.8.4, 3.8.6
@redhat-cloud-services/frontend-components-config 6.11.3, 6.11.4, 6.11.6
@redhat-cloud-services/frontend-components-config-utilities 4.11.2, 4.11.3, 4.11.5
@redhat-cloud-services/frontend-components-notifications 6.9.2, 6.9.3
@redhat-cloud-services/frontend-components-remediations 4.9.2, 4.9.3, 4.9.5
@redhat-cloud-services/frontend-components-testing 1.2.1, 1.2.2, 1.2.4
@redhat-cloud-services/frontend-components-translations 4.4.1, 4.4.2
@redhat-cloud-services/frontend-components-utilities 7.4.1, 7.4.2, 7.4.4
@redhat-cloud-services/hcc-feo-mcp 0.3.1, 0.3.2, 0.3.4
@redhat-cloud-services/hcc-kessel-mcp 0.3.1, 0.3.2, 0.3.4
@redhat-cloud-services/hcc-pf-mcp 0.6.1, 0.6.2, 0.6.4
@redhat-cloud-services/host-inventory-client 5.0.3, 5.0.4, 5.0.6
@redhat-cloud-services/insights-client 4.0.4, 4.0.5, 4.0.7
@redhat-cloud-services/integrations-client 6.0.4, 6.0.5, 6.0.7
@redhat-cloud-services/javascript-clients-shared 2.0.8, 2.0.9, 2.0.11
@redhat-cloud-services/notifications-client 6.1.4, 6.1.5, 6.1.7
@redhat-cloud-services/patch-client 4.0.4, 4.0.5, 4.0.7
@redhat-cloud-services/quickstarts-client 4.0.11, 4.0.12, 4.0.14
@redhat-cloud-services/rbac-client 9.0.3, 9.0.4, 9.0.6
@redhat-cloud-services/remediations-client 4.0.4, 4.0.5, 4.0.7
@redhat-cloud-services/rule-components 4.7.2, 4.7.3
@redhat-cloud-services/sources-client 3.0.10, 3.0.11, 3.0.13
@redhat-cloud-services/topological-inventory-client 3.0.10, 3.0.11, 3.0.13
@redhat-cloud-services/tsc-transform-imports 1.2.2, 1.2.4, 1.2.6
@redhat-cloud-services/types 3.6.1, 3.6.2, 3.6.4
@redhat-cloud-services/vulnerabilities-client 2.1.8, 2.1.9, 2.1.11

View Original Report

This intelligence was aggregated from Unit 42.

Read on Source