FIELD REPORT // 2026-04-29
The NPM supply-chain canaries we keep replaying.
Field-pattern observations on namespace squatting, maintainer takeover anomalies, and the supply-chain signals that lead a Labs audit.
The supply chain is the surface
When a Labs engagement scopes "external attack surface," NPM is part of it on almost every audit. The reason is not that NPM is uniquely insecure. The reason is that NPM is the surface most consumers cannot see — the dependency graph that gets pulled, executed, and trusted in CI runners with credentials, in developer laptops with SSH keys, and in production containers behind authentication that the dependency package never had to bypass because it was already inside.
The point of this report is to describe the recurring signals that lead a Labs audit to spend time on a specific NPM region, with no client names attached.
Five canaries we watch
1. Maintainer-of-one with infrequent commits and a recent ownership transfer. Mathematically this is the supply chain's most reliable warning sign in 2026. A package with one maintainer, irregular commit cadence, and a recent ownership handover is in the top decile for hostile takeover risk. The takeover itself is not visible from outside; the consequence — a 1.x.y+1 minor that adds a postinstall script the previous version did not have — is.
2. Sudden bump in install scripts. A package that has shipped for two years without a postinstall, preinstall, or custom prepare script, then publishes a minor that adds one, deserves immediate attention. The script may be legitimate. It is also the most common single vector for credential harvesting at scale in our observations.
3. Namespace adjacency to brand keywords. Squat packages mimicking common internal scopes — @acme-internal, @acme-tools, @acme-utils — show up in our scans around any major fundraising event for the named company. Attackers correlate fundraising news with hiring news and target the new hires' laptops with internal-namespace squats. The pattern is mechanical; the mitigation is to register your own namespace defensively.
4. Typosquat density on common utilities. The packages that benefit most from typosquatting are not glamorous. They are the utility libraries every project depends on: argument parsers, async helpers, format converters. A typosquat density audit on a client's package-lock.json finds candidates within minutes. Whether they get pulled is a function of an engineer's tired Tuesday afternoon.
5. Maintainer email rotated to a freshly-registered domain. This is rarer than the others but more damning. When the email contact on a maintainer record changes to a domain registered in the last 60 days, the probability that the contact is part of a hostile transfer is materially higher.
What the data does not show
The above signals are useful. They are not sufficient.
The single most-damaging supply-chain compromises of the last 18 months were not catchable from outside-in scanning of NPM metadata. They were catchable by behavioural observation of the package's execution inside CI — and most teams do not have that observation. The honest answer to "is my supply chain currently clean" is "the public signals look acceptable, and you should not interpret that as evidence of absence."
The most useful compensating control we have observed is npm install --ignore-scripts as the default in CI, with explicit allowlists for the packages that legitimately need install scripts. This is unpopular because it breaks setup for some legitimate packages. It is the highest-leverage single change a team can make to its NPM exposure.
What Labs does during an engagement
The NPM portion of a Board-Ready audit involves three passes:
- A static read of the published
package.jsonandpackage-lock.jsonfor the client's own scopes, looking for the canaries above. - A historical read of the maintainer records associated with each direct dependency, for ownership-transfer events in the engagement window.
- A behavioural read of the install scripts in the resolved dependency tree, against a reference of "what install scripts the same package shipped six months ago."
The output is a finding only if at least two of the three passes flag the same package or the same maintainer. A single canary does not produce a Board-Ready finding. The cost of a false positive in a Board-Ready deliverable is high enough that the bar must be.
What the buyer should expect to NOT see
A Labs NPM audit deliverable does not contain:
- A list of named third-party maintainers with risk scores. The maintainer attribution stays inside the engagement. We will not publish a public score for a developer.
- A regenerated
package-lock.jsonwith our recommendations as a diff. The audit produces a runbook; the engineering team applies it. Mixing audit and remediation produces a conflict of interest we refuse. - Detection-tool branded language. The audit is methodology output, not a vendor demo. If the client wants a specific scanner's output, the client buys the scanner.
How to act on this without an engagement
If you are reading this and are not (yet) a Labs client, three actions in declining order of leverage:
- Default your CI to
--ignore-scripts. Allowlist explicitly. - Register your internal namespace in every public package registry you ship to, even if you do not currently publish to it. The registration is free; the squat opportunity is closed.
- Pin every dependency at the lockfile level. Trust the lock; renew it deliberately, not opportunistically.
If you want a 3-day diagnostic that does these three for you and finds the next ten — Discovery Brief is the entry tier on /services.
AUTHOR
BleedWatch Labs founder
Founder-led research from the same auditor of record who signs Labs engagements. Specific client references and prior research identifiers are shared under reciprocal NDA when relevant.