What Shai-Hulud Teaches Cybersecurity Candidates About Trust in Software
Security Incident Analysis10 min read

What Shai-Hulud Teaches Cybersecurity Candidates About Trust in Software

Software supply-chain attacks do not break trust. They borrow it.

Shai-Hulud ran three waves from September 2025 through May 2026. npm was the vehicle; the pattern applies to any ecosystem where package installation runs scripts with environment access.

  • September 2025: phish a maintainer account, inject an installation hook, harvest credentials, republish across every package the account owns.
  • November 2025 (2.0): scale to 25,000+ attacker-created repositories, persist as self-hosted CI runners, wipe the home directory if exfiltration fails.
  • May 2026 "Mini" wave: clone the technique against two ecosystems, 639 malicious versions across 323 packages in 22 minutes: 400,000 secrets exfiltrated, 60% of stolen publish tokens still valid a week later.

The primary control owner is AppSec and DevSecOps. SOC visibility is limited: the attack produces no detectable anomaly until exfiltration begins.

Anatomy of the Attack

  1. Initial access: Wave 1 phished a maintainer account. Waves 2 and 3 exploited a misconfigured CI workflow trigger granting write-level tokens to untrusted fork contributions, bypassing the need to steal credentials directly.
  2. Execution: A malicious installation hook ran silently during a routine dependency install, invoking a heavily obfuscated 10+ MB script via a secondary runtime bundled in the payload.
  3. Credential harvesting: Broad sweep across package manager config files, environment variables, source control tokens, cloud metadata endpoints, container orchestration service accounts, secrets manager tokens, SSH keys, database connection strings. Later waves added password manager vaults.
  4. Self-propagation: Stolen publish token used to enumerate every package the victim account maintained, inject the payload, increment the version, republish. One account, full surface.
  5. Exfiltration: Primary: encrypted POST to attacker infrastructure. Fallback: secrets committed to attacker-created public repositories under victim accounts. Wave 3 added a decentralized messaging network resistant to takedown.
  6. Persistence: Wave 2 registered machines as self-hosted CI runners. Wave 3 installed a daemon polling token validity every 60 seconds, wiping the home directory on revocation.

Detection gap: The full chain runs inside a trusted package manager invoking a legitimate runtime. No exploit, no unusual binary. In most CI environments: broad execution permissions, no behavioral baseline, logs not forwarded to SIEM. First available signal is outbound traffic to an unknown host or unexpected repository creation, both occurring after credential theft is complete.

MITRE ATT&CK Techniques

Technique IDNamePhase
T1195.001Compromise Software DependenciesInitial Access
T1566.002Phishing: Spearphishing LinkInitial Access
T1059.004Command and Scripting: Unix ShellExecution
T1543.002Create or Modify System ProcessPersistence
T1552.001Unsecured Credentials: Credentials in FilesCredential Access
T1528Steal Application Access TokenCredential Access
T1567.001Exfiltration to Code RepositoryExfiltration
T1485Data DestructionImpact

What a Security Professional Would Do

AppSec / DevSecOps (primary owner)

Three controls, in order of impact:

Disable installation scripts by default in CI. Most pipelines do not need lifecycle hooks. Disabling them eliminates the execution vector regardless of whether a package is malicious. Exceptions should be explicit and reviewed, not inherited from an unchanged default.

Scope publish credentials to the minimum surface. A credential covering one package limits the blast radius to one incident. A credential covering an entire maintainer account or CI service account turns one compromised dependency into a propagation engine across everything the account touches.

Route all package traffic through a private proxy with quarantine. Direct registry access from CI runners and developer machines removes the only choke point where policy can be applied before consumption. A proxy adds two things: the ability to block a confirmed malicious version immediately without touching downstream lockfiles, and a quarantine window for new versions. Shai-Hulud's May wave published 639 malicious versions in 22 minutes; most were flagged within hours. A 48-hour quarantine would have stopped consumption before any pipeline ran the payload. Proxy download logs (which version, which runner, what time) are also the data that makes IR executable rather than guesswork.

SOC / Blue Team

No useful signal exists until exfiltration starts. In environments with centralized build runner logs, look for:

  • Outbound network connections spawned by the package manager during installation steps
  • Credential-access patterns immediately after a dependency install: config file reads, environment variable enumeration, cloud metadata API calls
  • Repository creation under CI service accounts or developer accounts outside normal pipeline hours, with encoded content in committed files
  • Outbound connections to domains registered within the past 30 days from build infrastructure

Without CI log centralization, this attack is invisible until after the damage is done. That gap is worth surfacing explicitly to stakeholders.

IR

Sequence matters. The worm republishes under victim accounts, so revoking credentials before knowing which versions ran destroys forensic evidence and can break downstream consumers.

  1. Scan all lockfiles for affected package versions before touching credentials.
  2. Identify which runners or machines executed the malicious install and which secrets were in scope.
  3. Rotate in propagation order: registry publish tokens first, then source control tokens, then cloud credentials, then SSH keys.
  4. Audit for attacker-created artifacts: repositories with anomalous creation times, injected CI workflow files, newly registered service accounts.
  5. Check for persistence mechanisms before rotating credentials: some variants trigger destructive payloads on token revocation.
  6. Coordinate with the registry to remove malicious versions. Deprecation is not enough; deprecated versions remain installable.

ThreatIntel

Static IOCs for supply-chain campaigns decay fast. When source code is released, as it was after the May 2026 wave, copycat variants appear within days on independent infrastructure. By the time indicators are published, the next wave is already running elsewhere.

Behavioral signatures survive rotation:

  • Installation hooks invoking a secondary runtime not declared in the package manifest
  • Broad credential enumeration immediately after a dependency install: config reads, environment sweeps, cloud metadata calls, secret store queries in rapid sequence
  • Outbound connections from build runners to recently registered domains
  • Repository creation under developer or service accounts with encoded content in committed files

Collecting IOCs remains useful. It just cannot be the only output. The question to answer for any new supply-chain campaign is: what does the propagation mechanism look like, and what trace does it leave in pipeline logs?

Key Takeaways

  • When a pipeline installs external packages, treat it as code execution: hooks run with full access to environment, filesystem, and network. Disabling lifecycle scripts by default is not hardening; it is the correct baseline.
  • When a publish credential is in scope on a CI runner, the blast radius is the entire account, not the package being built: worms enumerate and republish across every package the credential can reach.
  • When investigating a suspected compromise, identify which versions ran before revoking credentials: premature rotation destroys forensic evidence and can trigger destructive fallback payloads.
  • When a malicious version is confirmed, the proxy is the first containment lever: blocking at the proxy stops consumption across all teams without requiring lockfile changes.

One credential, too broad a scope, in an environment where installation was treated as safe by default. That is the full story across all three waves. None of the controls that would have broken the chain are new. Most are defaults that were never deliberately set.