Skip to content

Add an npm resolution cooldown for the local-viewer frontend#864

Open
timhaines wants to merge 1 commit into
usestrix:mainfrom
timhaines:add-npm-cooldown
Open

Add an npm resolution cooldown for the local-viewer frontend#864
timhaines wants to merge 1 commit into
usestrix:mainfrom
timhaines:add-npm-cooldown

Conversation

@timhaines

@timhaines timhaines commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

A resolver-layer release-age cooldown for the tree's npm ecosystem: the React/Vite local-viewer SPA under strix/viewer/frontend. npm won't resolve a version until it's ~6 days old.

What

  • strix/viewer/frontend/.npmrcmin-release-age=6. This gates npm install <pkg> / npm update / lockfile regeneration, which is the manual and local path nobody opens a PR for. It does not affect npm ci, which installs the lockfile verbatim, so make viewer and any CI build behave exactly as they do today.
  • engines.npm >= 11.10.0 + engine-strict=truemin-release-age landed in npm 11.10.0. Older npm silently ignores the unknown key, which would fail the cooldown open with no error and no gate. The engine guard turns that into a hard error instead.

That fail-open case is the reason the second half exists. A cooldown that quietly does nothing on a contributor's older npm is worse than no cooldown, because it reads as covered.

Why bother — 2026 has been a brutal year for npm

The attacks a cooldown defends against are smash-and-grab: a malicious version is published, harvests credentials the moment it installs, and is spotted and pulled within minutes to hours. The blast radius is whoever auto-resolves the newest version inside that window.

  • axios (Mar 2026) — the year's marquee npm compromise. ~100M weekly downloads and ~174k dependents; Google attributed it to the North Korean group UNC1069. [Huntress] [Security Boulevard]
  • TanStack / "Mini Shai-Hulud" (11 May 2026) — TeamPCP pushed 84 malicious versions across 42 @tanstack/* packages in a ~6-minute window (@tanstack/react-router alone is 12.7M weekly downloads). Caught in ~25 minutes, but npm's "no unpublish while dependents exist" policy left the tarballs installable for ~3 hours. It was also the first documented case of malicious npm packages carrying valid SLSA provenance: signing and attestation verified fine, so a release-age cooldown is the layer that would actually have caught it. [Socket]
  • Shai-Hulud 2.0 (Nov 2025 →) — a self-propagating worm that moved execution to preinstall and a weaponized binding.gyp (node-gyp runs it during install, before any script is reviewed), harvesting npm/GitHub/AWS/GCP/Azure/Vault/K8s credentials and republishing from every account it reaches. Follow-on waves hit 300+ package versions (~16M weekly downloads) on 19 May and the @redhat-cloud-services namespace on 1 Jun. [Microsoft] [The Register]

None of these are direct strix dependencies, but the viewer is React-ecosystem npm, which is exactly the target class, and its graph already contains debug (3× in the lockfile), one of the packages hijacked in the 2025 qix-maintainer compromise. Every incident above was caught well inside 6 days.

The honest limit: a cooldown does nothing against a compromise that stays hidden longer than the window. It filters the smash-and-grab, which is what 2026 has mostly been. [cooldowns.dev]

Verification

Checked rather than assumed, since a cooldown that strands a locked version would be a real objection:

  • It blocks nothing currently locked. Regenerated the lockfile in a temp copy with the cooldown active and diffed resolved versions against the committed lock: no version changes. Control run without the cooldown produces the same result, so nothing here is attributable to the 6-day window.
  • npm ci is unaffected, confirmed against the committed lock.
  • One cosmetic note: npm writes engines into package-lock.json's root entry on the next npm install, so the lock will pick up a three-line delta whenever someone next regenerates it. npm ci doesn't enforce that field, so nothing breaks in the meantime and there's no need to churn the lock in this PR.

Notes

  • No min-release-age-exclude: there are no capped-back or security-critical deps in the frontend tree. One behavioural difference from the Dependabot cooldown to be aware of — min-release-age blocks an npm audit fix that falls inside the window (keeps the vulnerable version, warns, non-zero exit) rather than auto-exempting security updates. If a frontend CVE ever needs a same-week bump, add that package to min-release-age-exclude.
  • Contributors who rebuild the viewer (make viewer) will need npm >= 11.10.0.

Relationship to #860 and #861

Stands alone. It only touches strix/viewer/frontend, so it can merge in any order, or on its own if you don't take the others.

The three are complementary rather than sequential. #860's Dependabot cooldown gates when a bump PR opens; this gates what any resolution produces, so it covers the local and manual path the updater never sees, and it keeps working if the Dependabot config is later changed or removed. #861 is the same idea for the Python tree — same reasoning, different ecosystem, no shared code.

The 6-day value is picked to sit one day under #860's 7-day cooldown so its bumps still resolve here if both land. If #860 doesn't land, 6 days is a sensible standalone window either way.

Like the uv cooldown it's a little opinionated, since it changes what npm install resolves, so it's happily droppable if you'd rather keep just the Dependabot side.

🤖 Generated with Claude Code

The npm analog of the uv exclude-newer in usestrix#861. min-release-age=6 in an
.npmrc under the frontend gates tree resolution (npm install/update,
lockfile regen) so a version has to age a few days before it resolves —
one day under the Dependabot cooldown so bumps still land here.

min-release-age arrived in npm 11.10.0 and is a no-op on older npm, which
would fail the cooldown open. engine-strict + engines.npm >= 11.10.0 make
an older npm error instead. Does not affect npm ci (lockfile verbatim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@timhaines timhaines changed the title Add an npm resolution cooldown to match the Dependabot config Add an npm resolution cooldown for the local-viewer frontend Jul 23, 2026
@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds a six-day npm package-resolution cooldown for the local-viewer frontend.

  • Configures min-release-age=6 and strict npm engine enforcement.
  • Requires npm 11.10.0 or newer for frontend package operations.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
strix/viewer/frontend/.npmrc Adds the six-day release-age policy and enables strict engine validation.
strix/viewer/frontend/package.json Declares npm 11.10.0 as the minimum supported npm version.

Reviews (2): Last reviewed commit: "Add an npm resolution cooldown to match ..." | Re-trigger Greptile

Comment thread strix/viewer/frontend/.npmrc
@timhaines

Copy link
Copy Markdown
Contributor Author

@greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant