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)
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
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] 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 agentin a Poetry project withvirtualenvs.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:
get_global_python_site_packagesorders paths assite.getsitepackages()first andsite.getusersitepackages()last (crates/socket-patch-core/src/crawlers/python_crawler.rs:1316, plus the well-known-dir scan after it, which also adds~/.locallast). That's the reverse of Python's import precedence.- Apply keeps PyPI on a "one representative" contract and patches only
pkg_paths.first()(crates/socket-patch-cli/src/commands/apply.rs:1861and:1888-1898). The comment there assumes "their crawlers resolve one install dir per version", which doesn't hold in global scope.rollbackdoes fan out to every copy (it reportsrolledBack: 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),-gwrites 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 projectscan.
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.rscomment: "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 onlypkg_paths.first()).- Related but distinct: #409 (
--system-site-packagesvenv, 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
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di SocketDev/socket-patch
-
agent:triaged bug bughunt pm:npm priority:p1
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
SocketDev/socket-patch#1127 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
agent:triaged bug bughunt pm:bundler priority:p1
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
SocketDev/socket-patch#1125 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
agent:triaged bug bughunt pm:pipenv priority:p1
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 85/100
SocketDev/socket-patch#1122 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
agent:triaged bug bughunt pm:npm priority:p1
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
SocketDev/socket-patch#1072 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
agent:triaged arch-audit bug priority:p3
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
SocketDev/socket-patch#1062 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di SocketDev/socket-patch
Issue simili
-
[Feature] 设置里面的同步功能Apertaenhancement user-priority/P2
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
containers/aardvark-dns#743 ·