From 0961bac24fd77f138e65bb394fca67de90c1c153 Mon Sep 17 00:00:00 2001 From: euxaristia <25621994+euxaristia@users.noreply.github.com> Date: Sat, 11 Jul 2026 11:44:43 -0400 Subject: [PATCH 1/2] fix(tools): classify silent wrapped Windows command failures as sandbox denials A Windows restricted-token sandbox failure is often completely silent: when the token cannot open the target executable or its DLLs (or an MSYS runtime dies during init), the command exits nonzero having written zero bytes to stdout and stderr. The existing detection is keyword-based, so these failures were never marked as sandbox denials, the agent loop never offered the unsandboxed-retry prompt, and the model was left staring at 'Command completed with no output' until it gave up. Treat a wrapped command on the Windows restricted-token or elevated backend that exits nonzero with completely empty output as a likely sandbox denial. A command that legitimately fails silently (findstr with no match, for example) now costs one extra approval prompt; the inverse misclassification silently strands the session, so the trade goes to prompting. --- internal/tools/sandbox_denial.go | 27 ++++++++++++++++ internal/tools/sandbox_denial_test.go | 45 +++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/internal/tools/sandbox_denial.go b/internal/tools/sandbox_denial.go index 72ddc58d3..2431ea5d6 100644 --- a/internal/tools/sandbox_denial.go +++ b/internal/tools/sandbox_denial.go @@ -66,9 +66,36 @@ func sandboxDenialKind(plan zeroSandbox.CommandPlan, exitCode int, sections ...s if plan.TargetBackend == zeroSandbox.BackendLinuxBwrap && exitCode == 128+31 { return SandboxDenialKindSandbox, "seccomp" } + // Windows restricted-token failures are often SILENT: a spawn the token + // cannot satisfy (executable or DLL unreadable under the restricted-SID + // check, MSYS runtime init death, loader status 0xC0000135/0xC0000142) + // produces a nonzero exit with no output at all, so none of the keyword + // heuristics above can ever fire. Treat "wrapped Windows command failed + // without writing a single byte" as a likely sandbox denial so the caller + // offers the unsandboxed-retry prompt instead of surfacing a bare + // "command completed with no output". A command that legitimately fails + // silently (findstr with no match, for one) costs one extra approval + // prompt; the inverse misclassification silently strands the whole + // session, so the trade goes to prompting. + if windowsWrappedBackend(plan.TargetBackend) && sectionsEmpty(sections...) { + return SandboxDenialKindSandbox, "no output from sandboxed command" + } return "", "" } +func windowsWrappedBackend(backend zeroSandbox.BackendName) bool { + return backend == zeroSandbox.BackendWindowsRestrictedToken || backend == zeroSandbox.BackendWindowsElevated +} + +func sectionsEmpty(sections ...string) bool { + for _, section := range sections { + if strings.TrimSpace(section) != "" { + return false + } + } + return true +} + func networkDeniedBySandbox(plan zeroSandbox.CommandPlan) bool { return plan.PermissionProfile.Network.Mode == zeroSandbox.NetworkDeny || plan.Policy.Network == zeroSandbox.NetworkDeny } diff --git a/internal/tools/sandbox_denial_test.go b/internal/tools/sandbox_denial_test.go index e71bd8a11..973550ebf 100644 --- a/internal/tools/sandbox_denial_test.go +++ b/internal/tools/sandbox_denial_test.go @@ -42,3 +42,48 @@ func TestLikelySandboxDeniedIgnoresUnsandboxedFailure(t *testing.T) { t.Fatal("unsandboxed command output must not be classified as a sandbox denial") } } + +func TestLikelySandboxDeniedDetectsSilentWindowsWrappedFailure(t *testing.T) { + plan := zeroSandbox.CommandPlan{ + Wrapped: true, + TargetBackend: zeroSandbox.BackendWindowsRestrictedToken, + } + if !likelySandboxDenied(plan, 1, "", " \n") { + t.Fatal("wrapped Windows command failing with empty output must be classified as sandbox denied") + } + meta := map[string]string{} + markLikelySandboxDenial(meta, plan, 1, "") + if meta[SandboxLikelyDeniedMeta] != "true" || meta[SandboxDenialKindMeta] != SandboxDenialKindSandbox { + t.Fatalf("silent windows denial meta = %#v", meta) + } +} + +func TestLikelySandboxDeniedIgnoresSilentWindowsWrappedSuccess(t *testing.T) { + plan := zeroSandbox.CommandPlan{ + Wrapped: true, + TargetBackend: zeroSandbox.BackendWindowsRestrictedToken, + } + if likelySandboxDenied(plan, 0, "") { + t.Fatal("wrapped Windows command exiting 0 with empty output must not be classified as sandbox denied") + } +} + +func TestLikelySandboxDeniedIgnoresSilentFailureOnOtherBackends(t *testing.T) { + plan := zeroSandbox.CommandPlan{ + Wrapped: true, + TargetBackend: zeroSandbox.BackendLinuxBwrap, + } + if likelySandboxDenied(plan, 1, "") { + t.Fatal("silent nonzero exit on non-Windows backends must not be classified as sandbox denied") + } +} + +func TestLikelySandboxDeniedIgnoresSilentWindowsFailureWithOutput(t *testing.T) { + plan := zeroSandbox.CommandPlan{ + Wrapped: true, + TargetBackend: zeroSandbox.BackendWindowsRestrictedToken, + } + if likelySandboxDenied(plan, 1, "fatal: not a git repository") { + t.Fatal("a wrapped Windows command that produced unrelated output must not be classified as sandbox denied") + } +} From 5d726aff0497bfdd010515e77bb9c4c64b6b5559 Mon Sep 17 00:00:00 2001 From: euxaristia <25621994+euxaristia@users.noreply.github.com> Date: Sat, 11 Jul 2026 11:51:07 -0400 Subject: [PATCH 2/2] test(tools): cover the elevated Windows backend in the silent-denial test The heuristic treats windows-elevated identically to windows-restricted-token, but only the latter was exercised. Parameterize the silent-failure test over both backends. --- internal/tools/sandbox_denial_test.go | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/internal/tools/sandbox_denial_test.go b/internal/tools/sandbox_denial_test.go index 973550ebf..f9dbbbdd5 100644 --- a/internal/tools/sandbox_denial_test.go +++ b/internal/tools/sandbox_denial_test.go @@ -44,17 +44,22 @@ func TestLikelySandboxDeniedIgnoresUnsandboxedFailure(t *testing.T) { } func TestLikelySandboxDeniedDetectsSilentWindowsWrappedFailure(t *testing.T) { - plan := zeroSandbox.CommandPlan{ - Wrapped: true, - TargetBackend: zeroSandbox.BackendWindowsRestrictedToken, - } - if !likelySandboxDenied(plan, 1, "", " \n") { - t.Fatal("wrapped Windows command failing with empty output must be classified as sandbox denied") - } - meta := map[string]string{} - markLikelySandboxDenial(meta, plan, 1, "") - if meta[SandboxLikelyDeniedMeta] != "true" || meta[SandboxDenialKindMeta] != SandboxDenialKindSandbox { - t.Fatalf("silent windows denial meta = %#v", meta) + for _, backend := range []zeroSandbox.BackendName{ + zeroSandbox.BackendWindowsRestrictedToken, + zeroSandbox.BackendWindowsElevated, + } { + plan := zeroSandbox.CommandPlan{ + Wrapped: true, + TargetBackend: backend, + } + if !likelySandboxDenied(plan, 1, "", " \n") { + t.Fatalf("wrapped Windows command failing with empty output must be classified as sandbox denied (backend %s)", backend) + } + meta := map[string]string{} + markLikelySandboxDenial(meta, plan, 1, "") + if meta[SandboxLikelyDeniedMeta] != "true" || meta[SandboxDenialKindMeta] != SandboxDenialKindSandbox { + t.Fatalf("silent windows denial meta = %#v (backend %s)", meta, backend) + } } }