[agent] Found by the scheduled PDM bug-hunt routine (ledger #312).
Summary
PDM releases before 2.11 (lock_version 2 / 4.3 / 4.4) don't replace a package that's already installed at the same version. Hosted mode handles this: it emits redirect_pdm_stale_install_risk (plus the installed-byte probe redirect_pypi_stale_install), and vex then fails closed. Vendored mode handles neither. scan --mode vendored on a warm PDM env exits 0 with no stale warning. The next pdm sync / pdm install exits 0 but keeps the upstream bytes, and socket-patch vex attests not_affected.
The VEX envelope does carry a vendored_tree_out_of_sync warning, but its advice ("re-run your package manager's install to resync it") doesn't work on these PDM versions: pdm sync is exactly the step that keeps the old bytes.
Impact
A team on PDM 1.x / 2.0–2.10 vendors a patch into a project where the dependency is already installed (a dev machine, a cached CI venv) and runs pdm sync. Every command succeeds, yet the vulnerable code keeps running, and the published VEX says the vulnerability is mitigated. Hosted mode warns about this exact PDM behaviour, so vendored users get a weaker guarantee for the same lock.
Repro
Uses a local mock of the patch API that serves a patched urllib3 1.26.18 wheel, with a marker line appended to urllib3/response.py. Any free urllib3 1.26.18 patch shows the same thing.
uv venv tools/2.10.4 --python 3.11 && uv pip install --python tools/2.10.4/bin/python pdm==2.10.4
mkdir proj && cd proj
cat > pyproject.toml <<'EOF'
[project]
name = "x"
version = "0.0.0"
requires-python = ">=3.8"
dependencies = ["urllib3==1.26.18"]
[tool.pdm]
distribution = false
EOF
uv venv .venv --python ../tools/2.10.4/bin/python
export VIRTUAL_ENV=$PWD/.venv
../tools/2.10.4/bin/pdm lock && ../tools/2.10.4/bin/pdm sync # warm env: upstream urllib3 installed
socket-patch scan --mode vendored --json --yes # exit 0; vendor events: only vendor_prebuilt_downloaded
../tools/2.10.4/bin/pdm sync # exit 0, "All packages are synced to date"
grep -c SOCKET-PATCH-MARKER .venv/lib/python3.11/site-packages/urllib3/response.py # 0 -> still upstream
socket-patch vex --json -O vex.json # exit 0; statement: not_affected / inline_mitigations_already_exist
For comparison, the same project with --mode hosted emits redirect_pdm_stale_install_risk and redirect_pypi_stale_install, and vex exits 1 (no_applicable_patches).
Expected vs actual
- Expected: the same treatment as hosted on these locks.
docs/testing/pdm-compatibility.md says PDM < 2.11 keeps an already-installed same-version package, and redirect/pdm.rs warns proactively once per lock for that reason. The Pipenv vendored path already probes the installed bytes (pypi_pipenv_stale_install, documented in docs/ecosystems.md). The vendored PDM path should warn with the remedy that works (pdm sync --reinstall, uninstall the package, or recreate the env), and the VEX hint shouldn't say a plain reinstall resyncs it.
- Actual: no warning from the vendored scan.
pdm sync / pdm install leave the env unpatched, and vex attests not_affected with only the generic vendored_tree_out_of_sync hint.
Matrix (Linux, main 045d7ec, real PDM)
| PDM |
lock_version |
vendored scan warns? |
installed after pdm sync |
vex |
| 1.4.5 |
2 |
no (only pypi_pdm_legacy_sync_required) |
upstream |
not_affected |
| 1.5.3 |
2 |
no (only pypi_pdm_legacy_sync_required) |
upstream |
not_affected |
| 2.8.2 |
4.3 |
no |
upstream |
not_affected |
| 2.10.4 |
4.4 |
no |
upstream (pdm sync and pdm install; reproduced twice) |
not_affected |
| 2.11.2 |
4.4.1 |
— |
patched (pass) |
not_affected (correct) |
| 2.29.2 |
4.5.1 |
— |
patched (pass) |
not_affected (correct) |
2.10.4, --mode hosted (control) |
4.4 |
yes (redirect_pdm_stale_install_risk, redirect_pypi_stale_install) |
upstream |
fails closed |
macOS and Windows weren't probed. The behaviour comes from PDM's installer, not the OS.
Suspect code
crates/socket-patch-core/src/vendor/pypi_pdm.rs:95-97 only adds pypi_pdm_legacy_sync_required for lock_version == "2". There's no equivalent of the hosted redirect_pdm_stale_install_risk for 2 / 4.3 / 4.4.
crates/socket-patch-core/src/vendor/pypi.rs:606 (pipenv_stale_install_warning) is only called from the Pipenv flavor (pypi.rs:881), so the PDM flavor never probes the installed bytes.
crates/socket-patch-core/src/patch/redirect/pdm.rs:42-55 is the hosted counterpart to mirror.
crates/socket-patch-cli/src/commands/vex.rs:677-690 is the vendored_tree_out_of_sync advice.
Related but distinct: #477 (the reverse direction, after rollback).
[agent] Found by the scheduled PDM bug-hunt routine (ledger #312).
Summary
PDM releases before 2.11 (
lock_version2/4.3/4.4) don't replace a package that's already installed at the same version. Hosted mode handles this: it emitsredirect_pdm_stale_install_risk(plus the installed-byte proberedirect_pypi_stale_install), andvexthen fails closed. Vendored mode handles neither.scan --mode vendoredon a warm PDM env exits 0 with no stale warning. The nextpdm sync/pdm installexits 0 but keeps the upstream bytes, andsocket-patch vexattestsnot_affected.The VEX envelope does carry a
vendored_tree_out_of_syncwarning, but its advice ("re-run your package manager's install to resync it") doesn't work on these PDM versions:pdm syncis exactly the step that keeps the old bytes.Impact
A team on PDM 1.x / 2.0–2.10 vendors a patch into a project where the dependency is already installed (a dev machine, a cached CI venv) and runs
pdm sync. Every command succeeds, yet the vulnerable code keeps running, and the published VEX says the vulnerability is mitigated. Hosted mode warns about this exact PDM behaviour, so vendored users get a weaker guarantee for the same lock.Repro
Uses a local mock of the patch API that serves a patched urllib3 1.26.18 wheel, with a marker line appended to
urllib3/response.py. Any free urllib3 1.26.18 patch shows the same thing.For comparison, the same project with
--mode hostedemitsredirect_pdm_stale_install_riskandredirect_pypi_stale_install, andvexexits 1 (no_applicable_patches).Expected vs actual
docs/testing/pdm-compatibility.mdsays PDM < 2.11 keeps an already-installed same-version package, andredirect/pdm.rswarns proactively once per lock for that reason. The Pipenv vendored path already probes the installed bytes (pypi_pipenv_stale_install, documented in docs/ecosystems.md). The vendored PDM path should warn with the remedy that works (pdm sync --reinstall, uninstall the package, or recreate the env), and the VEX hint shouldn't say a plain reinstall resyncs it.pdm sync/pdm installleave the env unpatched, andvexattestsnot_affectedwith only the genericvendored_tree_out_of_synchint.Matrix (Linux, main
045d7ec, real PDM)pdm syncpypi_pdm_legacy_sync_required)pypi_pdm_legacy_sync_required)pdm syncandpdm install; reproduced twice)--mode hosted(control)redirect_pdm_stale_install_risk,redirect_pypi_stale_install)macOS and Windows weren't probed. The behaviour comes from PDM's installer, not the OS.
Suspect code
crates/socket-patch-core/src/vendor/pypi_pdm.rs:95-97only addspypi_pdm_legacy_sync_requiredforlock_version == "2". There's no equivalent of the hostedredirect_pdm_stale_install_riskfor 2 / 4.3 / 4.4.crates/socket-patch-core/src/vendor/pypi.rs:606(pipenv_stale_install_warning) is only called from the Pipenv flavor (pypi.rs:881), so the PDM flavor never probes the installed bytes.crates/socket-patch-core/src/patch/redirect/pdm.rs:42-55is the hosted counterpart to mirror.crates/socket-patch-cli/src/commands/vex.rs:677-690is thevendored_tree_out_of_syncadvice.Related but distinct: #477 (the reverse direction, after rollback).