Secure npm Registry Tested Against axios and Shai-Hulud

php2shell patches (CVE-2026-109618 and CVE-2026-109619) for EOL PHP are out now. With sales replies slower than usual due to high demand, the fastest route to patched packages is to buy ELS for Runtimes online (opens in new tab). Read the patch FAQ

Go straight to an AI summary of this blog post instead

  • Summarize this post with Perplexity
  • Summarize this post with Gemini

Key Takeaways

  • Third Coming and Miasma abused trusted CI publishing paths rather than stolen long-lived maintainer tokens.
  • A registry that screens release content can catch those publishes even when the attestation checks out.
  • For packages SecureChain covers, rebuilding from vetted source keeps a stolen-credential republish out of your build.
  • A quarantine window only helps if the malicious version gets pulled before the delay expires.

npm compromises show up often enough that the same follow-up question comes around every time. Would a secure npm registry have actually stopped this one? The answer changes with the mechanism, which is the part most vendor claims skip.

This piece checks SecureChain’s actual controls against four 2026 incidents: axios, jscrambler, Shai-Hulud’s “Third Coming,” and Miasma. Each one gets mapped to the mechanism that catches it, along with how much confidence that mapping earns.

Two Root Causes, Not Four Separate Incidents

Line the four campaigns up by mechanism and they split into two groups, not four.

Both axios and jscrambler came down to a stolen publishing credential used directly against the registry, with the project’s own CI process bypassed entirely. In the axios case, an attacker reached the lead maintainer’s machine through a targeted social engineering campaign and then published two poisoned versions by hand on March 31. The source repository was never touched, and there is no commit or tag anywhere behind either release. The jscrambler incident in July ran the same play. Jscrambler later confirmed that an attacker used a compromised npm publishing credential to push five malicious versions over roughly three hours, again with nothing behind them in the repo.

Third Coming and Miasma do not fit that pattern, and that gap is why this piece exists rather than just linking to the writeups. Both compromises reached the build pipeline instead of a maintainer’s npm token. For Bitwarden, the way in was a compromised Checkmarx GitHub Action already used in Bitwarden’s own pipeline, after which the release workflow was edited repeatedly to get a prebuilt tarball published through Bitwarden’s OIDC-backed npm publishing path. In the Miasma case, at least 32 packages under Red Hat’s @redhat-cloud-services scope shipped malicious releases on June 1 after a Red Hat employee’s GitHub account was compromised. The attacker pushed orphan commits, which skipped code review entirely, then published through the repository’s GitHub Actions OIDC path. Neither attacker needed a maintainer’s npm credentials to make a publish look legitimate.

That split matters for an evaluation. Miasma is the clean example. Wiz found the injected workflow requesting an OIDC token and publishing packages with valid SLSA provenance attestations, because the workflow that produced them really was the legitimate CI pipeline, just triggered by a commit nobody authorized.

Third Coming is murkier. Endor Labs walked the public commit history and found the release workflow edited five times in quick succession to get a staged tarball published, one of those attempts dropping the provenance flag altogether, and the analysis explicitly declines to pin the successful publish on any particular run or to be read as a signed incident-response timeline.

Either way, the point holds. Replacing long-lived tokens with Trusted Publishing is exactly what gets recommended after a stolen-credential incident like axios, and both campaigns show where that advice runs out, because a compromised pipeline can produce a publish that looks legitimate whether or not a clean attestation ends up attached to it. A registry that only checks for a green attestation would have missed Miasma outright, and cannot be assumed to have caught Third Coming either.

The naming lineage kept going, too. A separate campaign surfaced in August under the “Here We Go Again” tag. It is its own incident, not a repeat of Third Coming.

How a Secure npm Registry Catches What Reaches the Pipeline

This is the part that matters for Third Coming and Miasma, because neither one gets caught by asking whether a publish came from a trusted workflow. Both involved trusted CI publishing paths.

Where Blocking Install Scripts Stops Helping

npm runs a package’s install scripts automatically unless something stops it, and that is the mechanism most of these campaigns reached for first. The malicious axios dependency fired from a postinstall hook. jscrambler’s first three poisoned versions used preinstall, and so did the backdoored Bitwarden CLI and the main wave of Miasma releases.

As of npm 12, which shipped in July 2026, dependency install scripts are off by default. Preinstall, install, and postinstall no longer run unless a project explicitly approves them, and npm also blocks the implicit node-gyp rebuild that a root-level binding.gyp file used to trigger. That second part is not academic here, because Wiz’s June 4 follow-up covered a further wave of Miasma packages abusing binding.gyp to execute code during installation, which is exactly the move you make when scanners are only reading the scripts block. On older clients, --ignore-scripts covers the lifecycle-script subset and nothing beyond it.

Then there is the limit, and jscrambler demonstrated it inside the same incident. From 8.18.0 onward the attacker moved the identical dropper out of preinstall and into a self-executing function at the top of dist/index.js, so it fired on import or CLI use instead of at install time and sailed straight through npm install --ignore-scripts. Attackers can move the payload. Blocking install scripts does not take it out of the package.

