OrbitalReg Sign in →

Supply-chain case study · retrospective

node-ipc · March 2022

When the maintainer is the attacker.

March 2022. The maintainer of node-ipc — a JavaScript IPC library with roughly a million weekly downloads — pushes a release that deliberately overwrites files on user machines whose IP geolocates to Russia or Belarus. Not a compromise. Not a breach. The trusted person you depended on decided to weaponise your dependency tree against people they disagreed with.

What happened

A "patch release" that wasn't.

  1. 01. Quiet patch versions. On 8 March 2022 the maintainer publishes node-ipc 10.1.1 and 10.1.2. SemVer says patch versions are bug-fixes. Most teams have caret-range deps (^10.1.0) that pull patches automatically.
  2. 02. Geolocation-gated wipe. The new code, hidden in a dependency called peacenotwar that node-ipc started requiring, queries an IP geolocation service. If the machine's external IP geolocates to Russia or Belarus, the code recursively overwrites files in the user's home directory with a heart emoji.
  3. 03. Massive transitive blast radius. node-ipc is depended on by Vue.js CLI's official scaffolding — anyone running vue create on a vulnerable network would have shipped the wipe to their machine. The transitive footprint reached tens of thousands of organisations.
  4. 04. Detection within hours, but not by a scanner. Security researchers spotted the geolocation-gated wipe inside the day. npm pulled the affected versions, GHSA filed, CVE-2022-23812 issued. CVSS 9.8 — Critical — for a piece of "protestware" the maintainer publicly defended on Twitter.
The uncomfortable truth. This was not a maintainer who got phished. This was not a maintainer whose npm credentials leaked. This was the long-time maintainer of node-ipc, in good standing, publishing the malicious release with their own credentials, fully intending to do what they did. Every implicit trust model that depends on "the maintainer is a good actor" fails in this scenario. There is nothing wrong with the process — only the person.

The structural gap

"Use trusted dependencies" is not a defense.

The advice you read in every supply-chain hardening guide is "audit your dependencies and prefer well-maintained, established packages." It is good advice. It does not address node-ipc, because node-ipc was a well-maintained, established package. Years of history, active maintainer, responsive to issues. The very profile the heuristic tells you to favour.

The defense that actually works against this threat model is the same defense that works against compromised-maintainer attacks (Shai-Hulud) and accidental high-severity bugs (Log4Shell): the registry edge has to be willing to stop serving an artifact even when the artifact came from the same maintainer who served the trusted version yesterday.

That requires two posture changes: (a) don't auto-merge upstream patch versions into your environment until the CVE feed has had time to catch up, and (b) wire the pull-gate so critical CVEs become 403s immediately on publication of the GHSA.

The OrbitalReg defense pattern

Trust the publish chain, verify each release.

01

Pull-gate on critical

Same mechanism that catches Shai-Hulud: once GHSA-d4xx-95fq-r2fp lands in the OSV feed, every pull of node-ipc 10.1.1 or 10.1.2 through your OrbitalReg gets a 403 instead of the tarball. The maintainer's pre-existing trust doesn't bypass the gate; each version is gated, not each maintainer.

02

Patch-version quarantine

Optional per-repo policy: hold any new upstream patch version in quarantine for N hours before serving it to consumers. Buys time for the OSV feed to catch up. Trade-off: small latency for new fixes; large reduction in "we got hit by a bad release in the first hour after upstream pushed it."

03

Behavioural diff

Roadmap item, not shipped today: per-package fingerprint (network calls, filesystem writes, child-process spawns) tracked across versions. A node-ipc 10.1.2 that suddenly adds a geolocation API call and recursive file writes is flagged for human review before serving.

What this composes to. Layer 1 closes the loop within hours of disclosure — same window as Shai-Hulud, fine for most organisations. Layer 2 trades a small new-version-latency for protection against the under-the-radar first-publish window; recommended for high-sensitivity repos. Layer 3 is on our roadmap and aimed at the protestware-specific signal of "this release does something this package has never done before."

Config sketch

Pull-gate + patch quarantine.

Both layers on. The 24-hour quarantine is calibrated against average OSV-feed lag for npm; tune up or down to your risk appetite.

# Mirror npmjs with CVE-gate AND new-patch quarantine.

orbital repo create npm-prod \
  --format=npm --kind=remote \
  --upstream=https://registry.npmjs.org \
  --scanner=trivy,osv \
  --pull-gate=block-on-cve-critical \
  --patch-quarantine=24h

For your records

node-ipc timeline.

2022-03-08
node-ipc 10.1.1 and 10.1.2 published to npm. Both versions depend on a new package, peacenotwar, also published by the same maintainer.
2022-03-15
Snyk security researchers publicly disclose the geolocation-gated wipe code. npm removes the offending versions; GHSA-d4xx-95fq-r2fp and CVE-2022-23812 are filed. At this point every registry running verify-on-pull on critical CVEs starts blocking 10.1.1 / 10.1.2 automatically.
2022-03-15+
The maintainer publicly defends the action on Twitter, framing the wipe as legitimate protest against the invasion of Ukraine. Community discussion turns to whether OSS social contracts allow this; legal commentators warn that "protest" does not move the CFAA / EU equivalent needle. Subsequent node-ipc releases revert the wipe but retain a peacenotwar dependency that prints a console message — itself enough to break some CI pipelines.

Honest caveats

What this does not claim.

First-wave exposure still exists. Between the publish of 10.1.1 on 8 March and the GHSA on 15 March, OrbitalReg's CVE-gate has nothing to act on. Teams with patch-quarantine enabled would have been protected during this window; teams without would have been exposed. That's a real seven-day gap.

We cannot evaluate maintainer intent. No registry can tell, at publish time, whether a release is good-faith or hostile. We can only catch it after the community has identified it as hostile and filed the advisory. The patch-quarantine knob is the only structural defense against the "first hours after publish" window.

Behavioural diff is roadmap. We don't yet ship runtime behavioural fingerprints. When we do, expect a high false-positive rate at first — legitimate version changes do add new network calls and new filesystem patterns. The signal is only useful once the baseline-noise floor is calibrated per-package.

This is not legal advice. The node-ipc incident raised genuinely hard questions about OSS social contracts, jurisdiction, and Computer Fraud and Abuse Act exposure for "protestware" maintainers. Those are legal questions for your counsel. The technical question — "can we stop the bad version from reaching our developers' machines once it's identified" — is the only one OrbitalReg answers.

Primary sources

Want a registry that's willing to say no to a maintainer?

Talk to us about patch-version quarantine.

Rico, the founder, walks you through how patch-quarantine windows interact with your CI cadence, what the latency cost really looks like in practice, and where in your org tree it makes sense to dial it tighter.