fix(hosted): CRLF-safe yarn classic rewrite, guard npm: aliases - #188
Merged
Mikola Lysenko (mikolalysenko) merged 1 commit intoAug 14, 2026
Merged
Conversation
On a CRLF yarn.lock (core.autocrlf Windows checkouts) the hosted
classic rewriter split blocks on "\n\n", which never matches CRLF
bytes: the whole lock became one block and the leftmost-match
replaces repointed the FIRST entry in the file at the patched
artifact instead of the target — with our real integrity pins, so
the install succeeded, the redirect was confirmed, ledgered, and
VEX-attested while the vulnerable dep kept its registry URL. The
rewriter now LF-normalizes CRLF locks for block scanning and
re-expands on output, so the correct entry is rewritten and every
untouched line stays byte-identical; ledger edits record the
on-disk CRLF form. Locks with bare carriage returns are refused
untouched with redirect_yarn_classic_unsupported_line_endings.
Block matching now resolves each lock-key pattern to the real
package it stands for (reusing the vendored backend's
pattern_real_name) instead of regex-matching the alias name, so a
fork-substitution entry ("left-pad@npm:other-pkg@^1") is never
hijacked onto the upstream patched artifact. Entries consuming the
patched package only through npm: aliases are skipped with an
explicit redirect_yarn_classic_alias_skipped /
redirect_yarn_berry_alias_skipped warning instead of silence (or
berry's misleading generic not-found), and classic now emits
redirect_yarn_classic_entry_not_found when a granted dep matches no
lock entry, matching every sibling npm-family rewriter.
Pinned by CRLF + alias-guard golden fixtures, rewriter unit tests,
and an in-process CRLF scan --redirect test.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Wenxin Jiang (Wenxin-Jiang)
approved these changes
Aug 14, 2026
Mikola Lysenko (mikolalysenko)
merged commit Aug 14, 2026
d39bbb5
into
main
231 of 234 checks passed
Mikola Lysenko (mikolalysenko)
deleted the
fix/classic-hosted-crlf-alias
branch
August 14, 2026 20:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Four audit findings (2026-08-13 hosted-mode audit) against the yarn classic hosted rewriter, one critical:
CRLF wrong-entry rewrite + false attestation (critical).
rewrite_yarn_classicsplit blocks on"\n\n", which never matches in a CRLFyarn.lock(core.autocrlfWindows checkouts — yarn v1 parses them fine). The whole lock collapsed into ONE block, and the leftmost-matchresolved/integrityreplaces repointed the FIRST entry in the file at the patched artifact instead of the target. Concretely: a CRLF lock withabbrev@1.1.1beforeleft-pad@1.3.0and a left-pad patch grant ends up installing the patched left-pad tarball AS abbrev (integrity passes — the pins are real), while left-pad keeps its registry URL and stays vulnerable. Downstream, the confirm gate (text.contains(artifact_url)) then counted the dep as redirected, ledgered it, and VEX-attested it — a full fail-open.Fork-alias hijack (medium). Block matching used a
^<name>@regex on the key line, so a fork-substitution entry"left-pad@npm:totally-other@^1.3.0":— which resolves a different package — matched on the alias name and was silently rewritten onto the upstream patched artifact, reversing the user's deliberate fork pin.Alias-only consumers invisible (medium). An entry consuming the patched package only through an alias (
"safe-pad@npm:left-pad@^1.3.0":) got no redirect and no signal at all in classic, and only a misleading genericentry_not_foundin berry — that copy keeps installing the unpatched artifact with zero indication why.No entry-not-found warning in classic (low). Every sibling npm-family rewriter warns when a granted dep matches no lock entry (version drift, not installed); classic vanished silently.
Fix
basicgolden and itsexpected-edits.jsonpass unmodified, preserving the cross-language TS edit-shape contract). Locks with bare carriage returns outside a CRLF pair are refused untouched, fail-closed, withredirect_yarn_classic_unsupported_line_endings.pattern_real_name(visibility widenedpub(super)→pub(crate)instead of duplicating alias resolution), so<name>@npm:<other>@…fork blocks are never touched and surface as not-found.redirect_yarn_classic_alias_skipped/redirect_yarn_berry_alias_skippedwarning naming the entry (suppressing the misleading generic not-found) and the dep stays out ofredirected/ledger/VEX via the existing confirm gate. Merged keys serving both a direct and an alias descriptor still rewrite. Rewriting alias entries to parity with the vendored classic backend is possible follow-up.redirect_yarn_classic_entry_not_foundon version drift/missing entry, mirroring berry/pnpm. Like berry's existing warning, it fires per npm dep absent fromyarn.lockin mixed-lockfile projects — warning-hygiene consolidation is tracked separately.docs/ecosystems.mddocuments the yarnnpm:alias behavior for both flavors.New golden fixtures (
npm/yarn-classic/crlf,npm/yarn-classic/alias-guard) are covered by the pre-existing.gitattributes-textrule so their CRLF bytes survive checkout. They are Rust-side only for now: the depscan TSgolden.test.tstwin needs the same fixtures/behavior ported (the TSrewriteYarnClassiclikely shares the CRLF bug).Testing
cargo test -p socket-patch-core --lib(2082 passed) — includes 7 new unit tests: CRLF target-only rewrite with byte-exact untouched lines + CRLF ledger originals + LF-equivalence, mixed-EOL fail-closed refusal, fork-alias no-hijack, alias-only skip warning (classic + berry), merged direct+alias non-regression, classic entry-not-found.cargo test -p socket-patch-core --test redirect_golden— green, with the two new fixtures (both verified red against the pre-fix rewriter: the alias-guard fork block was visibly hijacked).cargo test -p socket-patch-cli --test in_process_redirect(24 passed) — includes new full-chainscan --redirecttest over a decoy-first CRLF classic lock: decoy untouched, target pinned, CRLF preserved, ledger written.cargo test -p socket-patch-cli --test e2e_redirect_yarn_classic_build(7 passed, real corepack yarn@1.22.22 install-proof legs) ande2e_redirect_yarn_berry_build(7 passed).No findings skipped.
🤖 Generated with Claude Code
Note
Medium Risk
Changes hosted redirect logic for yarn classic and berry lockfiles, including a prior wrong-entry/attestation bug on CRLF locks; behavior is heavily tested but affects supply-chain pinning paths.
Overview
Critical CRLF fix: Classic
yarn.lockhosted redirects now normalize CRLF to LF for block splitting, rewrite the correct target entry (not the first block), re-expand CRLF on output, and store CRLF bytes in revert ledger edits. Mixed line endings are left untouched withredirect_yarn_classic_unsupported_line_endings.Matching & alias safety: Block selection uses
pattern_real_nameon comma-joined key patterns so fork entries like"left-pad@npm:other@…"are not hijacked. Alias-only consumers ("safe-pad@npm:left-pad@…") are skipped with explicitredirect_yarn_classic_alias_skipped/redirect_yarn_berry_alias_skippedwarnings instead of silent failure or misleadingentry_not_found. Classic now emitsredirect_yarn_classic_entry_not_foundwhen a granted dep has no matching entry.Adds golden fixtures, unit tests, an in-process CRLF
scan --redirecttest, anddocs/ecosystems.mdnotes on yarnnpm:alias behavior.Reviewed by Cursor Bugbot for commit ef92e46. Configure here.