Repository navigation
Hosted pnpm scan pins a pnpm-lock.yaml that pnpm is configured to ignore (lockfile=false / lockfile: false), reports success, and lock-only VEX attests not_affected while pnpm installs the upstream package #1074
Description
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
When the project disables pnpm's lockfile (lockfile=false in .npmrc on pnpm 9/10, or lockfile: false in pnpm-workspace.yaml on pnpm 11/12) but a pnpm-lock.yaml is still committed, scan --mode hosted rewrites that lock, auto-adds trustLockfile: true, and reports success with only the usual redirect_pnpm_trust_lockfile warning. pnpm never reads the lock: a plain pnpm install prints A pnpm-lock.yaml file exists. The current configuration prohibits to read or write a lockfile and installs the upstream package from the registry. Standalone socket-patch vex on a lockfile-only checkout (no node_modules, the usual CI/SBOM case) still attests the package not_affected from the lock pin.
socket-patch never reads pnpm's lockfile setting (no match for it under crates/socket-patch-core/src).
Impact
- Hosted mode reports success for a patch that no install will ever apply.
- VEX makes a false
not_affectedclaim for an unpatched install. That's the worst outcome the routine looks for. - Vendored mode is not affected: pnpm still applies
overrideswithout a lockfile, so the vendored tarball installs (verified on 12.10.1).
Repro (Linux, Node 22; patch API mocked as in the repo's e2e_redirect_pnpm_build.rs)
mkdir proj && cd proj
printf '{"name":"proj","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}\n' > package.json
pnpm install # writes pnpm-lock.yaml
printf 'lockfile: false\n' > pnpm-workspace.yaml # pnpm 11/12 (pnpm 9/10: echo 'lockfile=false' > .npmrc)
socket-patch scan --mode hosted --json --yes --api-url $MOCK --org test-org --api-token fake
# status: success, warnings: [redirect_pnpm_trust_lockfile]; lock now pins the Socket tarball
rm -rf node_modules
socket-patch vex --output vex.json --json --api-url $MOCK --org test-org --api-token fake
# exit 0, vex.json: not_affected / inline_mitigations_already_exist for pkg:npm/left-pad@1.3.0
pnpm install --store-dir "$(mktemp -d)"
# WARN A pnpm-lock.yaml file exists. The current configuration prohibits to read or write a lockfile
head -c 20 node_modules/left-pad/index.js # upstream bytes, not the patched markerOnce node_modules is installed, standalone vex correctly declines ("the patched files still hold the original content"). Only the lock-only attestation is wrong.
Expected vs actual
- Expected: CLI_CONTRACT (manifest-less VEX, vlt row) says a lock the package manager discards gets no lockfile basis: "So does a lock some vlt release discards … every hosted reference in it keeps no pin, and one
patched_ref_unattributablenames them", and the scan warns (redirect_vlt_old_lockfile_ignoredand similar). A pnpm lock that pnpm is configured not to read is the same case. Hosted should refuse or warn loudly (and say vendored works here), and VEX should withhold the lockfile basis. - Actual: hosted reports
successand writestrustLockfile: true. Lock-only VEX attestsnot_affected. A plainpnpm installinstalls upstream bytes.
Matrix (main 05ecc6e, Linux)
| pnpm | setting | hosted scan | lock-only vex |
pnpm install after scan |
pnpm install --frozen-lockfile |
|---|---|---|---|---|---|
| 9.15.9 | .npmrc lockfile=false |
success | not_affected (wrong) | upstream | fails ERR_PNPM_NO_LOCKFILE (loud) |
| 10.34.6 | .npmrc lockfile=false |
success | not_affected (wrong) | upstream | untested |
| 10.34.6 | pnpm-workspace.yaml lockfile: false |
success | not_affected | patched (pnpm 10 ignores the key there) | — |
| 11.28.5 | pnpm-workspace.yaml lockfile: false |
success | not_affected (wrong) | upstream | untested |
| 12.10.1 | pnpm-workspace.yaml lockfile: false |
success | not_affected (wrong) | upstream | patched (pnpm 12 reads the lock under --frozen-lockfile) |
| 12.10.1 | same, --mode vendored |
success | not_affected | patched (correct) | — |
Reproduced twice on main (independent fixtures) on every "wrong" row. macOS and Windows weren't probed. The setting is read by pnpm itself, so the result shouldn't depend on the OS.
Not a regression: release 4.0.0 (npm @socketsecurity/socket-patch@4.0.0) behaves the same on 9.15.9 (.npmrc) and 12.10.1 (pnpm-workspace.yaml).
Suspect code
crates/socket-patch-core/src/hosted/engine.rs:1430(the pnpm trust plan): it readspnpm-workspace.yamlfortrustLockfilebut never checks pnpm'slockfilesetting (.npmrclockfile, workspacelockfile:) before pinning.crates/socket-patch-core/src/vex/discover/npm.rs:562(extract_pnpm_lock): it grants the lockfile basis to every hosted pin inpnpm-lock.yamlwithout checking whether pnpm reads that lock.
No probe runs (Linux-only reproduction).
Activity
pnpm bug-hunt run 30: file #1074, re-verify #935/#956/#903/#904
mikolalysenko commentedon Oct 7, 2026
[agent] Triage:
priority:p1(pnpm, npm-family). Not a duplicate; no open PR covers it (no code undercrates/socket-patch-core/srcreads pnpm'slockfilesetting). Related in kind to #899 (a lock the package manager ignores still gets pinned and attested), but that's npm 12 / shrinkwrap through a different code path, so I'm not clustering them.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
v5 triage: P2, not a release blocker. Retain explicit pnpm lockfile=false handling at P2; the release gate assumes the input lockfile is the one the package manager consumes.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commentedon Oct 12, 2026
[agent] Claiming this issue (shared root cause: hosted pnpm pinning and lock-only VEX never read pnpm's
lockfilesetting, so a lock pnpm is configured to ignore is still pinned and attested). Branch: agent/fix-pnpm-lockfile-disabled. Claim-ID: 2026-10-12T13:22:37Z-76f8b4Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Draft PR: #1431
Generated by Claude Code
Refuse hosted pnpm pins when lockfile is off
Withhold lock-only VEX when pnpm lockfile is off
Read pnpm lockfile setting per pnpm major
Treat package-lock=false as pnpm lockfile off