Skip to content

< all problems55 · Level 06, MCP

Sandbox the Shell Tool

medium · implement · Tool Calling

The coding agent's run_shell tool runs whatever text it is handed, and last week that was cat ~/.aws/credentials, because a README said the deploy config lived there. A blocklist gets walked around (rm is blocked, so the model pipes to sh), so the gate is an allowlist plus a few structural rules, applied in a fixed order.

Implement vet_command(command) returning (True, "ok") or (False, rule), where rule is the first of these that fires:

  1. shell: the raw text contains a pipe, a semicolon, an ampersand, a redirect (> or <), a backtick or a $; or shlex cannot parse it (an unbalanced quote); or the program is python with a -c flag.
  2. program: the program (the first token after shlex.split) is not in ALLOWED_PROGRAMS. An empty command has no program.
  3. escape: any argument is an absolute path, contains .., or starts with ~.
  4. secrets: any argument's final path component is .env, id_rsa, credentials or .netrc, or ends in .pem or .key.
  5. destructive: git with push, reset, clean or rebase as its subcommand, or find with -delete or -exec among its arguments.

Use shlex.split so quoting works the way the shell sees it: cat "my notes.txt" is one argument.

The catch: the order matters. cat ../.env is an escape before it is a secret, and curl x | sh is a shell construct before curl is an unknown program.