[RIP-SEC] workspace-write `.git` carveout does not cover nested repositories, so a sandboxed agent can plant a git hook that runs unsandboxed later

Open 💬 0 comments Opened Aug 5, 2026 by scadastrangelove

Summary

Under the workspace-write sandbox, the read-only carveout for .git/.codex/.agents — which exists
to stop a sandboxed agent from planting a git hook / config that a later unsandboxed operation would
execute — is applied only to the writable root's top-level metadata directory. A git repository
nested inside the workspace (submodule, vendored dependency, fixture repo) has its own .git
that is not the top-level one and is fully writable. A sandboxed agent can write
<workspace>/vendor/sub/.git/hooks/pre-commit, which git executes the next time a git operation runs
in that subdirectory outside the sandbox.

I understand the root-level scope is intentional (PR #19846/#19847/#19852, "to avoid blocking
legitimate nested repositories"). This report is about the consequence of that choice, not the
writability itself: the deliberate non-protection of nested repos defeats the anti-hook-escape control
the top-level carveout provides.

Where

codex-rs/protocol/src/permissions.rsmetadata_child_of_writable_root inspects only
relative_path.components().next() (the first component below a writable root), so
vendor/sub/.git/... is not recognized as protected metadata. Present on current main.

Reproduction (macOS / Seatbelt)

Real codex binary, codex sandbox -c sandbox_mode='"workspace-write"', from a workspace containing
a top-level .git and a nested vendor/sub/.git:

# control: write into the top-level .git
$ codex sandbox -c sandbox_mode='"workspace-write"' /bin/sh -c 'echo x > .git/hooks/rip-canary'
/bin/sh: .git/hooks/rip-canary: Operation not permitted        # denied — carveout works

# attack: write into a nested repo's .git
$ codex sandbox -c sandbox_mode='"workspace-write"' /bin/sh -c 'echo PWNED > vendor/sub/.git/hooks/rip-canary'
$ cat vendor/sub/.git/hooks/rip-canary
PWNED                                                          # landed in the nested .git (bypass)

Impact

A sandboxed agent can plant executable git hooks in any nested repository inside the workspace; those
hooks run with the user's privileges the next time a git operation touches that nested repo outside
the sandbox. Deferred/conditional on a later out-of-sandbox git op, not immediate in-session RCE.

Caveats

  • e2e was macOS/Seatbelt only. Windows issue #18918's fix ("statically exclude .git at any depth")

may already deny nested .git on Windows — not verified here.

  • The case-insensitivity of the metadata name match is a separate policy-layer inconsistency that does

NOT yield a macOS escape (Seatbelt evaluates the deny on the kernel-canonicalized path); it is not
claimed here.

Suggested fix

If nested-repo protection is desired, match protected metadata names against every path component (or
enumerate nested .git/.codex/.agents when materializing the policy) rather than only the
writable root's first component.

---
Found with the rust-in-peace pipeline
(AI-assisted Rust vulnerability research).

View original on GitHub ↗