Skip to content

Hosted Hatch rewrite leaves an existing Hatch environment unpatched with no stale-install warning, and vex still attests not_affected #335

Description

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

Summary

On a Hatch project whose default environment already exists (the normal state for any developer or warm CI cache), socket-patch scan --mode hosted rewrites six==1.16.0 to six @ <hosted wheel>#sha256=… and reports success with no warnings. But the Hatch environment is never actually patched:

  1. On the next hatch run, Hatch notices the dependency hash changed and runs pip install "six @ <url>". pip downloads the wheel, sees six 1.16.0 is already installed, and keeps the installed bytes (it exits 0 and prints nothing).
  2. Hatch then records the new dependency hash as synced, so later hatch runs never retry. The env stays unpatched until someone runs hatch env remove / hatch env prune.
  3. socket-patch has a redirect_pypi_stale_install check for exactly this situation, but it never sees Hatch's environment. Hatch keeps envs out of tree ($HATCH_DATA_DIR/env/virtual/<project>/<hash>/<env>, or the platform data dir by default), and find_local_venv_site_packages only probes VIRTUAL_ENV, .venv/venv, and the Poetry and Pipenv out-of-tree venvs. The warning fires only when the user happens to scan with VIRTUAL_ENV set to the Hatch env.
  4. socket-patch vex run from the project root emits not_affected for the vulnerability, even though the environment hatch run uses holds the unpatched file. With VIRTUAL_ENV pointing at the Hatch env, the same vex omits it (not_applied), which is correct.

The installer = "uv" flavour is not affected: uv reinstalls the direct-URL wheel. A fresh environment is also fine. The problem is pip-installer Hatch envs that already exist, and that's the default.

Related, same root cause: scan --mode agent on a Hatch project applies 0 patches to the Hatch env (it crawls the PATH interpreter instead) and exits 1 partial_failure. The Poetry siblings of this are #327 and #329.

Impact

  • Users are told the dependency is patched, and a VEX attestation claims not_affected, while hatch run / hatch test / hatch shell keep executing the vulnerable code.
  • Nothing prompts the remedy (hatch env remove <env>, or hatch env prune).

Repro (Linux; macOS and Windows identical, see probe)

Uses a local mock of the patch API (the same shape as crates/socket-patch-cli/tests/vex_pypi_real_common: six 1.16.0 with a SOCKET_PATCHED marker). The full mock and driver are in the probe workflow linked below.

pip install hatch==1.18.1
mkdir app && cd app && mkdir -p src/app && touch src/app/__init__.py
cat > pyproject.toml <<'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "app"
version = "0.1.0"
dependencies = ["six==1.16.0"]

[tool.hatch.build.targets.wheel]
packages = ["src/app"]
EOF
hatch env create                                  # six 1.16.0 from PyPI
socket-patch scan --mode hosted --json --yes --api-url $API --api-token x --org test-org --patch-server-url $API --ecosystems pypi
#  -> status success, redirected 1, warnings []
hatch run python -c "import six; print(hasattr(six,'SOCKET_PATCHED'))"   # False
hatch run python -c "import six; print(hasattr(six,'SOCKET_PATCHED'))"   # False (hash now recorded as synced)
socket-patch vex --product pkg:pypi/app@0.1.0 --api-url $API --patch-server-url $API --org test-org --api-token x
#  -> 1 statement, status not_affected, "Patched via Socket patch … (redirected)"
VIRTUAL_ENV=$(hatch env find default) socket-patch scan --mode hosted --json --yes …
#  -> warnings: [redirect_pypi_stale_install]   <- only when the env is named explicitly
hatch env remove default
hatch run python -c "import six; print(hasattr(six,'SOCKET_PATCHED'))"   # True

Underlying pip behaviour, inside the Hatch env (pip 26.2.1): pip install "six @ http://…/six-1.16.0-py2.py3-none-any.whl#sha256=…" prints Collecting…/Downloading…, exits 0, and leaves six.py unchanged.

Expected vs actual

  • Expected: consistent with the PyPI stale-install contract in README.md ("Socket Patch warns (redirect_pypi_stale_install …) when a venv still holds the upstream release, with the verified remedy") and with how Poetry and Pipenv out-of-tree venvs are handled in find_local_venv_site_packages. A hosted Hatch scan should find the project's Hatch environments and warn with a Hatch-specific remedy (hatch env remove <env> / hatch env prune, not "reinstall from the rewritten lock", which does nothing here). And vex should not attest not_affected while the Hatch env holds the original bytes.
  • Actual: success, warnings: [], the env stays unpatched indefinitely, and vex attests not_affected.

OS × Hatch version (hosted, pip installer, [project] dependencies)

1.7.0 1.9.7 1.16.5 1.18.1
Linux (sandbox + ubuntu-latest) repro repro repro repro
macOS (macos-latest) repro repro repro repro
Windows (windows-latest) repro repro repro repro

Also reproduced on Linux with [tool.hatch.envs.default] dependencies (env flavour) on 1.16.5. Does not reproduce with installer = "uv" (1.16.5 and 1.18.1: patched on the next hatch run) or on a fresh environment.

First bad

Present since Hatch support landed in 649d457 (#244). No release ships Hatch support yet (v4.0.0 predates it), so there's nothing to bisect.

Suspect code

  • crates/socket-patch-core/src/crawlers/python_crawler.rs:273 find_local_venv_site_packages: no Hatch environment discovery (compare the Poetry and Pipenv arms at :297 and :307).
  • crates/socket-patch-cli/src/commands/scan/hosted/python.rs:57: the stale-install judgment only sees those site-packages. Its generic remedy text (:127) doesn't fit Hatch.
  • VEX's installed-basis lookup uses the same discovery, so it falls back to the pin basis.

Probe

https://github.com/SocketDev/socket-patch/actions/runs/36740025279 (ubuntu, macos and windows × Hatch 1.7.0 / 1.9.7 / 1.16.5 / 1.18.1, all reproduce).

Activity

  1. mikolalysenko commented on Sep 30, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged: priority:p1 (PyPI family / Hatch). Not a duplicate, and no existing fix PR. This is related to the venv-discovery cluster (#327 / #334, in flight in #330). The missing piece here is different: there is no Hatch env discovery at all ($HATCH_DATA_DIR/env/virtual/<project>/<hash>/<env>), and the stale-install remedy text doesn't fit Hatch. Reordering the existing probes won't fix it, so it's kept as its own work item.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-triage on main 2463257 (#277, the v5 workflow), Linux, Hatch 1.18.1, same mock patch API. Still reproduces: hosted scan success, redirected: 1, warnings: []; two hatch runs both keep the unpatched six.py; a re-scan gives no warning; vex from the project root attests not_affected.

    New: vendored mode has the same hole, and it's worse. Its warning is missing even when the Hatch env is named explicitly:

    hatch env create
    VIRTUAL_ENV=$(hatch env find default) socket-patch scan --mode vendored --json --yes …
    #  -> exit 0, success; vendor.events: [{"action":"applied","files":[{"path":"six.py","verified":true}]},
    #                                      {"action":"skipped","errorCode":"vendor_prebuilt_downloaded"}]
    #  -> no warnings at all. pyproject.toml now pins six @ {root:uri}/.socket/vendor/pypi/<uuid>/six-…whl#sha256=…
    grep -c SOCKET_PATCHED <hatch env>/lib/python3.11/site-packages/six.py   # 0, despite the "applied … verified" event
    hatch run python -c "import six; print(hasattr(six,'SOCKET_PATCHED'))"   # "Syncing dependencies" … False (pip keeps the installed 1.16.0)
    socket-patch vex --product pkg:pypi/app@0.1.0 …                           # not_affected "(vendored)", no warning
    VIRTUAL_ENV=… socket-patch vex …   # not_affected, plus a warning telling the user to "re-run your package manager's install to resync it". For Hatch that doesn't help (hatch run / hatch env create keep the bytes).

    Reproduced twice (two fresh projects). On the vendored side the only stale-install probe is pipenv_stale_install_warning (crates/socket-patch-core/src/vendor/pypi.rs:606, called only for the Pipenv flavour at :880), so the Hatch flavour (vendor/pypi_hatch.rs) never checks the installed tree. A hosted-only fix (adding Hatch env discovery to find_local_venv_site_packages, crawlers/python_crawler.rs:274) would therefore leave vendored Hatch silent. Mentioning it here instead of filing a twin, because the user-visible failure and the remedy (hatch env remove <env> / hatch env prune) are the same. Happy to split it out if you'd rather track it separately.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 2, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-triage on main 1169ae6, Linux, same mock patch API. Still reproduces on Hatch 1.18.1 with the pip installer: hosted scan success, warnings: [], and the existing env keeps the upstream six.py.

    New: on Hatch 1.10–1.15, the uv installer is affected too. The issue body says "The uv installer and fresh envs are fine". That holds from Hatch 1.16 on, but not for older 1.x. Before 1.16, Hatch's dependency check accepts the installed six 1.16.0 as satisfying six @ <url>#sha256=…, so it never syncs at all ("Checking dependencies" with no "Syncing dependencies" line):

    # pyproject: dependencies = ["six==1.16.0"]; [tool.hatch.envs.uvenv] installer = "uv"
    hatch -e uvenv run python -c 1                 # env created with upstream six
    socket-patch scan --mode hosted --yes --json … # success, warnings: [], pyproject -> six @ <url>#sha256=…
    hatch -e uvenv run python -c 'import six; print(hasattr(six, "SOCKET_PATCHED"))'
    Hatch (uv installer, existing env) output
    1.10.0 / 1.12.0 (2×) / 1.13.0 / 1.14.1 / 1.15.1 Checking dependencies → False (unpatched)
    1.16.5 / 1.17.0 / 1.18.1 Checking dependencies, Syncing dependencies → True

    Fresh envs are patched on every version. The fix still belongs to the same missing Hatch-env discovery and stale-install warning, so I'm adding this here rather than filing a twin. Any fix's tests should include a pre-1.16 uv env, not just pip.


    Generated by Claude Code

  4. mikolalysenko commented on Oct 3, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: the PyPI installed-env discovery has no model of Hatch's out-of-tree environments, so stale-install checks and VEX never see the env hatch run uses). Branch: agent/fix-hatch-env-discovery. Claim-ID: 2026-10-03T14:21:17Z-3cbaf3


    Generated by Claude Code

  5. mikolalysenko commented on Oct 3, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #700


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions