Repository navigation
Hosted yarn classic rewrite drops the #sha1 fragment when the grant has no sha1, so yarn's cache serves stale bytes: yarn ≤1.17 silently installs the unpatched package, and yarn ≥1.19 fails every warm-cache install #558
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:yarn-classicYarn classic (1.x)Yarn classic (1.x)
on Oct 2, 2026 mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] A correction to the "Expected" citation: the contract is
crates/socket-patch-cli/CLI_CONTRACT.md. Its lockfile-discovery table (line 363) lists the yarn classic hosted pin as "classicintegrity/#sha1, required". docs/ecosystems.md doesn't state the fragment explicitly, so please disregard that part of the citation.
Generated by Claude Code
mikolalysenko commented
on Oct 2, 2026 CollaboratorAuthorMore actions[agent] Triage: priority:p1 (yarn classic). Hosted
rewrite_yarn_classicwrites a fragmentlessresolvedURL when the grant carries no sha1, colliding in yarn's cache slot. Composer has an equivalent guard (redirect_composer_missing_sha1); yarn classic does not. Distinct root cause; no open PR covers it.
Generated by Claude Code
mikolalysenko commented
on Oct 7, 2026 CollaboratorAuthorMore actions[agent] Re-triage on main
05ecc6e: still reproduces on Linux, ×2 per version, using the issue's repro (warm the cache with a fragmentless upstreamleft-pad@1.3.0lock, then a hosted scan against a grant whose artifactintegrityhas onlysha512).- The scan exits 0 with
redirected: 1and no warning. The lock getsresolved "<hosted>/left-pad-1.3.0.tgz"with no#sha1fragment. - yarn 1.10.1: the warm-cache
yarn install --frozen-lockfileexits 0 and installs unpatched bytes. - yarn 1.22.22: the warm-cache frozen install exits 1 with
Incorrect integrity when fetching from the cache for "left-pad". - Control: the same flow with a grant that carries
sha1pins#<sha1>, and the warm-cache install is patched on both versions.
Generated by Claude Code
- The scan exits 0 with
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Re-triage on main
e2d9633(after #1057, the yarn.lock grammar move): still reproduces, Linux, ×2 per version, same repro (warm the cache from a fragmentless upstream lock, then a hosted scan against a grant whose artifactintegrityhas onlysha512).- The scan exits 0 and writes
resolved "<hosted>/left-pad-1.3.0.tgz"with no#sha1fragment and no warning. - yarn 1.10.1: the warm-cache
install --frozen-lockfileexits 0 and installs unpatched bytes. - yarn 1.22.22: it exits 1 with
Incorrect integrity when fetching from the cache for "left-pad".
Generated by Claude Code
- The scan exits 0 and writes
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). A normal first hosted Yarn classic install with a warm cache can use upstream bytes or fail when the service supplies SHA-512 only. Fix the cache identity or the supported grant contract.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming for v5 blocker burn-down (shared root cause: hosted yarn classic rewrite writes a fragmentless resolved URL when the grant lacks sha1). Branch: agent/v5-yarn-classic-sha1. Claim-ID: 2026-10-09T16:42:02Z-9ea6d3
- added 3 commits that reference this issue
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Re-triage from the Yarn classic bug-hunt (ledger #304), Linux, local mock whose grant artifact
integrityhas onlysha512. Same repro as before: warm the yarn cache from a fragmentless upstream lock, run a hosted scan, thenyarn install --frozen-lockfileagainst the same cache.binary yarn scan resolvedwrittenwarm-cache frozen install main 9ab72d41.10.1 exit 0, no warning no #sha1exit 0, unpatched bytes main 9ab72d41.22.22 exit 0, no warning no #sha1exit 1, Incorrect integrity when fetching from the cachePR #1328 head 494932e1.10.1 exit 0 …/left-pad-1.3.0.tgz#81960ffa…exit 0, patched PR #1328 head 494932e1.22.22 exit 0 …/left-pad-1.3.0.tgz#81960ffa…exit 0, patched On #1328 the control cell also passes on both releases (an upstream lock that already had a fragment, so the cache key is distinct). So #1328 fixes the repro, and main still reproduces it.
Generated by Claude Code
[agent] Found by the scheduled Yarn classic (1.x) bug-hunt routine (ledger #304).
Summary
In hosted mode,
rewrite_yarn_classicwritesresolved "<hosted-url>#<sha1>"only when the granted tarball artifact carriesintegrity.sha1. When the grant has onlysha512, it writes a resolved URL with no fragment, adds the newintegrityline, and reports success. The repo's own hosted npm-family fixtures use that sha512-only shape, for examplecovgap_commands_scan_hosted.rs:1339ande2e_redirect_bun_build.rs:809.Yarn classic names its cache slot
npm-<name>-<version>-<fragment>[-integrity]. With no fragment, the hosted entry lands innpm-left-pad-1.3.0-integrity. That's the same slot as:resolvedhas no#sha1), andThe URL plays no part in the cache key, so yarn reuses whatever bytes are already in that slot:
yarn install --frozen-lockfileexits 0 and installs the cached unpatched (or superseded) bytes, even though the lock pins the patchedintegrity.scanreportedredirected: 1.error Incorrect integrity when fetching from the cache for "left-pad" … Run yarn cache clean.vexdoes notice the unpatched tree (patch omitted from VEX: the patched files still hold the original content), so this isn't a false attestation. But the install itself silently runs the vulnerable code, or breaks.Impact
On yarn ≤ 1.17, a hosted-patched project can reinstall unpatched code with no error. On yarn ≥ 1.19, a developer or CI machine with a warm cache can't install at all until it runs
yarn cache clean. Composer already refuses this case (redirect_composer_missing_sha1informats/composer/hosted.rs:186). Yarn classic has no equivalent guard, and it doesn't compute the sha1 from the downloaded artifact either.Repro (Linux, main
61cfb9b)Mock patch API: the batch / view /
patches/packageroutes, with the grantedtarballartifact'sintegrityset to{ "sha512": "<sri>" }only, and the hosted tgz served athttp://127.0.0.1:8766/patch/npm/left-pad/1.3.0/…/left-pad-1.3.0.tgz.Superseding-patch variant (no fragmentless upstream needed): start from a normal registry lock, run a hosted scan against grant A (no sha1), install, then run a hosted scan against grant B for the same version (different bytes, no sha1), and do a fresh frozen install with the same cache. yarn 1.10.1 exit 0 installs A's bytes; 1.22.22 fails
Incorrect integrity when fetching from the cache.Expected vs actual
#sha1plus a recomputedintegrity, and the capstone e2e header (e2e_redirect_yarn_classic_build.rs) says the same. A hosted rewrite should either always pin a fragment (computing the sha1 from the downloaded artifact when the grant lacks one) or refuse with a warning, as composer does. It must not reportredirectedfor a lock that installs stale bytes or fails.scanexits 0 withredirected: 1and no warning, and the next warm-cache install behaves as in the table below.Matrix (Linux, Node 22; each cell run at least twice)
Incorrect integrity when fetching from the cacheThe OS doesn't matter, because the cache-key logic is yarn's own. macOS / Windows weren't probed.
First bad version
Not a regression: v4.0.0 (npm
@socketsecurity/socket-patch@4.0.0) writes the same fragmentlessresolved.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:3110-3115:fragfalls back tounwrap_or_default()whendep.integrity.sha1isNone, and no warning or refusal is emitted. Compareformats/composer/hosted.rs:186(redirect_composer_missing_sha1).