# NPM Supply Chain Attack Techniques Context (May 2025-May 2026)

Purpose: defensive context for reviewing Node.js projects, dependency updates,
package publishing workflows, and CI/CD configuration. This document is
organized by attack technique rather than by individual incident.

Safety note: this file intentionally avoids exploit-ready reproduction steps and
malware source code. It captures observed conditions, behaviors, indicators, and
defensive review heuristics.

## Source Set

Primary and technical sources consulted:

- Unit 42, "Monitoring npm Supply Chain Attacks": https://unit42.paloaltonetworks.com/monitoring-npm-supply-chain-attacks/
- Unit 42, "Shai-Hulud" npm supply chain attack: https://unit42.paloaltonetworks.com/npm-supply-chain-attack/
- Datadog Security Labs, "Shai-Hulud 2.0 npm worm": https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/
- GitHub, npm security roadmap after recent incidents: https://github.blog/security/supply-chain-security/our-plan-for-a-more-secure-npm-supply-chain/
- StepSecurity, Axios compromise analysis: https://www.stepsecurity.io/blog/axios-compromised-on-npm-malicious-versions-drop-remote-access-trojan
- Trend Micro, Axios compromise analysis: https://www.trendmicro.com/en_us/research/26/c/axios-npm-package-compromised.html
- TanStack postmortem: https://tanstack.com/blog/npm-supply-chain-compromise-postmortem
- Socket, TanStack / Mini Shai-Hulud analysis: https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack
- Socket, Beamglea npm-hosted phishing campaign: https://socket.dev/blog/175-malicious-npm-packages-host-phishing-infrastructure
- Snyk, npm ecosystem phishing campaign: https://snyk.io/blog/phishing-campaign-leveraging-the-npm-ecosystem/
- Socket, targeted npm-hosted spearphishing: https://socket.dev/blog/spearphishing-campaign-abuses-npm-registry
- Koi Security, PhantomRaven: https://www.koi.ai/blog/phantomraven-npm-malware-hidden-in-invisible-dependencies
- Sonatype, PhantomRaven: https://www.sonatype.com/blog/phantomraven-npm-malware
- Sonatype, Chalk/debug hijack: https://www.sonatype.com/blog/npm-chalk-and-debug-packages-hit-in-software-supply-chain-attack

## Executive Defensive Model

The last year of npm attacks shows five recurring breakpoints:

1. Publisher trust can be broken even when the upstream GitHub repository looks
   clean.
2. Installation is an execution surface because npm lifecycle scripts run before
   application code is ever imported.
3. CI/CD systems are high-value credential aggregation points, not just build
   workers.
4. Trusted publishing / provenance helps with stolen npm-token attacks, but it
   does not protect against attacker code running inside a legitimate publishing
   workflow.
5. The npm registry and package CDNs can be abused as generic web hosting,
   without any developer installing the package.

When reviewing another Node.js project, treat `package.json`, lockfiles,
package-manager configuration, GitHub Actions workflows, cache usage, registry
configuration, and developer-tool config directories as part of the attack
surface.

## Technique 1: Maintainer Account Takeover and Malicious Publish

### Observed In

- Chalk/debug and related package hijack wave, September 2025.
- Shai-Hulud first wave, September 2025.
- Axios malicious versions, March 31, 2026.
- Related high-impact npm package events where publish rights were abused.

### Preconditions

- Attacker obtains npm account credentials, a reusable npm token, or access to a
  publishing identity.
- The compromised maintainer has publish rights over popular packages or
  packages with valuable downstream consumers.
- Consumers allow fresh dependency resolution from the public npm registry.
- CI or developer machines expose secrets during install or build.

### Attack Shape

- The attacker publishes a new package version from a legitimate maintainer or
  package identity.
- The upstream GitHub repository may have no matching commit, tag, release, or
  `gitHead` metadata.
- The malicious delta can be tiny: a version bump plus one new dependency or one
  lifecycle hook.
- The package may be removed quickly, but a lockfile, artifact cache, private
  mirror, or local `node_modules` can preserve the compromised version.

### Axios Pattern: Phantom Dependency Injection

Axios was not backdoored by changing Axios runtime source. The poisoned versions
added a dependency (`plain-crypto-js@4.2.1`) that was not imported by Axios. Its
purpose was side-effect execution during install through that dependency's
`postinstall` script.

Defensive significance:

- A dependency can be malicious even if application code never imports it.
- A package source diff can look almost clean if the payload lives in a newly
  added dependency.
- Lockfile review is more reliable than source-only review because lockfiles
  expose newly resolved transitive packages.
- The absence of a corresponding upstream git tag or commit is a major registry
  integrity signal.

Review heuristics:

- Flag package versions on npm that lack expected provenance metadata when prior
  releases had it.
- Compare registry metadata across adjacent versions: publisher identity,
  `_npmUser`, `gitHead`, provenance / trusted-publisher metadata, publish time,
  dist-tags, and tarball integrity.
- Diff dependency lists, not only source files.
- Investigate dependencies that are present in manifests but unused by source.
- Treat sudden package author email changes, unusual ProtonMail-style publisher
  changes, or new publisher accounts in the release chain as suspicious.

## Technique 2: Lifecycle Hook Execution

### Observed In

- Shai-Hulud and Shai-Hulud 2.0.
- Mini Shai-Hulud / SAP CAP wave.
- Axios via the `plain-crypto-js` dependency.
- PhantomRaven remote dynamic dependency payloads.
- GitHub-hosted dependency payloads in the TanStack compromise.

### Lifecycle Hooks Used

High-risk hooks:

- `preinstall`
- `install`
- `postinstall`
- `prepare`

Why these matter:

- They run during package installation, before application code is used.
- They run for transitive dependencies.
- `prepare` can run for git-based dependencies.
- They often run in CI/CD with access to secrets, cloud credentials, npm tokens,
  or OIDC permissions.

### Conditions That Made Hooks Dangerous

- CI workflows ran `npm install`, `pnpm install`, `yarn install`, or equivalent
  without script restrictions.
- Developer machines installed packages with normal script execution enabled.
- Package managers resolved fresh versions because ranges or missing lockfiles
  allowed updates.
- Build jobs exposed environment secrets to all steps, including dependency
  installation.
- Install jobs had broad outbound network access.

### Review Heuristics

For each project:

- Inspect all direct dependencies for lifecycle scripts.
- Inspect lockfile-resolved transitive dependencies for lifecycle scripts.
- Flag lifecycle scripts in packages that are normally pure libraries, configs,
  type packages, linters, formatters, UI components, or test helpers.
- Flag lifecycle scripts that invoke shells, PowerShell, Python, curl, wget,
  node one-liners, Bun downloads, archive extraction, base64 decoding, dynamic
  `eval`, or arbitrary network access.
- Flag packages that add lifecycle scripts in a patch/minor release when prior
  adjacent versions did not have them.
- Prefer `npm ci --ignore-scripts` or equivalent in CI unless specific native
  build steps are explicitly required and allowlisted.

## Technique 3: Self-Replicating npm Worms

### Observed In

- Shai-Hulud, September 2025.
- Shai-Hulud 2.0, November 2025.
- April 2026 Shai-Hulud-family activity involving `@bitwarden/cli@2026.4.0`.
- Mini Shai-Hulud SAP CAP wave, April 2026.
- TanStack / Mini Shai-Hulud wave, May 2026.

### Core Worm Pattern

The worm's loop is:

1. Execute during install.
2. Harvest npm, GitHub, cloud, CI/CD, and local developer credentials.
3. Validate whether stolen credentials have publish or repository-write access.
4. Enumerate packages or repositories controlled by the victim.
5. Modify package manifests or tarballs to include the worm.
6. Bump versions and publish or commit the infected artifact.
7. Repeat when downstream consumers install the new version.

### Important Defensive Details

- The worm does not need a central server if it can use GitHub repositories or
  commits as data staging and token discovery locations.
- Some waves exfiltrated to public GitHub repositories created under victim
  accounts.
- Some variants searched public GitHub data for prior stolen tokens or dead-drop
  messages, allowing fallback without attacker-owned infrastructure.
- Later variants used Bun as a runtime dependency to run bundled payloads and
  avoid assumptions about the target's Node.js environment.
- Payloads were often heavily obfuscated and large enough to stand out in
  packages that normally contain small source files.

### Conditions That Enabled Propagation

- Reusable npm tokens existed in `~/.npmrc`, project `.npmrc`, or CI secrets.
- npm tokens had broad publish rights, long lifetimes, or 2FA bypass.
- GitHub PATs had repo, workflow, or organization scope.
- CI runners had access to repository secrets, package-publish permissions, or
  broad environment variables.
- Maintainers used machines where local secrets, publishing credentials, and
  development dependencies coexisted.