Why Content Screening Ignores the Attestation

The control that actually answers Third Coming and Miasma sits a step earlier, and it reads the release instead of the publisher. Content screening can look for unexpected install hooks, obfuscated code with no reason to be there, mismatches between the published artifact and the project’s source, and anomalies from one version to the next. The Bitwarden release shows how loud that last signal can get, since Endor Labs’ recursive diff found package.json advertising 2026.4.0 while the bundled CLI still carried 2026.3.0 in its packed metadata, which says repackaged long before anybody decompiles anything.

SecureChain’s own account of this step is that every package is rebuilt from source in hardened, isolated environments and screened for known malware, suspicious code patterns, and supply chain risks, with anything that fails inspection blocked before it reaches your environment. Screening on that basis does not care whether a publish arrived through a hijacked personal token or a compromised CI pipeline with a spotless attestation, because the attestation is not the thing being read.

Confidence here is moderate to high, with the same caveat that applies to script blocking. This is detection, and detection carries a false negative rate. Malware can delay, disguise, or split up its behavior, and jscrambler’s mid-incident pivot is a decent reminder that attackers adapt to whatever the scanners are looking at. It is still the closest thing on this list to answering Third Coming and Miasma on their own terms, because it evaluates the contents of a release instead of trusting the identity behind it.

SecureChain as an npm Registry Replacement Against Stolen-Credential Hijacks

axios and jscrambler are the cleaner case, and this is where an npm registry replacement earns its keep with the least hedging.

Point your builds at a curated, rebuilt-from-source catalog and, for any package SecureChain covers, the version you resolve is the one TuxCare built from verified source in a hardened environment rather than whatever was last pushed to npmjs.com. A malicious tarball published with a stolen token is simply not in that path. It does not matter how convincingly it is packaged or how fast it gets flagged elsewhere, because your build was never going to look at the public registry’s copy. jscrambler’s compromise is structurally axios with a different package name on it, so the same guarantee covers both.

Two things are worth being precise about, because collapsing them is how this argument gets oversold. Coverage is the first. SecureChain launched with the most depended-on packages in the npm registry and will add a package you depend on if it is not in the catalog yet, so the guarantee above applies to covered packages rather than to every name a dependency tree happens to drag in. Reproduction fidelity is the second. A published npm package often contains transpiled or bundled output rather than the repository’s raw source, and matching that byte for byte would mean reproducing the publisher’s own build environment, which the ecosystem does not guarantee. A SecureChain rebuild is not a bit-for-bit clone of the publisher’s tarball, and it was never meant to be. It is a build with a traceable origin, which is a different and more useful property when the publisher’s tarball is the thing you stopped trusting.

That traceability is what the accompanying metadata is for. SecureChain packages are built and signed to support SLSA Level 3 provenance, with builds running from vetted sources and continuous testing behind them, and TuxCare publishes SBOM and VEX metadata where it is available. SBOM coverage varies by package and is still expanding, in SPDX or CycloneDX depending on the package, so check the current documentation rather than assuming a uniform set.

A Quarantine Window Is Deterministic Against Short-Lived Releases

Screening, script blocking, rebuilding from source. All three work by recognizing something as wrong. A quarantine window does not have to recognize anything.

Delay resolution of a freshly published version for long enough, and a release that gets pulled inside that window is never eligible to reach a build. Nothing gets analyzed, and there is no classifier with a false negative rate to tune. The window length and any exclusions are still configuration decisions, but they are the kind you can settle on a whiteboard. The catch lives in the wording, though. Age alone does not make a version safe. It buys time for somebody else to catch it. A malicious release that stays up past the delay ages into eligibility like any other version, which is exactly what happened with jscrambler 8.14.0.

Incident Exposure window Covered by a 24-hour quarantine
axios Roughly 3 hours, 00:21 to 03:15 UTC on March 31 Yes, both versions were pulled well inside it
Shai-Hulud “Third Coming” 93 minutes, 21:57 to 23:30 UTC on April 22 Yes, deprecated well inside it
Miasma Two waves of commits on June 1, most versions revoked by 13:00 UTC Likely, but not confirmed for every version
jscrambler Five versions over roughly 3 hours on July 11 Partly, since 8.14.0 was never pulled from the registry

Two of those are confirmed wins for arithmetic over analysis. jscrambler is the counterexample. Miasma sits in between, because Wiz reported that most malicious versions had been revoked by 13:00 UTC with two still live at that point, which establishes fast partial removal but not whether every version disappeared before a 24-hour age gate would have expired.

The tradeoff is real, too. A quarantine window means running slightly behind on legitimate patches, and teams shipping against fast-moving upstream dependencies feel that more than teams on slower internal platforms. It is also one of the simplest controls here to implement, and the one most likely to get waved off in an evaluation for sounding too simple to be doing real work.

Private npm Registry Security Beyond a Pull-Through Cache

Switching only matters if it works day to day, so here is the operational part.

The integration is two lines in .npmrc, a registry line and the auth line for that host, using the CLN token TuxCare issues you, with YOUR_CLN_TOKEN swapped for the real thing:

registry=https://artifacts.tuxcare.com/npm/
//artifacts.tuxcare.com/npm/:_authToken=YOUR_CLN_TOKEN

package.json does not change. Names and versions stay as they are, and the same endpoint serves SecureChain builds where they exist plus the public upstream package for everything else, so there is no second registry to wire up.

There is one wrinkle worth testing before a wide rollout. package-lock.json records, among other things, a resolved URL naming where each tarball came from and an integrity hash over that tarball’s bytes. The resolved URL changing when you switch hosts is expected. The integrity hash is the interesting one. A hash validates against a byte-identical tarball from any host, so a pure change of host would not touch it, but a SecureChain rebuild is legitimately not byte-identical to the public artifact. That mismatch is what surfaces as EINTEGRITY when an old public-registry lockfile meets a new registry underneath it.

So plan for a regenerated lockfile rather than a cosmetic diff. Delete node_modules and package-lock.json, run a fresh install against the new registry, then commit the lockfile it produces, which records the SecureChain URLs and checksums. Do that in a scratch branch or a clone first, so the diff is something you read rather than something CI discovers for you. Then decide up front whether the change lands as its own commit across every repo in one window or rolls out gradually. Mixing a registry switch into a feature branch is how the config gets quietly reverted by somebody who never knew it was there.

Two more steps turn the switch from a suggestion into something enforced. Move CI to npm ci wherever it is still running npm install, since npm ci installs from the committed lockfile and fails when the lockfile and package.json disagree instead of quietly updating it. Then block egress to registry.npmjs.org from build agents, because until that is closed, the registry setting in .npmrc is a suggestion anyone can override to unblock a deploy.

Test that egress block in staging before enforcing it everywhere. Whatever breaks there will show you which pipelines and tools have been going around the registry setting, and that list is a much better thing to have as a document than as an incident.

The Case for a Different npm Registry

Content screening and rebuild-and-resolve cover different failure modes, not the same one twice. Screening speaks to Third Coming and Miasma, because it does not depend on where a publish came from. Rebuilding and resolving from a curated catalog speaks to axios and jscrambler, because for a covered package the malicious artifact never enters the path your build resolves from, backed by signed artifacts and SLSA Level 3 provenance.

If your team is still resolving straight from the public registry, get a quote for SecureChain for npm and see what it costs to close that gap.

FAQ

What is a secure npm registry?

A registry layer that serves rebuilt and evaluated packages for the dependencies it covers, instead of passing the publisher’s artifact straight through. In practice it is a mix, with SecureChain builds where they exist and public upstream packages for the rest, all served through the same endpoint. That is a different thing from a pull-through cache, which improves availability and speed without inspecting anything that passes through it.

Would a secure npm registry have stopped Shai-Hulud’s Third Coming campaign?

It can, provided the registry screens content independently of publishing identity. Whether the malicious release itself carried a valid attestation was never established, so identity-based checks alone cannot be relied on here. A screening step that reads what a release contains, a new build hook, obfuscated code, files with no matching commit, can detect that regardless of what an attestation says. Miasma is the cleaner example of the same failure mode, since those releases did carry valid, signed SLSA provenance.

Would a quarantine window have stopped axios?

Yes. The malicious versions were live for roughly three hours and were then pulled, so a one-day adoption delay, the shortest npm can express, would have kept them ineligible for their entire malicious lifetime with nothing needing to be identified as bad. That gate is the min-release-age setting, which takes a value in days and needs npm 11.10.0 or newer, since older clients ignore it silently. It gates dependency resolution rather than acting as a retroactive check, so a bad version already pinned in a committed lockfile is a separate problem.

What does an npm registry replacement actually change day to day?

Mainly where install commands resolve from. package.json and most workflows stay the same. package-lock.json needs regenerating once, because both the resolved URL and the integrity hash in it describe artifacts from the old registry.

Is private npm registry security handled just by standing up a private registry?

Not on its own. A caching proxy gives you a chokepoint for where packages come from, but a chokepoint does not establish that what flows through it is trustworthy. Whether installs actually get safer depends on what runs at that chokepoint, and on whether the paths around it are closed off too. CI still resolving straight from the public registry is the usual gap.

Summary
Secure npm Registry Tested Against axios and Shai-Hulud
Article Name
Secure npm Registry Tested Against axios and Shai-Hulud
Description
Would a secure npm registry have stopped axios, jscrambler, Shai-Hulud, and Miasma? SecureChain's controls, mapped to each mechanism.
Author
Publisher Name
TuxCare
Publisher Logo

Join 4,500+ Linux & Open Source Professionals!

2x a month. No spam.

Table of Contents
Get the open-source security answers you need

Join 4,500+ Linux & Open Source Professionals!

2x a month. No spam.