On May 14, 2026, three malicious versions of node-ipc appeared on npm: 9.1.6, 9.2.3, and 12.0.1. If the package name sounds familiar, it should. This is the same library behind the 2022 protestware incident, and it still sits in the dependency trees of a very large number of projects.

The compromise vector was not a stolen npm password. The attacker re-registered an expired domain belonging to a maintainer, atlantis-software.net, set up mail on it, and used the inbox to take over the account. CSO Online covered the domain takeover; Datadog Security Labs published the deep payload analysis.

The payload

The malicious code lives in the CommonJS bundle and triggers on require("node-ipc"). From there, per the public analyses:

  • Forks a detached child process so the work survives the parent
  • Fingerprints the host: platform, architecture, hostname, uname -a
  • Harvests credentials against more than 100 file patterns: AWS, Azure, GCP, Kubernetes, Docker, SSH keys, npm tokens, GitHub and GitLab credentials, Terraform state, .env files, shell histories, macOS Keychain
  • Packs everything into a gzip tarball in a temp directory
  • Exfiltrates through DNS TXT queries to a decoded endpoint, not HTTP

The DNS TXT channel is the detail worth remembering. Most egress monitoring watches HTTP. DNS queries leave almost everywhere, and a credential archive chunked into TXT lookups does not look like a data transfer to most network tooling.

What we shipped, and when

Two things went into Aguara within a day of the advisory.

First, the known-compromised versions went into the advisory data, so aguara check . flags any of the three versions in a lockfile or an installed node_modules tree, offline:

$ aguara check .

CRITICAL  pnpm-lock.yaml
  known-compromised-package: node-ipc@9.2.3

Second, and more interesting: a behavioral rule. IOC lists only catch the versions you already know about. The May payload has a structure worth detecting on its own: code that reads credential files, builds an archive, and then talks to DNS with constructed query names. JS_DNS_TXT_EXFIL_001 fires on that chain in JavaScript package code: a DNS TXT resolution bound to constructed hostnames, paired with the credential-read or archive stage. The chain requirement matters, because plenty of legitimate code resolves TXT records; the rule needs the surrounding behavior before it speaks up.

The takeaway that outlives the incident

An expired maintainer domain is all it took. No amount of 2FA on your own account protects you from a dependency whose maintainer's domain lapsed. The practical defenses are on the consumer side: check lockfiles against known-bad versions before install, prefer a release-age window so day-zero versions do not flow straight into CI, and treat install-time execution as the attack surface it is.

Further reading: Socket's advisory, Snyk's writeup, and The Hacker News coverage.

Check your lockfiles against this incident

aguara check . runs offline against embedded advisory data, before any install script executes.