- Package publishing workflows could be invoked without human review.

### Review Heuristics

Look for these suspicious package contents:

- New files named like `setup.mjs`, `execution.js`, `setup_bun.js`,
  `bun_environment.js`, `router_init.js`, `router_runtime.js`, or similarly
  generic bootstrap names.
- Large single-line JavaScript files in packages that historically shipped small
  source modules.
- Obfuscation patterns: `_0x...` dispatcher functions, rotated string tables,
  base64/gzip blobs, custom string decoders, heavy control-flow flattening.
- Manifest changes that clear existing scripts and replace them with a lifecycle
  hook.
- Patch version bump with no meaningful source change except install hooks,
  optional dependencies, git dependencies, or bundled payload files.
- Tarballs that contain files absent from the source repository or omitted from
  expected `files` lists.

Look for these suspicious runtime behaviors:

- Reading `.npmrc`, `.env`, `.git-credentials`, `.git/config`, `.ssh`, cloud CLI
  config directories, Kubernetes service account paths, or AI-tool config
  directories.
- Running `gh auth token` or otherwise querying local GitHub CLI credentials.
- Calling npm registry token APIs or package search endpoints during install.
- Creating public GitHub repositories from install-time code.
- Writing GitHub Actions workflows into repositories.
- Detached / daemonized child processes during install.
- Silent failure handling that suppresses all errors.

## Technique 4: CI/CD Identity Plane Attacks

### Observed In

- TanStack May 2026 compromise.
- Shai-Hulud-family GitHub Actions secret harvesting.
- Mini Shai-Hulud waves.

### Why CI/CD Was Targeted

CI runners concentrate:

- Repository tokens.
- GitHub Actions OIDC request tokens and URLs.
- npm publishing privileges.
- Cloud deployment credentials.
- Environment secrets.
- Build caches reused across workflows.
- Access to private source code and generated artifacts.

### TanStack Chain: Trust Boundary Failure

TanStack's postmortem describes a chain where no npm token was stolen and the
publish workflow itself was not directly edited. Instead, attacker-controlled
code crossed workflow trust boundaries:

- A fork PR triggered `pull_request_target` workflows in the base repository
  context.
- The workflow checked out fork-controlled code and ran build logic.
- GitHub Actions cache was poisoned under a key later restored by release jobs.
- A later release workflow with `id-token: write` restored the poisoned cache.
- Attacker code ran in the release workflow runtime.
- The code obtained an OIDC publish identity from the legitimate workflow
  environment and published directly to npm.

Defensive significance:

- Provenance can be valid for a malicious artifact if the attacker executes
  inside the legitimate workflow.
- OIDC trusted publishing removes long-lived npm tokens, but it shifts the
  security boundary to workflow integrity.
- `pull_request_target` is dangerous when it checks out or runs untrusted fork
  code.
- GitHub Actions caches are a cross-run state channel and must be treated as
  mutable supply-chain input.

### Review Heuristics for GitHub Actions

Flag:

- `pull_request_target` workflows that checkout PR head or merge refs from
  forks.
- Any `pull_request_target` workflow that runs package-manager install, tests,
  build, benchmark, lint, formatter, or arbitrary scripts from PR code.
- Floating action refs such as `@main`, `@master`, or unpinned third-party
  actions.
- Broad job-level `permissions`, especially `id-token: write`, `contents: write`,
  `actions: write`, `packages: write`, or `pull-requests: write`.
- `id-token: write` on jobs that do not publish or deploy.
- Cache keys shared between untrusted PR workflows and trusted release workflows.
- Cache restore paths covering package stores, executable directories, build
  outputs, or toolchain folders.
- Release jobs that restore caches before dependency verification.
- Workflows where publish credentials are available before tests/build complete.

Prefer:

- `pull_request` for untrusted code and `pull_request_target` only for metadata
  actions such as labeling or commenting.
- Repository-owner guards before privileged steps.
- Separate cache namespaces for untrusted PRs and trusted main/release runs.
- Minimal per-job permissions with `id-token: write` only on the publish job.
- Publishing from a small final job that receives immutable build artifacts, not
  from a broad test job.
- SHA-pinned actions.
- Egress monitoring in CI and explicit network allowlists.

## Technique 5: Git-Based Dependency Smuggling

### Observed In

- TanStack / Mini Shai-Hulud wave.

### Attack Shape

Malicious package versions added a git-based dependency or optional dependency
pointing to a GitHub commit. The referenced commit could be an orphan/root commit
in a fork network and contain a package with a lifecycle hook such as `prepare`.
When the package manager resolves the git dependency, it runs the hook and
executes the payload.

### Why This Evaded Simple Review

- The malicious payload was not necessarily in the main package's normal source.
- The dependency looked like a GitHub URL under a familiar organization or repo
  network.
- GitHub-hosted package installs have different lifecycle behavior than registry
  packages.
- Optional dependencies may be overlooked during review even though they can
  execute install-time hooks.

### Review Heuristics

Flag:

- Dependencies or optionalDependencies using `github:`, `git+https:`, raw HTTP
  tarballs, or unpinned branches.
- Git dependencies with short refs, branches, tags that can move, or commits not
  reachable from expected repository history.
- Dependencies pointing to forks, renamed forks, orphan commits, or commits with
  no parent history.
- Git dependencies that include `prepare` scripts.
- Optional dependencies introduced in patch releases of widely used packages.

Prefer:

- Registry packages with lockfile integrity.
- Full commit hashes for any unavoidable git dependencies.
- Allowlisting approved git dependency hosts and repositories.
- Blocking install-time lifecycle scripts for git dependencies unless explicitly
  reviewed.

## Technique 6: Remote Dynamic Dependencies

### Observed In

- PhantomRaven campaign, August-October 2025.

### Attack Shape

The visible npm package can look nearly empty or harmless, while `package.json`
declares a dependency fetched from an attacker-controlled HTTP URL rather than
from the npm registry. During install, the package manager fetches the remote
dependency and executes its lifecycle hook.

### Why This Was Effective

- npm UI and many scanners may display zero or benign registry dependencies.
- The malicious code is hosted outside npm and can change over time.
- The attacker can serve different payloads to different requesters.
- Lockfiles and SCA tools may not provide the same guarantees for remote URLs as
  for registry-hosted packages.
- The payload can target CI/CD variables, npm tokens, GitHub/GitLab/Jenkins/
  CircleCI credentials, system details, and network identity.

### Review Heuristics

Flag:

- Any dependency specifier using `http://` or `https://` direct tarball URLs.
- Dependencies pointing to non-registry domains.
- Package names that look AI-hallucinated, brandjacked, or "almost right" but do
  not match known package names.
- Packages with low history, new maintainers, sequential-looking publisher
  accounts, or many similarly named sibling packages.
- Install-time outbound network activity to non-registry hosts.

Prefer:

- Private registry proxy rules that deny external URL dependencies by default.
- Lockfile policies that reject non-registry package sources.
- Build egress restrictions permitting only expected package registries and
  artifact stores.
- Minimum package age policies to avoid newly seeded malicious releases.

## Technique 7: Phishing Infrastructure Hosted Through npm and Package CDNs

### Observed In

- Beamglea campaign, October 2025.
- Separate targeted spearphishing campaign reported December 2025.
- Snyk-observed related/copycat `mad-*` package cluster.

### Attack Shape

These campaigns did not primarily compromise developers through `npm install`.
Instead, attackers published packages so that package CDN services such as
`unpkg.com` would host JavaScript and HTML over trusted HTTPS infrastructure.
Victims received HTML lures or links that loaded scripts from package CDN URLs,
then redirected to credential-harvesting infrastructure.

### Beamglea Pattern

Observed characteristics:

- Randomized package names like `redirect-[a-z0-9]{6}`.
- A small JavaScript redirector file such as `beamglea.js`.
- HTML files themed as purchase orders, project documents, RFQs, or technical
  documents.
- Victim email passed in the URL fragment so the phishing page can prefill it
  without the email appearing in normal server access logs.
- Multiple npm publisher accounts and many packages for redundancy.
- Campaign identifiers embedded in HTML metadata.

### Targeted Spearphishing Pattern

Observed characteristics:

- Packages contained browser-rendered phishing flows rather than just redirect
  scripts.
- The lure impersonated secure document-sharing and Microsoft sign-in workflows.
- Target email addresses were hardcoded into page templates.
- Anti-analysis controls included bot checks, headless browser checks,
  honeypot form fields, interaction gating, disabled right-click or keyboard
  shortcuts, and DOM wiping on suspected automation.
- Some infrastructure overlapped with adversary-in-the-middle phishing patterns,
  creating risk of session-cookie or token theft even when MFA is used.

### Review Heuristics

For Node.js project review:

- Packages containing full HTML lures, Microsoft-looking login screens, document
  viewer UIs, hidden form fields, or DOM overwrite logic are suspicious in normal
  library dependencies.
- Browser bundles in packages should be explainable by the package's purpose.
- Flag `document.write`, full-page DOM replacement, hardcoded email addresses,
  iframe overlays, remote redirects, or anti-devtools logic in packages that are
  not supposed to be web applications.

For enterprise telemetry:

- Monitor package CDN requests from non-development endpoints.
- Alert on CDN paths matching random redirect package patterns.
- Quarantine HTML attachments that load external JavaScript from package CDNs.
- Look for local HTML files that immediately navigate to external identity pages.
- Treat package registries and CDNs as possible phishing infrastructure, not only
  developer tooling.

## Technique 8: Credential and Secret Harvesting

### Commonly Targeted Sources

Local developer machine:

- `~/.npmrc` and project `.npmrc`.
- `.env` files.
- `.git/config`, `.git-credentials`, Git credential helpers.
- GitHub CLI credentials.
- SSH private keys.
- Cloud CLI config and credential files.
- Docker registry config.
- Kubernetes kubeconfig and service account tokens.
- AI coding tool and MCP config directories such as `.claude`, Claude config
  files, and MCP server config files.
- Wallet files in some campaigns.

CI/CD:

- Environment variables.
- GitHub Actions secrets and runner context.
- `GITHUB_TOKEN`, GitHub PATs, and OIDC request variables.
- npm publish tokens or OIDC publish identity.
- Cloud deployment secrets.
- Build artifacts and caches.

Cloud and infrastructure:

- AWS metadata services, including IMDSv2 and ECS task metadata.
- AWS Secrets Manager and SSM Parameter Store.
- GCP metadata and Secret Manager.
- Azure Key Vault.
- HashiCorp Vault, including Kubernetes-internal Vault endpoints.
- Kubernetes service account token paths.

### Review Heuristics

Flag package or script behavior that:

- Reads broad environment variables during install.
- Enumerates home directories or common credential paths.
- Accesses cloud metadata IPs or Kubernetes service-account paths during install.
- Invokes cloud SDKs from lifecycle scripts.
- Calls GitHub, npm, cloud, Vault, or Kubernetes APIs during dependency install.
- Compresses, encrypts, or serializes large local data blobs before network
  transmission.
- Creates repositories, commits files, or uploads artifacts unexpectedly.

## Technique 9: Exfiltration and Dead-Drop Channels

### Observed Channels

- HTTPS POST to attacker-controlled domains.
- Public GitHub repositories created under victim accounts.
- Public GitHub commit messages or search results used as token dead drops or
  fallback C2.
- Session / Oxen messaging network file upload endpoints in Mini Shai-Hulud.
- Package CDN redirect chains for phishing.
- WebSocket fallbacks in PhantomRaven-style payloads.

### Defensive Notes

- Exfiltration may occur to legitimate platforms, not only suspicious domains.
- GitHub API calls from install-time code should be treated as high signal.
- Public repository creation by developer accounts or CI identities during an
  install/build job is abnormal.
- Encrypted payload upload to generic file-hosting, messaging, paste, or CDN
  infrastructure is suspicious when performed by dependency install scripts.

### Review Heuristics

In CI:

- Enforce egress allowlists.
- Log DNS and network connections per job.
- Alert on first-seen domains during dependency install.
- Alert on GitHub API calls that create repositories, write workflows, upload
  artifacts, or query public commits from package install contexts.

In code/package review:

- Flag network clients in lifecycle scripts.
- Flag packages that bundle SDKs for multiple cloud providers without a clear
  functional reason.
- Flag encrypted payload envelopes, embedded public keys, compressed blobs, or
  custom protocol implementations in packages that should not need them.

## Technique 10: Persistence and Anti-Forensics

### Observed Behaviors

- Detached background processes so `npm install` appears to finish normally.
- Replacing malicious package manifests with clean decoys after execution.
- Deleting setup scripts or temporary payload files.
- Writing persistence into developer tooling config directories, including
  `.claude` hooks and `.vscode` tasks.
- Injecting GitHub Actions workflows into repositories.
- Installing or registering self-hosted GitHub runners on compromised machines.
- Using process locks to avoid multiple noisy instances.
- Signal handlers or silent catches to reduce visible errors.
- Locale or sandbox checks to avoid execution in selected environments.
- Headless browser and automation checks in browser-phishing packages.

### Review Heuristics

Flag:

- Install scripts that spawn detached processes.
- `stdio: ignore`, `unref()`, `nohup`, hidden PowerShell windows, background
  shell operators, or process orphaning from lifecycle hooks.
- Lifecycle scripts that delete or rewrite their own files.
- Packages where installed `node_modules/<package>/package.json` differs from
  the lockfile-resolved version or registry tarball.
- Unexpected `.vscode/tasks.json`, `.claude/settings.json`, `.github/workflows`,
  or hidden tool config modifications after dependency install.
- Scripts with broad `try/catch` blocks that suppress all errors.

## Technique 11: Obfuscation and Payload Packaging

### Observed Patterns

- Large single-line JavaScript files.
- JavaScript-obfuscator style `_0x` string-array dispatchers.
- Rotated string tables.
- Base64 + gzip embedded payloads.
- Custom XOR or substitution decoders.
- Dynamic `require()` of built-in modules such as `fs`, `os`, and
  `child_process`.
- Platform-specific command templates decoded at runtime.
- Bundled SDKs for AWS, GCP, Azure, GitHub, tarball manipulation, or crypto.
- Fake package identity copied from legitimate packages.

### Review Heuristics

Flag:

- Obfuscation in packages where minification is not expected.
- Obfuscated lifecycle scripts.
- Dynamic construction of built-in module names.
- Payloads that download a runtime such as Bun during install.
- Files significantly larger than historical package contents.
- Package files that are not referenced by exports, `files`, source maps, or
  repository history.

## Technique 12: Package Naming and Discovery Abuse

### Observed Patterns

- Typosquatting and brandjacking.
- Namespace shadowing or fake scoped packages.
- AI hallucination / slopsquatting: plausible package names that LLMs might
  suggest but that are not real canonical packages.
- Randomized phishing-hosting package names.
- Packages impersonating configs, MCP servers, testing tools, lint plugins,
  browser helpers, SDKs, or internal-looking utilities.

### Review Heuristics

Flag:

- Packages suggested by AI tools without independent verification.
- Names that omit common prefixes from legitimate packages, such as missing
  `eslint-plugin-`, `babel-plugin-`, or organization scopes.
- Newly created packages with names close to high-volume ecosystems.
- Packages with little history, no repository, cloned metadata, or mismatched
  repository links.
- Internal package names that could be resolved from the public registry.

Prefer:

- Scoped internal packages.
- Private registry configuration that reserves internal scopes.
- Explicit allowlists for new dependency introduction.
- Human review for AI-suggested packages.

## Review Checklist for Node.js Projects

### package.json

- Are all dependencies necessary and imported?
- Did any dependency appear only to create install-time side effects?
- Are there direct URL, git, GitHub, or tarball dependencies?
- Are there lifecycle scripts in the project that run install-time commands?
- Are `overrides` / `resolutions` used to pin known-safe versions when needed?
- Is the package manager configured to block or delay very new versions?

### Lockfiles

- Is a lockfile committed and used in CI?
- Do lockfile changes introduce new transitive packages unexpectedly?
- Do resolved URLs point outside approved registries?
- Are integrity hashes present and stable?
- Are packages with lifecycle scripts introduced or updated?
- Are package versions extremely new relative to the PR date?

### CI/CD

- Does CI use `npm ci` or equivalent deterministic install?
- Are install scripts disabled by default in CI?
- Are exceptions for lifecycle scripts documented and allowlisted?
- Are secrets withheld from dependency install jobs?
- Is network egress restricted during install/build?
- Are `pull_request_target` workflows audited?
- Are workflow permissions minimal per job?
- Is `id-token: write` scoped only to publish/deploy jobs?
- Are caches separated between untrusted PRs and trusted releases?
- Are actions pinned to SHAs?
- Are publish steps isolated from test/build steps?

### Publishing

- Is trusted publishing used where possible?
- Are classic npm tokens removed or short-lived?
- Is local publishing protected by phishing-resistant MFA?
- Are package publish events monitored for unexpected publishers, versions,
  dist-tags, or missing provenance?
- Are registry artifacts compared with source repository tags?
- Are release artifacts built from clean, reproducible inputs?

### Developer Machines

- Are npm tokens avoided on developer machines where possible?
- Are cloud credentials separated from dependency installation contexts?
- Are package installs monitored for network egress?
- Are `.claude`, `.vscode`, `.github/workflows`, shell profiles, and IDE tasks
  monitored for unexpected changes after package installation?
- Are compromised-package incident response steps defined before an incident?

## High-Signal Findings for Future LLM Review

Use these as prompts when asking an LLM to review a Node.js project:

- "Identify all install-time code execution paths: project scripts, dependency
  lifecycle hooks, git dependency `prepare` scripts, native builds, and package
  manager hooks."
- "List all package sources that are not the default npm registry."
- "Find dependencies present in package manifests or lockfiles that are not used
  by application source."
- "Compare adjacent dependency versions for new lifecycle scripts, optional
  dependencies, git dependencies, large bundled files, or obfuscated code."
- "Audit GitHub Actions for `pull_request_target`, cache use across trust
  boundaries, broad permissions, floating action refs, and OIDC publishing
  exposure."
- "Identify secrets available during dependency installation and whether they are
  needed at that stage."
- "Find package install steps that have unrestricted outbound network access."
- "Check for persistence surfaces modified by dependencies: `.github/workflows`,
  `.vscode/tasks.json`, `.claude/settings.json`, shell profiles, and package
  manager config files."
- "Check whether npm package versions in lockfiles were published very recently
  and whether project policy gates newly published versions."

## Incident-Specific Technical Anchors

### Shai-Hulud / Shai-Hulud 2.0

- Major transition from one-off malicious package publication to automated
  worm-like package infection.
- Used lifecycle hooks to trigger payloads.
- Harvested npm tokens, GitHub credentials, cloud secrets, environment variables,
  and local config files.
- Republished packages controlled by the victim.
- Exfiltrated secrets through GitHub repositories in later waves.
- Shai-Hulud 2.0 used files such as `setup_bun.js` and `bun_environment.js`,
  installed/used Bun, and introduced aggressive fallback sabotage behavior when
  exfiltration or propagation failed.
- Defensive anchors: package manifests with unexpected preinstall hooks, large
  Bun payload files, public repos with campaign descriptions, self-hosted runner
  setup indicators, and npm publish anomalies.

### `@bitwarden/cli@2026.4.0` / TeamPCP-Linked April 2026 Activity

- Used preinstall execution and a secondary binary-name trigger path.
- Downloaded Bun and ran a large obfuscated payload.
- Targeted cloud providers, CI/CD systems, developer workstations, GitHub tokens,
  npm tokens, and secret stores.
- Used GitHub public repos and commit-search patterns as fallback or dead-drop
  infrastructure.
- Backdoored packages publishable by the victim.
- Defensive anchors: `bw_setup.js`, `bw1.js`, `setup.mjs`, unexpected Bun
  execution, C2 domain `audit.checkmarx[.]cx`, public repo dead-drop patterns,
  and unexpected workflow injection.

### SAP CAP Mini Shai-Hulud Wave

- Affected CAP ecosystem packages such as `@cap-js/sqlite`, `@cap-js/postgres`,
  `@cap-js/db-service`, and `mbt`.
- Added `setup.mjs` and `execution.js`.
- Used a `preinstall` hook to run the bootstrapper.
- Targeted enterprise CI/CD with SAP/cloud deployment credentials.
- Defensive anchors: new lifecycle hook, Bun download, large obfuscated
  `execution.js`, credential harvest attempts across GitHub, npm, cloud, Vault,
  Kubernetes, and developer-tool config.

### TanStack / Mini Shai-Hulud May 2026

- 84 malicious versions across 42 packages were published in two batches.
- Compromise chain combined `pull_request_target`, cache poisoning, and OIDC
  token extraction inside a legitimate release workflow.
- Malicious packages included `router_init.js` and an optional dependency to a
  GitHub-hosted setup package.
- Payload harvested CI/cloud/developer credentials and attempted propagation.
- Exfiltration used Session network infrastructure in reporting.
- Defensive anchors: `@tanstack/setup` optional dependency pointing to an
  unexpected GitHub commit, `router_init.js`, OIDC publish from unexpected step,
  poisoned cache keys, `pull_request_target` workflows running fork code, and
  publish events during failed release runs.

### Axios March 2026

- Malicious versions: `axios@1.14.1` and `axios@0.30.4`.
- Added phantom dependency `plain-crypto-js@4.2.1`.
- `plain-crypto-js` used `postinstall` to run a cross-platform dropper.
- The Axios GitHub repository had no corresponding clean source release for the
  malicious npm versions.
- The malicious dependency self-cleaned by replacing evidence in its installed
  package manifest.
- Defensive anchors: lockfile reference to `plain-crypto-js`, missing OIDC /
  `gitHead` metadata compared with adjacent Axios releases, C2 `sfrclak[.]com`,
  and platform artifacts such as suspicious temp payloads.

### Chalk / Debug Hijack

- Popular packages such as `chalk`, `debug`, ANSI/color utility packages, and
  related packages were affected by maintainer-account compromise.
- The blast radius was high because these packages are deeply transitive in many
  dependency trees.
- Payload intent included cryptocurrency theft and potentially broader secret
  theft risk.
- Defensive anchors: SBOM and lockfile inventory against known affected package
  versions, rapid credential rotation where affected packages executed, and
  stricter publisher authentication.

### PhantomRaven

- Used remote dynamic dependencies to hide malicious code outside npm-hosted
  package source.
- Visible npm packages could look harmless and show zero normal dependencies.
- Payloads targeted npm tokens, source-control credentials, CI/CD variables, and
  system fingerprinting.
- Attackers used plausible package names, brandjacking, and AI-hallucination
  style names.
- Defensive anchors: direct HTTP(S) dependency specifiers, non-registry resolved
  URLs, install-time outbound network requests, lifecycle scripts in remote
  dependencies, and packages with low trust/history.

### Beamglea and npm-Hosted Phishing

- Used npm packages and `unpkg.com` CDN as web hosting for phishing redirectors.
- Did not require `npm install` by a developer.
- Used randomized `redirect-*` packages, `beamglea.js`, HTML business-document
  lures, victim email prefill via URL fragments, and multiple phishing domains.
- Defensive anchors: package CDN requests from user endpoints, HTML attachments
  loading `unpkg.com` scripts, `redirect-*` package paths, and phishing domains.

### Targeted npm-Hosted Spearphishing

- Used 27 packages across multiple aliases for a five-month operation.
- Delivered embedded browser phishing flows impersonating secure document sharing
  and Microsoft sign-in.
- Included anti-analysis controls such as bot checks, honeypots, and interaction
  gates.
- Some observed infrastructure aligned with adversary-in-the-middle phishing
  patterns that can defeat non-phishing-resistant MFA.
- Defensive anchors: packages containing full phishing UI bundles, hardcoded
  target emails, DOM replacement, anti-devtools logic, and suspicious redirector
  domains.

## Defensive Controls Mapped to Techniques

### Dependency Intake

- Require lockfiles.
- Use `npm ci` / deterministic installs.
- Enforce package minimum age / cooldown windows.
- Reject direct URL dependencies by default.
- Review git dependencies manually.
- Block known malicious packages through a registry proxy or package firewall.
- Require source and registry artifact comparison for critical dependencies.

### Script Execution

- Disable lifecycle scripts in CI by default.
- Allowlist packages that genuinely require install scripts.
- Run dependency install in a stage without secrets.
- Prefer ephemeral build environments.
- Monitor process creation during install.

### Identity and Publishing

- Use trusted publishing where available.
- Remove long-lived classic npm tokens.
- Use granular, short-lived tokens only where unavoidable.
- Enforce phishing-resistant MFA for npm and GitHub.
- Scope GitHub Actions `permissions` per job.
- Keep OIDC permissions isolated to publish jobs.
- Monitor publishes for provenance anomalies.

### CI/CD Hardening

- Avoid `pull_request_target` for untrusted code execution.
- Separate caches by trust boundary.
- Pin third-party actions by SHA.
- Restrict network egress.
- Rotate secrets after any suspicious install-time execution.
- Log network and process behavior per job.

### Incident Response Triggers

Treat a host or runner as potentially compromised when:

- A malicious package version was installed, even briefly.
- A suspicious lifecycle hook ran.
- A package self-deleted or rewrote its manifest.
- CI made unexpected outbound connections during dependency install.
- Public GitHub repos or commits were created unexpectedly.
- New workflows, `.vscode` tasks, `.claude` hooks, or package publish events
  appear without a legitimate change.

Recommended response:

- Isolate persistent runners and developer machines.
- Rebuild affected hosts from known-good images.
- Rotate npm, GitHub, cloud, SSH, CI/CD, registry, package, and deployment
  credentials available to the affected environment.
- Audit package publishes and repository commits made during and after the
  exposure window.
- Purge poisoned caches and artifacts.
- Pin or override dependencies to known-good versions.

