You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Agent mode skips ./.venv when PIPENV_VENV_IN_PROJECT=0 or PIPENV_NO_VENV_IN_PROJECT=1 is set, but Pipenv 2018 through 2023.10.24 still use that .venv, so it stays unpatched and VEX attests not_affected (regression from #388) #645
[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
Since #388 (ccd43f5, the #334 fix), Pipenv venv discovery treats an explicit "not in project" setting as "ignore ./.venv". That covers PIPENV_VENV_IN_PROJECT=0 / false / off / no and PIPENV_NO_VENV_IN_PROJECT=1. In that case socket-patch returns only the $WORKON_HOME venv. The doc comment says this is because "Pipenv 2023+ ignores ./.venv then", but it only became true in Pipenv 2023.11.14. Every earlier release uses an existing ./.venvdirectory no matter what these variables say:
2022.x through 2023.10.24, Project.get_location_for_virtualenv: # If .venv in project root is a directory, use it. / if os.path.isdir(dot_venv): return dot_venv. is_venv_in_project() is never consulted once .venv exists.
2023.11.14+: if not os.path.exists(dot_venv) or os.path.isdir(dot_venv): if self.is_venv_in_project(): return dot_venv … so an explicit False falls through to WORKON_HOME. This is the behaviour Fix Pipenv venv discovery order (#334, #384) #388 modelled.
2018.11.26: PIPENV_VENV_IN_PROJECT = bool(os.environ.get("PIPENV_VENV_IN_PROJECT")), so "0" and "false" are truthy (in project). PIPENV_NO_VENV_IN_PROJECT doesn't exist. On top of that, an existing .venv directory always wins.
So on Pipenv ≤ 2023.10.24, a project with a ./.venv and either variable set gets the wrong venv patched.
Impact
pipenv run / pipenv shell keep importing the unpatched package from ./.venv, while scan --mode agent reports 1 of 1 targeted patch applied and exits 0.
socket-patch vex then attests not_affected / inline_mitigations_already_exist for a vulnerability that is still live in the interpreter Pipenv actually runs.
This is the same shape of regression as #529, which was the auto-detected .venv on 2018–2026.1. #529's fix returns both venvs when nothing explicit is set, but the explicit-false arm still returns WORKON_HOME only.
Repro
Linux, CPython 3.11 (3.8 for 2018.11.26), main 045d7ec. The patch API is a local mock serving a patched six 1.16.0 (batch / view / blob routes, SOCKET_PROXY_URL=http://127.0.0.1:8765). Any agent-mode patch for a package in the project shows the same thing.
export WORKON_HOME=$PWD/venvs
mkdir p &&cd p
printf'[[source]]\nurl = "https://pypi.org/simple"\nverify_ssl = true\nname = "pypi"\n\n[packages]\nsix = "==1.16.0"\n'> Pipfile
pipenv install # venv under $WORKON_HOME
PIPENV_VENV_IN_PROJECT=1 pipenv sync # ./.venv venv (e.g. a CI cache or an earlier setting)export PIPENV_VENV_IN_PROJECT=0 # or PIPENV_NO_VENV_IN_PROJECT=1
pipenv --venv # 2022.12.19: …/p/.venv
socket-patch scan --mode agent --yes # Summary: 1 of 1 targeted patch applied … (exit 0)
grep -c SOCKET_PATCHED .venv/lib/python3*/site-packages/six.py # 0 <- the venv Pipenv uses
grep -c SOCKET_PATCHED $WORKON_HOME/p-*/lib/python3*/site-packages/six.py # 1
pipenv run python -c "import six; print(hasattr(six,'SOCKET_PATCHED'))"# False
socket-patch vex --product pkg:pypi/x@1 --output vex.json # status not_affected <- false
fail: the global interpreter's six was patched (#504 shape)
The Pipenv boundary comes from the upstream wheels: get_location_for_virtualenv returns an existing .venv directory unconditionally in 2023.2.4, 2023.6.26, 2023.10.3, 2023.10.20 and 2023.10.24. It gates on is_venv_in_project() from 2023.11.14 on (also checked 2023.11.15, 2023.11.17, 2023.12.0 and 2023.12.1). macOS and Windows weren't probed, but this is a pure discovery decision with no OS-specific code.
First bad
socket-patch 4.0.0 (npm) on the same 2022.12.19 project patches ./.venv (pipenv run gets patched six), so it passes.
crates/socket-patch-core/src/crawlers/python_crawler.rs:697 (the doc comment's "Pipenv 2023+ ignores ./.venv then") and :717-724 in pipenv_project_site_packages: if in_project.is_none() { results.extend(in_tree); } drops ./.venv for Some(false).
crates/socket-patch-core/src/crawlers/python_crawler.rs test pipenv_venv_in_project_settings_decide_about_dot_venv pins the 2023.11.14+ behaviour as the only one.
[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
Since #388 (
ccd43f5, the #334 fix), Pipenv venv discovery treats an explicit "not in project" setting as "ignore./.venv". That coversPIPENV_VENV_IN_PROJECT=0/false/off/noandPIPENV_NO_VENV_IN_PROJECT=1. In that case socket-patch returns only the$WORKON_HOMEvenv. The doc comment says this is because "Pipenv 2023+ ignores./.venvthen", but it only became true in Pipenv 2023.11.14. Every earlier release uses an existing./.venvdirectory no matter what these variables say:Project.get_location_for_virtualenv:# If .venv in project root is a directory, use it./if os.path.isdir(dot_venv): return dot_venv.is_venv_in_project()is never consulted once.venvexists.if not os.path.exists(dot_venv) or os.path.isdir(dot_venv): if self.is_venv_in_project(): return dot_venv… so an explicitFalsefalls through to WORKON_HOME. This is the behaviour Fix Pipenv venv discovery order (#334, #384) #388 modelled.PIPENV_VENV_IN_PROJECT = bool(os.environ.get("PIPENV_VENV_IN_PROJECT")), so"0"and"false"are truthy (in project).PIPENV_NO_VENV_IN_PROJECTdoesn't exist. On top of that, an existing.venvdirectory always wins.So on Pipenv ≤ 2023.10.24, a project with a
./.venvand either variable set gets the wrong venv patched.Impact
pipenv run/pipenv shellkeep importing the unpatched package from./.venv, whilescan --mode agentreports1 of 1 targeted patch appliedand exits 0.socket-patch vexthen attestsnot_affected/inline_mitigations_already_existfor a vulnerability that is still live in the interpreter Pipenv actually runs../.venv), discovery finds nothing and falls back to the global interpreter. On the sandbox that patched/usr/lib/python3/dist-packages/six.pyin place, which is the Agent-mode scan in a Pipenv project without a Pipenv venv patches the system Python's site-packages in place instead of the project's venv/ (regression from #388) #504 symptom triggered through a different root cause.This is the same shape of regression as #529, which was the auto-detected
.venvon 2018–2026.1. #529's fix returns both venvs when nothing explicit is set, but the explicit-false arm still returns WORKON_HOME only.Repro
Linux, CPython 3.11 (3.8 for 2018.11.26), main
045d7ec. The patch API is a local mock serving a patchedsix 1.16.0(batch / view / blob routes,SOCKET_PROXY_URL=http://127.0.0.1:8765). Any agent-mode patch for a package in the project shows the same thing.Expected vs actual
.venvsubject toPIPENV_VENV_IN_PROJECT…". On Pipenv ≤ 2023.10.24 that venv is./.venv. Since the CLI can't know the Pipenv version without running it, the safe answer is the one Agent mode patches only the WORKON_HOME venv when a Pipenv project also has an auto-detected ./.venv, so Pipenv 2018–2026.1 keep running the unpatched .venv and VEX attests not_affected (regression from #388) #529 already uses for the auto-detected case: return WORKON_HOME and./.venvfor an explicit "not in project" too. Patching an extra.venvthat 2023.11.14+ ignores is harmless; missing the live one isn't../.venvstays unpatched, exit 0, and VEX saysnot_affected.OS × version (Linux, agent mode,
.venv+ WORKON venv, each cell run twice unless noted)pipenv --venv.venvpipenv runPIPENV_VENV_IN_PROJECT=0.venvPIPENV_NO_VENV_IN_PROJECT=1(1×).venvPIPENV_VENV_IN_PROJECT=0.venvPIPENV_NO_VENV_IN_PROJECT=1(1×).venvPIPENV_VENV_IN_PROJECT=0(1×).venvPIPENV_VENV_IN_PROJECT=false(1×).venvPIPENV_NO_VENV_IN_PROJECT=1(1×).venvPIPENV_VENV_IN_PROJECT=0PIPENV_VENV_IN_PROJECT=0PIPENV_VENV_IN_PROJECT=0/PIPENV_NO_VENV_IN_PROJECT=1PIPENV_VENV_IN_PROJECT=0, no WORKON venv.venvThe Pipenv boundary comes from the upstream wheels:
get_location_for_virtualenvreturns an existing.venvdirectory unconditionally in 2023.2.4, 2023.6.26, 2023.10.3, 2023.10.20 and 2023.10.24. It gates onis_venv_in_project()from 2023.11.14 on (also checked 2023.11.15, 2023.11.17, 2023.12.0 and 2023.12.1). macOS and Windows weren't probed, but this is a pure discovery decision with no OS-specific code.First bad
socket-patch4.0.0 (npm) on the same 2022.12.19 project patches./.venv(pipenv rungets patched six), so it passes.045d7ecfails. The explicit-false arm was introduced byccd43f5"Fix Pipenv venv discovery order (Agent-mode scan skips Pipenv's out-of-tree venv when the project has a stray venv/ directory or a .venv with PIPENV_VENV_IN_PROJECT=0, and still exits 0 #334, Agent-mode scan patches the activated VIRTUAL_ENV even when PIPENV_IGNORE_VIRTUALENVS or PIPENV_ACTIVE tells Pipenv to ignore it, leaving the Pipenv venv unpatched with exit 0 #384) (Fix Pipenv venv discovery order (#334, #384) #388)". Agent-mode scan skips Pipenv's out-of-tree venv when the project has a stray venv/ directory or a .venv with PIPENV_VENV_IN_PROJECT=0, and still exits 0 #334's repro only covered 2023.12.1 and 2026.8.0, where skipping.venvis right.Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:697(the doc comment's "Pipenv 2023+ ignores./.venvthen") and:717-724inpipenv_project_site_packages:if in_project.is_none() { results.extend(in_tree); }drops./.venvforSome(false).crates/socket-patch-core/src/crawlers/python_crawler.rstestpipenv_venv_in_project_settings_decide_about_dot_venvpins the 2023.11.14+ behaviour as the only one.