# Compromised npm Packages Reaching the Browser

Packages you legitimately depend on, compromised upstream, arriving in your bundle through the same pipeline everything else uses.

Provenance: Corroborated by external research.
Published: 2026-03-31. Updated: 2026-08-24.

Everything else we track gets onto a page by breaking in. This gets on by being invited: a package
you chose, installed on purpose, built into your bundle by the pipeline that builds everything else.

The hosts here are exfiltration endpoints from separate incidents where a widely used npm package was
taken over at the source and published with code added. One targeted wallet keys. Another was a
compromise of one of the most downloaded HTTP clients in the ecosystem. A third was a template
library whose earlier compromise had been cleaned up, then compromised again.

## The account, not the code

These takeovers are rarely clever attacks on source code. They are attacks on the ability to publish:
a phished maintainer, a stolen token, a stale credential in a CI configuration.

That matters for where you go looking. The public repository frequently still shows exactly the code
you would expect, because the tampering happened between the source and the registry. Reading the
GitHub page for a package tells you nothing about what npm actually served you.

## What a lockfile does and does not do

A lockfile is a genuinely good control and it solves the adjacent problem. It stops your dependencies
moving without you noticing, which rules out the version of this attack where a bad release arrives
through an automatic upgrade.

It does nothing once the version you deliberately install is already compromised. Somebody bumps a
dependency, CI is green, review passes, the lockfile records the choice — and then pins you to it
with excellent reliability. Reproducibility is not integrity. A lockfile guarantees everyone builds
the same thing, not that the thing is safe.

Subresource Integrity has a matching gap. It protects a script fetched from a URL against that file
changing underneath the hash, which is exactly right for a CDN-hosted library. It cannot help with a
package you installed and bundled, because the hash is computed over what you built, and what you
built already contains the malicious code.

## The one thing the attacker cannot avoid

Stolen data has to leave. Whatever the entry route, at some point code in the browser opens a
connection to somewhere the attacker controls, and that destination has no business being in your
policy.

That is why this is visible from the browser even when it is invisible everywhere else. Your build
is reproducible, your dependencies are pinned, your repository is clean, and the page still tries to
talk to a host nobody authorised.

## What to look for

Watch for a connection to an unfamiliar host from a page whose own files did not change, and treat a
new destination appearing shortly after a dependency bump as the two facts belonging together until
shown otherwise.

The practical control is the same one that works against everything else here: a `connect-src` that
names the origins your pages are allowed to reach, derived from what they legitimately need. It does
not care how the code got onto the page, which is what makes it useful against a route that arrived
through your own pipeline with a review and a green build behind it.

## Indicators

- cfww.shop
- jiathis.com
- l1ewsu3yjkqeroy.xyz
- sfrclak.com
- sol-rpc.xyz
- utaq.cfww.shop
- v3.jiathis.com

## Questions

### How does a package get compromised?

Usually the publishing account rather than the code. Someone phishes a maintainer's credentials or steals a publish token and pushes a release under their name. The repository often still shows clean code, because the tampering happened between the source and the registry.

### Doesn't a lockfile protect me?

It stops you upgrading by accident, which is worth having. It does nothing once you deliberately take a version that is already malicious, and it will then pin you to that version very reliably.

### What does Subresource Integrity actually cover?

A script loaded from a URL with a hash attached. If the file changes, the browser refuses it. That covers a CDN serving something new under an existing URL; it does not cover a version you installed and bundled yourself, because the hash is taken from what you built.

### How would I notice this in my reports?

By the connection, not the code. The exfiltration has to reach somewhere, and that destination is not in your policy, so it is reported as a violation on the page the bundle runs on.
