Scrub the guest environment for the process backend - #285
Merged
Conversation
The process backend launched its guest with subprocess.Popen and no env=, so the child inherited the supervisor's entire os.environ. Any credential held by the host process -- AWS keys, API tokens, session secrets -- was readable by guest code with a plain os.environ.get(), which defeats the point of the boundary regardless of how well seccomp and Landlock confine the rest of the process. Build the child environment from a fixed allow-list instead: the variables the interpreter needs to boot and to resolve pyisolate (PYTHONPATH, PYTHONHOME, LD_LIBRARY_PATH), plus locale and TMPDIR. PATH is set to a fixed minimal value rather than forwarded, since the child is launched by absolute path and the host's PATH only leaks machine layout. LD_LIBRARY_PATH is forwarded deliberately: conda and custom CPython builds need it to find libpython, and dropping it stops the child from starting. Callers that need to hand the guest real configuration can pass env=, which is merged last so an explicit value always wins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ebvMQ3vLxdK3joymz6Feg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
ProcessSandboxlaunched its guest withsubprocess.Popen(...)and noenv=, so the child inherited the supervisor's entireos.environ. Confirmed on this branch's parent commit:Any credential held by the host process —
AWS_SECRET_ACCESS_KEY,GITHUB_TOKEN, session secrets — was readable by guest code with a one-lineos.environ.get(). This is the mode SECURITY.md designates as the security boundary, and no amount of seccomp/Landlock confinement helps once the secret is already inside the guest's address space.The change
Build the child environment from a fixed allow-list rather than handing over a copy of the host's:
PYTHONPATH,PYTHONHOME,LD_LIBRARY_PATH— module and shared-library resolutionLANG,LC_ALL,LC_CTYPE,PYTHONIOENCODING,PYTHONUTF8— text encodingTMPDIR— the guest should land where the host chose, which may be the only writable directory its policy grantsPATH— set to a fixed/usr/local/bin:/usr/bin:/bin, not forwarded. The child is launched by absolute path (sys.executable), soPATHis never consulted to start it; forwarding the host's value only leaks machine layout.An allow-list rather than a deny-list, so a credential variable nobody anticipated is withheld by default.
LD_LIBRARY_PATHis forwarded deliberately: conda and custom CPython builds need it to locatelibpython, and dropping it would stop the child from starting at all. It names library directories, not secrets.Callers that need to give the guest real configuration pass
env=, merged last so an explicit value always wins.Tests
Six new tests in
tests/test_process_backend.py: the secret no longer crosses the boundary, the env is a subset of the allow-list (so future variables are withheld),PATHis the fixed value rather than the supervisor's,build_child_envfilters correctly given a synthetic source,extraoverrides, and an explicitenv=reaches the guest.Full suite: 511 passed, 6 skipped (was 505 before these six). flake8 clean, black/isort applied.
SECURITY.md §2 gains this as guarantee 8.
Scope
One orthogonal fix; quota forwarding and the fail-open filesystem default are separate branches.
Generated by Claude Code