feat: first-party fixed-argv carve-out in sandbox fail-close (#1563) - #2428
Conversation
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsThis is a carefully-scoped, structurally-ratcheted security hardening change (first-party fixed-argv carve-out) with thorough tests. Verifying the key invariants:
No AUTOSDE rule is weakened and no residual-class defect is present on the changed lines. No findings. [OPUS-REVIEWED] 09f98db Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 5.6 Review — ✅ human override acceptedHuman judgment by @bolichen97 overrides the GPT 5.6 finding for This comment is updated in place on each push. The model was not re-run because an authorized human decision supersedes it. False positive or not applicable? A repository writer can comment: |
Design Review (Fable 5) — ✅ PASSAdvisory design-level review of Design-Verdict: PASS A root-cause split of a conflated opt-in, gated structurally (equality-checked argv, three preconditions, CI ratchet), reversible, and it removes the doc's nudge toward the dangerous global flag. Suggestions
[DESIGN-REVIEWED] 09f98db |
f4e3d04 to
1497a14
Compare
|
🤖 Kiro Crew Auto-Pipeline [operator: bolichen97] — response to GPT 5.6 review of f4e3d04 (fixes pushed as 1497a14) Finding 1 (env bypass) — LEGITIMATE, FIXED. Finding 3 (second governance walk) — LEGITIMATE, FIXED. Finding 2 (SEL log-and-proceed → re-raise) — REBUTTED as designed behavior. The log-and-proceed posture on the
Design Review CONCERNS (advisory) — answered. The declaration fallback lists tools but cannot verify the server can START — |
|
🤖 Kiro Crew Auto-Pipeline [operator: bolichen97] — response to GPT 5.6 review of 1497a14 Findings 1 (env bypass) and 3 (double governance walk) from the previous round are confirmed cleared. The two remaining blockers are rebutted with evidence: "Agent-writable package code runs unconfined" — REBUTTED: no new exposure class. The scenario (injected edit to an editable checkout → managed probe executes modified code) is not introduced by the carve-out; it is the pre-existing, explicitly documented residual of backend-less hosts, and GPT's proposed fix has the identical exposure:
"SEL audit-or-deny" (2nd repetition) — REBUTTED as designed behavior, unchanged from the previous round: the log-and-proceed posture matches the two sibling audits in the same function ( |
|
/ai-review override gpt 1497a14: Both findings are designed residuals documented in security.md — the in-process fallback GPT recommends imports (executes) the same agent-writable package code unconfined in the gateway, so the carve-out adds no new exposure; SEL log-and-proceed matches the mode=off delegation and nested-passthrough precedents because a backend-less host has no safe fallback layer. |
Human judgment recorded@bolichen97 marked the gpt AI finding as false positive, not applicable, or explicitly accepted for
This decision applies only to this commit. A new push requires a new judgment. |
1497a14 to
b0187ed
Compare
agent.sandbox_allow_unsandboxed_exec conflated two decisions on a host with no sandbox backend: spawning Kiro Crew's own managed MCP servers (argv fully derived inside this package) and unconfining the mode="strict" hostile-input paths. A Windows user who just wanted working first-party tooling had to unconfine the hostile-input paths too. wrap_argv/sandboxed_spawn_argv gain a keyword-only first_party_fixed_argv caller-class axis. In the backend=="none" fail-close branch the spawn proceeds unconfined only when ALL of: the flag is set (ratcheted by test_spawn_audit FIRST_PARTY_SPAWNS), the unavailability class is no_backend (transient and foreign_sandbox still raise), and no governance sandbox.min_level floor is active (shared read with _clamp_sandbox_mode so the two cannot disagree). The allowed path env-scrubs via the trusted absolute env binary, warns loudly once per process, and SEL-audits with a distinct third outcome: unconfined (critical=True, log-and-proceed on SEL failure, matching the mode=off delegation precedent). The only classified site is the managed-server MCP probe, and only when command+args EQUAL the invocation agent._kirocrew_mcp_invocation derives (a customized command under a managed name keeps the full opt-in). sandbox_allow_unsandboxed_exec=true remains a strict superset: byte-identical behavior when set. Closes #1563
b0187ed to
09f98db
Compare
|
🤖 Kiro Crew Auto-Pipeline [operator: bolichen97] — response to GPT 5.6 review of b0187ed (fixes pushed as 09f98db) Both round-3 findings are legitimate and fixed:
Synchronous critical SEL flush on the event loop — FIXED as recommended. |
|
🤖 Kiro Crew Auto-Pipeline [operator: bolichen97] — response to GPT 5.6 review of 09f98db "Mutable launcher is trusted for unconfined execution" — REBUTTED (2nd repetition of the round-2 finding, console-script variant; same rebuttal, previously overridden on 1497a14). A tampered install is a conceded, pre-existing residual on backend-less hosts, and the recommended fix provides zero protection against it: the declaration fallback |
|
/ai-review override gpt 09f98db: Repetition of the finding overridden on 1497a14 — the recommended declaration fallback imports the same agent-writable package code unconfined into the gateway (documented conceded residual), so the carve-out adds no new exposure on a backend-less host and is unreachable where a backend exists. |
Human judgment recorded@bolichen97 marked the gpt AI finding as false positive, not applicable, or explicitly accepted for
This decision applies only to this commit. A new push requires a new judgment. |
…dev#1563) (kirodotdev#2428) agent.sandbox_allow_unsandboxed_exec conflated two decisions on a host with no sandbox backend: spawning Kiro Crew's own managed MCP servers (argv fully derived inside this package) and unconfining the mode="strict" hostile-input paths. A Windows user who just wanted working first-party tooling had to unconfine the hostile-input paths too. wrap_argv/sandboxed_spawn_argv gain a keyword-only first_party_fixed_argv caller-class axis. In the backend=="none" fail-close branch the spawn proceeds unconfined only when ALL of: the flag is set (ratcheted by test_spawn_audit FIRST_PARTY_SPAWNS), the unavailability class is no_backend (transient and foreign_sandbox still raise), and no governance sandbox.min_level floor is active (shared read with _clamp_sandbox_mode so the two cannot disagree). The allowed path env-scrubs via the trusted absolute env binary, warns loudly once per process, and SEL-audits with a distinct third outcome: unconfined (critical=True, log-and-proceed on SEL failure, matching the mode=off delegation precedent). The only classified site is the managed-server MCP probe, and only when command+args EQUAL the invocation agent._kirocrew_mcp_invocation derives (a customized command under a managed name keeps the full opt-in). sandbox_allow_unsandboxed_exec=true remains a strict superset: byte-identical behavior when set. Closes kirodotdev#1563
Summary
agent.sandbox_allow_unsandboxed_execis one boolean that conflates two decisions on a host with no sandbox backend (detect_backend() == "none"— every Windows host, Linux without user namespaces):agent._kirocrew_mcp_invocation(), with no agent/repo/user-config input;mode="strict"hostile-input paths (worktree handler's repo-controlled gitinclude.path, Papyrus' crafted-.texchokepoints).A Windows user who just wants working first-party MCP tooling had to unconfine the hostile-input paths too. This adds a caller-class axis distinguishing WHO chose the argv, enforced structurally.
What changed
wrap_argv/sandboxed_spawn_argvgain keyword-onlyfirst_party_fixed_argv: bool = False. In thebackend == "none"fail-close branch, the spawn proceeds unconfined ONLY when ALL of:test_spawn_audit.py::FIRST_PARTY_SPAWNS(a new site passing the kwarg without an allowlist entry fails CI);no_backend—transientstill raises (self-heals; must not buy a bypass),foreign_sandboxstill raises (host sandbox is fine; remedy is config);sandbox.min_levelfloor is active —_governance_sandbox_floor_active()shares ONE read (_governance_sandbox_floor()) with_clamp_sandbox_mode, including thePlatformCompositionError-propagates / other-errors-treat-absent posture, so the two cannot disagree.envbinary (_unset_env_argv, never PATH-resolved; on Windows where none exists, the chokepoint'sscrub_envon the child env is the guarantee — a superset of the unset keys), one-shot loudSECURITYwarning, and a SEL tool-invocation event with a distinct third outcomeunconfined(critical=True; SEL failure is log-and-proceed, matching themode="off"delegation precedent).mcp_discovery.probe_server). The flag is computed by_is_first_party_managed_argv, which requires the spec's command+args to equal the freshly re-resolved_kirocrew_mcp_invocation— stronger than name matching, so an mcp.json row squatting a managed name with custom command text stays fail-closed. Thecomputer_use.pydoctor probe was verified NOT to route through the chokepoint (it is inBENIGN_SPAWNS) and is untouched per the spec's verify-before-touching condition. All hostile-input callers are explicitly unchanged.FIRST_PARTY_SPAWNSallowlist + AST scan for the kwarg (any value expression, not just literalTrue) + a staleness test.sandbox_allow_unsandboxed_exec=trueremains a strict superset — byte-identical behavior when set (pinned by test).security.mdfail-closed section documents the carve-out, its three preconditions, and theunconfinedSEL outcome;windows-install.mdMCP tool-listing row updated._warn_managed_in_process_oncereworded (the "set the opt-in to probe for real" tail went stale — the fallback now fires only for transient/foreign/floor/customized-command cases).Tested
test/test_sandbox_first_party_exec.py(13 tests): full behavior matrix — passthrough + env scrub + SELunconfined+ one-shot warning; no-flag still raises; transient/foreign/floor still raise despite the flag; opt-in byte-identical with/without flag; flag inert with a backend; chokepoint threading; Windows no-env-binary shape.test_mcp_discovery.py: 6 new tests on_is_first_party_managed_argv(equality gate, customized-command rejection, resolution-failure fail-safe) and probe flag pass-through.test_spawn_audit.py: 2 new ratchet tests.**kwargs-indirection limitation). The server-side GPT + Opus review gates on this PR are the real gate.Closes #1563