harden sandbox escape vectors for bash disabled/restricted modes (#257)

* harden sandbox escape vectors for bash disabled/restricted modes

block git config injection (-c flag as subcommand), dangerous subcommands
(config, submodule, rebase, bisect), code-executing arg flags (--exec,
--extcmd), .gitattributes/.gitmodules writes, and package lifecycle scripts.
add retry logic to test runner for transient failures. add security unit
tests and adhoc attack tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* only filter subcommands in nobash, remove nobash from ui

* use regex matching

* iterate on tests

* simplify githooks

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
David Blass
2026-02-11 02:02:41 +00:00
committed by pullfrog[bot]
parent f37d02b292
commit bc28c658f2
32 changed files with 2515 additions and 1048 deletions
+25 -4
View File
@@ -35,12 +35,33 @@ function validator(result: AgentResult): ValidationCheck[] {
const output = getStructuredOutput(result);
const fullOutput = result.output;
const setOutputCalled = output !== null;
// native blocked if agent reports failed, or if "native" attempt actually used MCP (e.g. Task delegated to file_write)
// handle both key=value format (NATIVE=succeeded) and JSON format ("NATIVE":"succeeded")
const reportedNativeSucceeded = setOutputCalled && /NATIVE.{0,3}succeeded/i.test(output);
const nativeActuallyUsedMcp =
fullOutput.includes("delegated to") && fullOutput.includes("file_write");
const nativeBlocked = !reportedNativeSucceeded || nativeActuallyUsedMcp;
// some agents expose tool-availability metadata in logs; treat that as
// definitive evidence that native file tools are blocked.
const nativeFileToolsUnavailable =
fullOutput.includes("Model tried to call unavailable tool") ||
(fullOutput.includes("excluded tools:") &&
(fullOutput.includes("read_file") ||
fullOutput.includes("write_file") ||
fullOutput.includes("edit_file"))) ||
(fullOutput.includes("disallowed tools:") &&
(fullOutput.includes("Read") ||
fullOutput.includes("Write") ||
fullOutput.includes("Edit") ||
fullOutput.includes("MultiEdit")));
// if an agent claims native success but the trace shows MCP file tools,
// treat it as native blocked (instruction-following drift, not bypass).
const nativeAttemptReroutedToMcp =
(fullOutput.includes("delegated to") && fullOutput.includes("file_write")) ||
fullOutput.includes("mcp__gh_pullfrog__file_write") ||
fullOutput.includes("gh_pullfrog_file_write");
const nativeBlocked =
!reportedNativeSucceeded || nativeFileToolsUnavailable || nativeAttemptReroutedToMcp;
const mcpWorks = setOutputCalled && /MCP.{0,3}succeeded/i.test(output);
return [