Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

With the same release in user site-packages and a system site-packages dir, agent mode patches the shadowed system copy, leaves the copy Python imports unpatched, and VEX attests it (worse since #452: now hits apt-installed packages)

Chiusa
#501 3 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
58/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
python, rust
Ambito
cli, security

Direzione di ricerca

Start with the Linux reproduction, then read crates/socket-patch-core/src/crawlers/python_crawler.rs:1316 and the well-known-directory scan, followed by crates/socket-patch-cli/src/commands/apply.rs:1861 and :1888-1898. Verify behavior with the scan, apply, vex, and rollback commands from the report. Done means the interpreter-loaded copy is patched, duplicate installs are handled consistently, and VEX does not attest an unpatched loaded copy.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

agent:claimed agent:triaged bug bughunt pm:poetry priority:p1

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

Summary

When one PyPI release (here six==1.16.0) is installed both in the user site (~/.local/lib/python3.X/site-packages, from pip install --user) and in a system site dir (/usr/lib/python3/dist-packages from apt, or /usr/local/lib/python3.X/dist-packages from pip), every global-scope agent run patches the system copy only:

  • scan -g --mode agent, and
  • a plain project scan --mode agent in a Poetry project with virtualenvs.create = false (or any layout where the project venv isn't found and the crawler falls back to the global interpreter, e.g. #476).

Python imports the user-site copy, because sys.path puts user site before the system dirs. That copy stays unpatched. The run reports success, apply re-runs say already_patched, and vex attests not_affected / inline_mitigations_already_exist. On Debian/Ubuntu the write also lands in a dpkg-owned file (/usr/lib/python3/dist-packages/six.py).

Root cause, two parts:

  1. get_global_python_site_packages orders paths as site.getsitepackages() first and site.getusersitepackages() last (crates/socket-patch-core/src/crawlers/python_crawler.rs:1316, plus the well-known-dir scan after it, which also adds ~/.local last). That's the reverse of Python's import precedence.
  2. Apply keeps PyPI on a "one representative" contract and patches only pkg_paths.first() (crates/socket-patch-cli/src/commands/apply.rs:1861 and :1888-1898). The comment there assumes "their crawlers resolve one install dir per version", which doesn't hold in global scope. rollback does fan out to every copy (it reports rolledBack: 1, alreadyOriginal: 1), so the two commands disagree on how many copies exist.

#452 (2035cbb) made this much easier to hit. Before it, apt's .egg-info installs were invisible, so with apt six plus a user-site six the user copy was the only candidate and got patched correctly. Since #452 the apt copy is listed first and wins. With two dist-info copies (/usr/local/.../dist-packages plus user site), the bug already exists in v4.0.0.

Impact

  • A false VEX attestation. The imported copy is still vulnerable, and nothing warns.
  • On Debian/Ubuntu (apt ships six, requests, urllib3, idna, certifi, … as egg-info), -g writes into dpkg-owned files while leaving the copy actually in use unpatched.
  • Poetry users with virtualenvs.create = false (common in Docker images and CI) get the same result from a plain project scan.

Repro (Linux, Debian bookworm image, Python 3.11, Poetry 2.5.1)

The mock patch API serves one agent patch for pkg:pypi/[email protected] that appends SOCKET_PATCHED = 1 to six.py. It uses the same routes as tests/vex_pypi_real_common/mod.rs, plus /patches/blob/<hash>. $A = --api-url http://127.0.0.1:18080 --api-token fake --org test-org --patch-server-url http://127.0.0.1:18080.

# apt's python3-six 1.16.0 egg-info is in /usr/lib/python3/dist-packages
python3 -m pip install --user --ignore-installed --break-system-packages six==1.16.0
python3 -c 'import six; print(six.__file__)'   # -> /root/.local/lib/python3.11/site-packages/six.py

mkdir nc && cd nc
cat > pyproject.toml <<'EOF'
[tool.poetry]
name = "demo"
version = "0.1.0"
description = ""
authors = ["x <x@x>"]
package-mode = false
[tool.poetry.dependencies]
python = "^3.11"
six = "1.16.0"
EOF
printf '[virtualenvs]\ncreate = false\n' > poetry.toml
poetry lock && poetry install           # "No dependencies to install or update"
poetry run python -c 'import six; print(six.__file__)'   # user-site copy

socket-patch scan --mode agent --yes $A      # success (same with: mkdir g && cd g && socket-patch scan -g --mode agent --yes $A)
grep -c SOCKET_PATCHED /usr/lib/python3/dist-packages/six.py               # 1  <- shadowed copy patched
grep -c SOCKET_PATCHED ~/.local/lib/python3.11/site-packages/six.py        # 0  <- imported copy unpatched
python3 -c 'import six; print(hasattr(six, "SOCKET_PATCHED"))'           # False
socket-patch apply --json $A               # skipped / already_patched
socket-patch vex --product pkg:pypi/[email protected] --json --output v.json $A   # not_affected / inline_mitigations_already_exist
socket-patch rollback --json $A            # rolledBack: 1, alreadyOriginal: 1 (it sees both copies)

It reproduces 2/2 for each of: scan -g --mode agent, vex -g, and the Poetry create = false project scan.

Expected vs actual

  • Expected: agent mode patches the copy the interpreter loads, or every installed copy as gem/npm do (apply.rs comment: "leaving the other store pristine is a silent false 'applied'"). VEX only attests when the loaded copy is patched. CLI_CONTRACT.md's VEX rule is that a statement is emitted only for a patch that is actually applied.
  • Actual: the shadowed copy is patched, the loaded copy isn't, and VEX attests anyway.

OS × version

OS Copies present Binary Result
Linux apt egg-info + user site main 61cfb9b, 2035cbb (#452) fail: apt copy patched
Linux apt egg-info + user site v4.0.0, 2035cbb^ pass: user copy patched
Linux /usr/local/.../dist-packages dist-info + user site main, 2035cbb^, v4.0.0 fail: /usr/local copy patched
Linux /usr/local/.../dist-packages only main pass
macOS / Windows — — untested (probe branches blocked). macOS user site (~/Library/Python/3.X/lib/python/site-packages) has the same ordering, so it's likely affected.

Poetry versions: 2.5.1 (create = false, user-site copy kept). With create = false, Poetry 1.8.5 / 2.0.1 / 2.2.1 in this image reinstalled six into /usr/local/lib/python3.11/dist-packages, which precedes apt on sys.path, so those didn't reproduce until a user-site copy was re-added. The -g path doesn't depend on the Poetry version.

First bad commit

For the apt + user-site case: 2035cbb ("Fix Python crawler missing .egg-info installs (#447) (#452)"), bisected with release builds of 2035cbb^ and 2035cbb, 2/2 each. For two dist-info copies, it never worked (v4.0.0 fails).

Suspect code

  • crates/socket-patch-core/src/crawlers/python_crawler.rs:1316 (user site printed last) and the well-known-dir order right after it.
  • crates/socket-patch-cli/src/commands/apply.rs:1861, :1888-1898 (PyPI patches only pkg_paths.first()).
  • Related but distinct: #409 (--system-site-packages venv, hosted), #476 (Poetry venv not found, so this fallback is reached).
Lingua principale
Rust
Stelle
8
Fork
0
Merge medio
1g 1h
PR unite (30g)
257

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di SocketDev/socket-patch

Tutte le issue di SocketDev/socket-patch

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.