Skip to content

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Jul 24, 2025

This PR updates is_known_safe_command() to account for "safe operators" to expand the set of commands that can be run without approval. This concept existed in the TypeScript CLI, and we are [finally!] porting it to the Rust one:

// A conservative allow-list of bash operators that do not, on their own, cause
// side effects. Redirections (>, >>, <, etc.) and command substitution `$()`
// are intentionally excluded. Parentheses used for grouping are treated as
// strings by `shell-quote`, so we do not add them here. Reference:
// https://github.com/substack/node-shell-quote#parsecmd-opts
const SAFE_SHELL_OPERATORS: ReadonlySet<string> = new Set([
"&&", // logical AND
"||", // logical OR
"|", // pipe
";", // command separator
]);

The idea is that if we have EXPR1 SAFE_OP EXPR2 and EXPR1 and EXPR2 are considered safe independently, then EXPR1 SAFE_OP EXPR2 should be considered safe. Currently, SAFE_OP includes &&, ||, ;, and |.

In the TypeScript implementation, we relied on https://www.npmjs.com/package/shell-quote to parse the string of Bash, as it could provide a "lightweight" parse tree, parsing 'beep || boop > /byte' as:

[ 'beep', { op: '||' }, 'boop', { op: '>' }, '/byte' ]

Though in this PR, we introduce the use of https://crates.io/crates/tree-sitter-bash for parsing (which incidentally we were already using in codex-apply-patch), which gives us a richer parse tree. (Incidentally, if you have never played with tree-sitter, try the playground and select Bash from the dropdown to see how it parses various expressions.)

As a concrete example, prior to this change, our implementation of is_known_safe_command() could verify things like:

["bash", "-lc", "grep -R \"Cargo.toml\" -n"]

but not:

["bash", "-lc", "grep -R \"Cargo.toml\" -n || true"]

With this change, the version with || true is also accepted.

Admittedly, this PR does not expand the safety check to support subshells, so it would reject, e.g. bash -lc 'ls || (pwd && echo hi)', but that can be addressed in a subsequent PR.

@bolinfest bolinfest force-pushed the pr1668 branch 3 times, most recently from 6866e53 to 18e266e Compare July 24, 2025 19:47
bolinfest added a commit that referenced this pull request Jul 24, 2025
`nl` is a line-numbering tool that should be on the _trusted _ list, as
there is nothing concerning on https://gtfobins.github.io/gtfobins/nl/
that would merit exclusion.

`true` and `false` are also safe, though not particularly useful given
how `is_known_safe_command()` works today, but that will change with
#1668.
@github-actions
Copy link

PR Summary

Adds a dedicated bash module that uses tree-sitter to parse bash -lc "<script>", allowing is_known_safe_command to accept pipelines/sequences of word-only commands joined by &&, ||, ;, or |. The previous single-command parser is removed, tests are expanded, and the module is wired into core::lib.

Review

Looks great—clear separation of concerns and stronger safety checks. A few small nits:

  • Consider caching the Parser to avoid re-allocating on every call.
  • The allow-list intentionally blocks redirections; if /dev/null redirection is ever needed we’ll have to revisit.
  • A quick benchmark would help ensure the added parsing doesn’t impact command latency.

Otherwise the implementation and tests are solid—ship it!


View workflow run

// a conservative allow‑list of shell operators that themselves do not
// introduce side effects ( "&&", "||", ";", and "|" ). If every
// individual command in the script is itself a known‑safe command, then
// the composite expression is considered safe.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasonable, I like it!

Copy link
Collaborator

@dylan-hurd-oai dylan-hurd-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bolinfest bolinfest merged commit a164174 into main Jul 24, 2025
23 checks passed
@bolinfest bolinfest deleted the pr1668 branch July 24, 2025 21:13
@github-actions github-actions bot locked and limited conversation to collaborators Jul 24, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants