Skip to content

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

Description

[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).

Summary

find_local_venv_site_packages (crates/socket-patch-core/src/crawlers/python_crawler.rs:276-284) takes VIRTUAL_ENV first and returns as soon as it has a site-packages. Pipenv only uses VIRTUAL_ENV when neither PIPENV_IGNORE_VIRTUALENVS nor PIPENV_ACTIVE is set (pipenv/environments.py: if "PIPENV_ACTIVE" not in os.environ and not self.PIPENV_IGNORE_VIRTUALENVS: self.PIPENV_VIRTUALENV = os.environ.get("VIRTUAL_ENV"), the same on 2018.11.26, 2023.12.1 and 2026.8.0). The crawler ignores both variables:

  • PIPENV_IGNORE_VIRTUALENVS=1 with some other venv activated. This is Pipenv's documented switch for keeping an activated venv from hijacking the project. Pipenv uses $WORKON_HOME/<name>-<hash>, but socket-patch patches the activated venv.
  • PIPENV_ACTIVE=1: you ran pipenv shell in project A, then cd into project B and ran socket-patch there. VIRTUAL_ENV still points at A's venv, and Pipenv in B deliberately ignores it. socket-patch patches project A's venv from project B.

Both cases report added / applied, status: success and exit 0. The venv that pipenv run / pipenv sync use in the project stays unpatched, and an unrelated venv gets modified. In hosted and vendored mode, the stale-install warning (vendor/pypi.rs:611, pipenv_stale_install_warning, which calls the same function) is judged against the wrong venv.

(socket-patch itself sets PIPENV_IGNORE_VIRTUALENVS=1 when it runs pipenv in utils/pipenv.rs:80, so the codebase already relies on this variable meaning "don't use VIRTUAL_ENV".)

This is related to #334 (stray venv/ or .venv shadowing Pipenv's venv), but it's a different trigger and needs a different fix. Pipenv does honour VIRTUAL_ENV by default, so moving Pipenv's placement ahead of ./.venv / ./venv for #334 won't fix it. The VIRTUAL_ENV probe itself has to respect the two Pipenv opt-outs when the project is a Pipenv project.

Impact

Agent mode reports success while the project's real venv keeps the vulnerable bytes, and it writes patched files into a venv the user didn't target (another project's venv, or a tool venv). CI that gates on the exit code passes. PIPENV_IGNORE_VIRTUALENVS=1 is common in shells and CI images that keep a tool venv activated. The pipenv shell → cd flow is everyday developer use.

Repro (Linux; mock patch API or a local manifest)

mkdir proj && cd proj
cat > Pipfile <<'EOF'
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
six = "==1.16.0"
EOF
PIPENV_IGNORE_VIRTUALENVS=1 pipenv install        # -> ~/.local/share/virtualenvs/proj-XXXX
python3 -m venv /tmp/other && /tmp/other/bin/pip install six==1.16.0
export VIRTUAL_ENV=/tmp/other PIPENV_IGNORE_VIRTUALENVS=1   # or: PIPENV_ACTIVE=1 instead of IGNORE
pipenv --venv                                      # ~/.local/share/virtualenvs/proj-XXXX
SOCKET_API_URL=http://127.0.0.1:18080 SOCKET_API_TOKEN=fake SOCKET_ORG_SLUG=test-org \
  socket-patch scan --mode agent --json --yes; echo "exit=$?"
# status: success, patches: [{action: added}], exit=0
pipenv run python -c "import six; print(six.__file__, hasattr(six, 'SOCKET_PATCHED'))"
# ~/.local/share/virtualenvs/proj-XXXX/.../six.py False      <- project venv unpatched
/tmp/other/bin/python -c "import six; print(hasattr(six, 'SOCKET_PATCHED'))"
# True                                                        <- unrelated venv patched

The same thing happens with socket-patch apply --offline against a local .socket/manifest.json (reproduced twice locally on Linux 2023.12.1 and 2026.8.0, and once more per cell in the probe).

Expected vs actual

  • Expected: docs/testing/pipenv-compatibility.md ("Out-of-tree venv naming") says the crawler reproduces Pipenv's placement "so a bare scan/rollback sees the project's venv; before, it fell through to the global interpreter and reported success while the venv stayed unpatched". The project's venv is the one pipenv --venv reports. CLI_CONTRACT.md: status: success / exit 0 means the requested patches are in place.
  • Actual: it patches whichever venv VIRTUAL_ENV names, even when Pipenv has been told to ignore it. It exits 0.

Control: with VIRTUAL_ENV set and neither opt-out set, Pipenv 2023.12.1 / 2026.8.0 also use the activated venv, so socket-patch is correct there (pass).

OS × version

OS Pipenv IGNORE_VIRTUALENVS=1 PIPENV_ACTIVE=1 VIRTUAL_ENV only (control) no VIRTUAL_ENV (control)
Linux 2023.12.1 fail: project venv UNPATCHED, other venv patched, exit 0 fail (same) pass (Pipenv uses it too) pass
Linux 2026.8.0 fail fail pass pass
macOS 2023.12.1 fail fail pass pass
macOS 2026.8.0 fail fail pass pass
Windows 2023.12.1 fail fail pass pass
Windows 2026.8.0 fail fail pass pass
Linux 2018.11.26 (py3.8) fail fail ambiguous (pipenv --venv names VIRTUAL_ENV, but pipenv run imports from the WORKON_HOME venv) pass

First bad version

Not bisected. This isn't a regression: the unconditional VIRTUAL_ENV early return predates Pipenv venv discovery (added in 4.0.0), and neither PIPENV_IGNORE_VIRTUALENVS nor PIPENV_ACTIVE is read anywhere in the crawler.

Suspect code

  • crates/socket-patch-core/src/crawlers/python_crawler.rs:276-284: the unconditional VIRTUAL_ENV early return.
  • crates/socket-patch-core/src/vendor/pypi.rs:611: the stale-install warning goes through the same discovery.

Probe run: https://github.com/SocketDev/socket-patch/actions/runs/36779636041 (6 jobs: ubuntu / macos / windows × 2023.12.1 / 2026.8.0, scan --mode agent against a mock patch API). 2018.11.26 was checked locally on Linux.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions