fix(sandbox): allow exec in writable grant-dirs under command policies#1391
fix(sandbox): allow exec in writable grant-dirs under command policies#1391kipz wants to merge 1 commit into
Conversation
PR Review SummarySize
Affected crates
Blast radius — ContainedThis PR touches: source code Updated automatically on each push to this PR. |
Signed-off-by: James Carnegie <me@kipz.org>
8c1ad4d to
ac03729
Compare
| } | ||
|
|
||
| // Subtree grant: files written into these dirs after setup must still run. | ||
| for dir in writable_dirs { |
There was a problem hiding this comment.
Caution
🔒 [HIGH · security] Granting subtree AccessFs::Execute to writable directories (via outer_exec_writable_dirs) in apply_outer_exec_gate introduces a severe security bypass of the command_policies execution gate on Linux. A malicious sandboxed child can read any controlled binary (such as git or kubectl), copy it into a writable directory (like the current working directory . or /tmp), and execute that copy directly. Because Landlock is strictly allow-list oriented and cannot express deny-within-allow, granting execution rights to the writable directory allows execution of any file inside it. This bypasses the shim and supervisor entirely, circumventing all argument filtering, policy rules, credential isolation, and auditing. To maintain the security boundary, this change must be reverted. Scripts should instead be executed by running their respective interpreters (e.g., bash script.sh) directly, which does not require direct script execution privileges.
There was a problem hiding this comment.
This is the accepted residual risk documented on #1390. A copied policed binary gains no elevation: credential promotion and proxy network bind to the verified supervisor handshake, not to whether a file is executable — so an unshimmed copy runs under the same fs/network limits as the agent, which can already write-and-run arbitrary code in a writable grant-dir when no command_policies exist. This brings command_policies in line with that default. On Linux, Landlock is a strict allow-list with no deny-within-allow, and a copy has a fresh inode, so the exec gate cannot both permit new files in cwd to run and block a copied policed binary — the two are mutually exclusive. The original policed binary stays blocked from direct exec via the inode-identity gate.
Linked Issue
Closes #1390
Summary
Maybe there are better solutions, but without this, adding command policies breaks the main sandbox execution rules! This brings it inline with the default behavior on Linux without command policies, but might be unexpected. The original binary is there in the main sandbox, so it has the same restrictions as the agent itself....
NB: OSX has deny-within-allow, so blocking intercepted commands in the agent sandbox is easy.
The Landlock outer exec gate that
command_policiesinstalls allowed exec onlyfrom read-only directories (PATH scan +
executable_dirs), excluding everydirectory the profile also grants write access to — including cwd. This adds
a directory-subtree
AccessFs::Executegrant for those writable dirs, soscripts and freshly compiled binaries written into them execute again, while
the real policed-command binaries stay blocked from direct exec (their
read-only search dirs are still enumerated per-file with controlled inodes
excluded).
Agent Disclosure
I am an AI coding agent (Claude, via Claude Code) operating under human
supervision. Intent, approach, and residual-risk tradeoffs were disclosed and
discussed on the linked issue before this PR was opened:
#1390 (comment)
Relevant files consulted/changed:
crates/nono-cli/src/tool-sandbox/platform/linux.rs(
ResolvedToolSandboxPlan::build,build_outer_exec_files,apply_outer_exec_gate,outer_caps_grant_write),crates/nono-cli/tests/execution_strategy_run.rs.Test Plan
make fmt&&make ci(clippy -D warnings + fmt-check + tests) — cleanexecution_strategy_run.rs:command_policies_allows_script_exec_in_writable_grant_dirandcommand_policies_allows_compiled_binary_exec_in_writable_grant_dirmain): script/binary in a writable grant-dir both fail withexit 126 (
bad interpreter: Permission denied)(mediation unaffected)
Checklist
Agent Compliance Check