Package ecosystem
pnpm (handled by the npm_and_yarn ecosystem)
Package manager version
11.17.0 (also reproduces on 11.5.2)
Language version
Node 22+
Manifest location and content
Any project whose pnpm-lock.yaml pins a transitive dependency at an older version that already satisfies its declaring parent's range, while a newer fixed version exists on the registry. In the real case: [email protected] declares brace-expansion: ^5.0.5 and the lockfile pins [email protected]; the advisory fix is 5.0.9.
Updated dependency
Transitive brace-expansion, pinned at 5.0.8 in pnpm-lock.yaml under [email protected]. Advisory: CVE-2026-69152 / GHSA-rgw5-rvv9-x895 (affected >= 4.0.0 < 5.0.9).
What you expected to see, versus what you actually saw
Expected: a security PR bumping brace-expansion 5.0.8 → 5.0.9 in pnpm-lock.yaml.
Actual: the security update job fails with security_update_not_possible. Relevant output from the failed update job (no conflicting dependencies):
The latest possible version of brace-expansion that can be installed is 5.0.8
The earliest fixed version is 5.0.9.
security_update_not_possible | {
"dependency-name": "brace-expansion",
"latest-resolvable-version": "5.0.8",
"lowest-non-vulnerable-version": "5.0.9",
"conflicting-dependencies": []
}
The job runs corepack pnpm update [email protected] --lockfile-only --no-save -r (the version-pinned form from SubdependencyVersionResolver#pnpm_update_command) and the lockfile is left unchanged.
Native package manager behavior
pnpm update [email protected] --lockfile-only --no-save -r changes nothing — the brace-expansion: 5.0.8 pin under [email protected] stays, even though 5.0.9 satisfies the declaring range ^5.0.5.
The unpinned form works:
pnpm update brace-expansion --lockfile-only --no-save -r → updates to 5.0.9.
Smallest manifest that reproduces the issue
mkdir repro && cd repro
# package.json
cat > package.json <<'EOF'
{
"name": "repro",
"version": "1.0.0",
"private": true,
"packageManager": "[email protected]",
"dependencies": {
"minimatch": "10.2.5"
}
}
EOF
# 1. Simulate a lockfile generated before [email protected] existed,
# by temporarily pinning 5.0.8 via an override.
printf 'overrides:\n "brace-expansion": "5.0.8"\n' > pnpm-workspace.yaml
pnpm install --lockfile-only # lockfile pins brace-expansion 5.0.8
# 2. Drop the override; the lockfile is now "stale" (5.0.9 is on the registry).
printf '' > pnpm-workspace.yaml
# 3. Dependabot-style update (version pinned) — silent NO-OP:
pnpm update [email protected] --lockfile-only --no-save -r
grep -c 'brace-expansion: 5.0.8' pnpm-lock.yaml # -> 1 (unchanged)
# 4. Unpinned update — works:
pnpm install --lockfile-only # restore stale state
pnpm update brace-expansion --lockfile-only --no-save -r
grep -c 'brace-expansion: 5.0.8' pnpm-lock.yaml # -> 0 (now 5.0.9)
The lockfile's dual-version state (5.0.8 under one parent, 5.0.9 under another) reproduces it as well — both versions satisfy their parents' ranges, so the pinned update has nothing to do.
Root cause hypothesis
For a transitive dependency, pnpm will not re-pin an entry away from a version that already satisfies the declaring parent's range, even when asked for an explicit higher in-range version (update <pkg>@<version>). The --depth Infinity / pnpm audit --fix fallbacks in SubdependencyVersionResolver that could recover are gated behind the enable-audit-fix-fallback experiment, which is not enabled by default → the resolver reports the locked 5.0.8 and the job ends in security_update_not_possible.
Related issues
Package ecosystem
pnpm (handled by the
npm_and_yarnecosystem)Package manager version
11.17.0 (also reproduces on 11.5.2)
Language version
Node 22+
Manifest location and content
Any project whose
pnpm-lock.yamlpins a transitive dependency at an older version that already satisfies its declaring parent's range, while a newer fixed version exists on the registry. In the real case:[email protected]declaresbrace-expansion: ^5.0.5and the lockfile pins[email protected]; the advisory fix is5.0.9.Updated dependency
Transitive
brace-expansion, pinned at5.0.8inpnpm-lock.yamlunder[email protected]. Advisory: CVE-2026-69152 / GHSA-rgw5-rvv9-x895 (affected>= 4.0.0 < 5.0.9).What you expected to see, versus what you actually saw
Expected: a security PR bumping
brace-expansion5.0.8 → 5.0.9 inpnpm-lock.yaml.Actual: the security update job fails with
security_update_not_possible. Relevant output from the failed update job (no conflicting dependencies):The job runs
corepack pnpm update [email protected] --lockfile-only --no-save -r(the version-pinned form fromSubdependencyVersionResolver#pnpm_update_command) and the lockfile is left unchanged.Native package manager behavior
pnpm update [email protected] --lockfile-only --no-save -rchanges nothing — thebrace-expansion: 5.0.8pin under[email protected]stays, even though 5.0.9 satisfies the declaring range^5.0.5.The unpinned form works:
pnpm update brace-expansion --lockfile-only --no-save -r→ updates to5.0.9.Smallest manifest that reproduces the issue
The lockfile's dual-version state (5.0.8 under one parent, 5.0.9 under another) reproduces it as well — both versions satisfy their parents' ranges, so the pinned update has nothing to do.
Root cause hypothesis
For a transitive dependency, pnpm will not re-pin an entry away from a version that already satisfies the declaring parent's range, even when asked for an explicit higher in-range version (
update <pkg>@<version>). The--depth Infinity/pnpm audit --fixfallbacks inSubdependencyVersionResolverthat could recover are gated behind theenable-audit-fix-fallbackexperiment, which is not enabled by default → the resolver reports the locked 5.0.8 and the job ends insecurity_update_not_possible.Related issues