Skip to content

Reject shell substitutions in terminal tool commands#51689

Merged
rtfeldman merged 9 commits intomainfrom
SEC-264/env-var-injection-bypass
Mar 17, 2026
Merged

Reject shell substitutions in terminal tool commands#51689
rtfeldman merged 9 commits intomainfrom
SEC-264/env-var-injection-bypass

Conversation

@rtfeldman
Copy link
Copy Markdown
Contributor

@rtfeldman rtfeldman commented Mar 16, 2026

Harden the terminal tool's permission system to reject commands containing shell substitutions and interpolations ($VAR, ${VAR}, $(…), backticks, $((…)), <(…), >(…)) before they reach terminal creation.

Changes

Shell command parser (shell_command_parser)

  • Added structured terminal command-prefix extraction with env-var prefix support
  • Added parser-backed validation that classifies commands as Safe/Unsafe/Unknown
  • Extended normalized command extraction to include scalar env-var assignments in order
  • Preserved quoted assignment values when they contain whitespace or special characters

Pattern extraction (agent/pattern_extraction)

  • Updated terminal pattern extraction to use structured parser output
  • Included env-var prefixes in generated allow patterns
  • Normalized regex token boundaries to \s+ while preserving display whitespace

Tool permissions (agent/tool_permissions)

  • Added invalid-terminal-command rejection for forbidden substitutions/interpolations
  • Added unconditional allow-all bypass (global default Allow, or terminal-specific Allow with empty patterns)
  • Preserved hardcoded denial precedence over allow-all

Terminal tool (agent/tools/terminal_tool)

  • Updated tool description and input schema to explicitly prohibit shell substitutions
  • Added comprehensive SEC-264 regression test suite (20 new tests) covering:
    • All forbidden constructs (${HOME}, $1, $?, $$, $@, $(whoami), backticks, $((1+1)), <(ls), >(cat), env-prefix variants, multiline, nested)
    • Allow-all exception paths (global and terminal-specific)
    • Hardcoded-denial precedence
    • Env-prefix permission flow (matching, value mismatch rejection, multiple assignments, quoted whitespace)

Closes SEC-264

Release Notes:

  • Terminal tool permissions regexes can now match environment variables (e.g. FOO=bar cmd arg1 arg2)
  • If terminal tool permissions have active permissions regexes running on them, then bare interpolations like $FOO are disallowed for security, since regexes wouldn't be able to match on them.

@rtfeldman rtfeldman self-assigned this Mar 16, 2026
@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Mar 16, 2026
@zed-community-bot zed-community-bot bot added the staff Pull requests authored by a current member of Zed staff label Mar 16, 2026
Fix two security bypasses in shell command validation:

- CaseClause patterns (Vec<Word>) were not being validated, allowing
  command substitutions like $(whoami) in case patterns to slip through
  as Safe despite being executed by the shell at runtime.

- ArithmeticForClause only validated the body, ignoring initializer,
  condition, and updater expressions that can contain command
  substitutions. Now treated as unconditionally Unsafe, mirroring
  standalone Arithmetic.
Clarify the return type of normalize_assignment_for_command_prefix by
introducing a NormalizedAssignment enum with Included and Skipped
variants, replacing the confusing double-Option.
When a command has both Unsafe and Unknown parts, return Unsafe since
it is a more definitive and actionable signal for user-facing error
messages.
Replace wildcard catch-all arms with explicit matches for Word and
ProcessSubstitution variants so future enum additions cause compile
errors rather than silently passing through.
'Unsupported' more accurately describes what the variant means: the
command uses syntax we cannot analyze, not that the result is unknown
for some other reason.
@rtfeldman rtfeldman marked this pull request as ready for review March 17, 2026 03:49
@rtfeldman rtfeldman merged commit f3fb4e0 into main Mar 17, 2026
31 checks passed
@rtfeldman rtfeldman deleted the SEC-264/env-var-injection-bypass branch March 17, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement staff Pull requests authored by a current member of Zed staff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant