Describe the bug
Description
The GitHub Copilot CLI's shell-command interception filter reads bash-tool heredoc-body data as if it were shell syntax. A heredoc body containing ordinary text such as kill, pkill, or killall is therefore rejected as a malformed kill command when that text is stdin payload for another program rather than shell command syntax.
In the tested heredoc cases, the trigger fires even when kill appears mid-line, after leading whitespace, or alone on its own line.
This report focuses on heredoc-body scanning specifically. In the non-heredoc forms tested, the filter passed literal text containing kill in single-quoted arguments, double-quoted arguments, $'...' ANSI-C strings, and a simple quoted-assignment-plus-expansion case. The rejection appears only for heredoc bodies, both <<'DELIM' quoted and <<DELIM unquoted.
This is closely related to #774, which describes the same interception filter rejecting command-like words in text arguments to non-bash tools. The present report covers a complementary case: the same filter scanning bash heredoc body data within a bash invocation.
Steps to Reproduce
- Invoke a bash command that feeds a heredoc body containing
kill, pkill, or killall as ordinary text into a program like cat, tee, ed, or any program that reads stdin.
- The outer command is the program receiving the heredoc; the heredoc body is data, not shell statements.
- The filter rejects the call before bash runs.
Example
Quoted heredoc
cat <<'EOF'
kill the lights before bed
EOF
Unquoted heredoc
cat <<EOF
kill the lights before bed
EOF
Both forms produce the same rejection:
Command not executed. The 'kill' command must specify at least one numeric PID. Usage: kill <PID> or kill -9 <PID>
The heredoc-body check is stricter than the quoted-argument check. echo "kill" passes, but a heredoc body containing only kill is rejected. This asymmetry suggests that heredoc bodies and ordinary quoted bash arguments are evaluated under different interception conditions.
Tested non-heredoc forms that the filter passes
| Form |
Passes? |
echo 'kill the lights before bed' |
yes |
echo "kill the lights before bed" |
yes |
echo "kill" |
yes |
printf '%s\n' "kill the lights before bed" |
yes |
x="kill the lights before bed"; echo "$x" |
yes |
printf $'kill the lights\nbefore bed\n' |
yes |
Heredoc-body behavior
| Heredoc body text |
Result |
kill the lights before bed |
rejected |
pre kill the lights before bed |
rejected |
kill the lights before bed |
rejected |
kill |
rejected |
pkill the lights |
rejected with the analogous pkill interception message |
the lights got killed |
passes |
just-kill-something |
passes |
These tests show that the filter passes several common non-heredoc quoting/data contexts — single quotes, double quotes, ANSI-C quoting, and a simple quoted-assignment-plus-expansion case — while rejecting comparable text in heredoc bodies. The heredoc trigger appears to respect whole-word boundaries.
For unquoted heredocs, bash can still perform expansions inside the body. For example, command substitution such as $(kill foo) would be executable syntax and may legitimately need scrutiny. The observation in this report is narrower: ordinary heredoc text without an expansion is being rejected as though it were shell command syntax.
I have not exhaustively tested every bash construct containing literal text — for example here-strings (<<<), process substitution (<(...)), command substitution ($(...)), or backticks. The claims here are limited to the tested contrast cases above and to the reproducible heredoc rejection.
Expected Behavior
A heredoc-grammar-aware filter would:
- When encountering a quoted heredoc opener such as
<<'DELIM', treat the body through the matching DELIM line as literal stdin data and not subject it to command-token interception.
- For unquoted heredocs such as
<<DELIM, not treat plain body lines as shell statements, while still permitting scrutiny of expansions such as parameter expansion, arithmetic expansion, and command substitution.
- Apply the interception rule only to tokens that bash would evaluate as executable command syntax, not to ordinary heredoc text.
Actual Behavior
The observed behavior is consistent with the filter scanning heredoc body bytes without distinguishing them from shell statements. It appears to have some awareness of common quoting forms in ordinary bash arguments. In the tested heredoc cases, the observed behavior does not distinguish between:
- Heredoc framing (
<<DELIM ... DELIM) and ordinary bash arguments.
- Heredoc quoting (
<<'DELIM' produces a literal body; the filter still scans it).
- Ordinary heredoc text and executable syntax that can appear inside unquoted heredoc expansions.
The heredoc-body behavior also appears stricter than the quoted-argument behavior: echo "kill" passes, but a heredoc body containing only kill is rejected. Whole-word boundaries are respected (killed and just-kill-something pass), so the trigger is whole-word token interception inside heredoc data rather than substring matching.
Impact
- Blocks writes of file content containing common English text. The word "kill" appears in idioms ("kill the lights"), literary references ("to kill a mockingbird"), song lyrics, and technical prose (signal documentation, OS man pages).
- Blocks code edits when
ed heredocs carry source files whose contents mention kill — including Lisp code with 'kill symbols, shell scripts that document kill semantics, or any source that includes the word kill near a line boundary.
- Non-deterministic from the agent's perspective — because the exact pattern isn't published, agents cannot reliably predict when a heredoc-bearing call will be rejected; only empirical batch-and-retry reveals the threshold.
Environment
- GitHub Copilot CLI version: 1.0.48
- OS: Linux
- Use case: editing source files via
ed heredocs whose contents contain the word kill in code, prose, or symbol names.
Suggested Fix
A heredoc-aware filter would:
- Parse the bash command to identify heredoc openers and locate their matching closing delimiter lines.
- For quoted heredocs such as
<<'DELIM', exclude the body from command-token interception entirely.
- For unquoted heredocs such as
<<DELIM, distinguish ordinary heredoc text from executable syntax introduced by expansions such as $(...), backticks, arithmetic expansion, or parameter expansion. Plain body text like kill the lights would not be intercepted as a command, while command substitutions that bash would actually execute could still be inspected.
Note: the filter already passes the tested single-quoted strings, double-quoted strings, $'...' strings, and simple quoted-assignment-plus-expansion case. This report suggests comparable heredoc awareness.
Related
Note: Together with #774, this report describes interception behavior across multiple text-bearing contexts. The filter passes several tested bash quoting/data contexts, so a change for heredoc handling could be scoped specifically to heredoc parsing.
Affected version
GitHub Copilot CLI 1.0.48.
Steps to reproduce the behavior
No response
Expected behavior
No response
Additional context
No response
Describe the bug
Description
The GitHub Copilot CLI's shell-command interception filter reads
bash-tool heredoc-body data as if it were shell syntax. A heredoc body containing ordinary text such askill,pkill, orkillallis therefore rejected as a malformedkillcommand when that text is stdin payload for another program rather than shell command syntax.In the tested heredoc cases, the trigger fires even when
killappears mid-line, after leading whitespace, or alone on its own line.This report focuses on heredoc-body scanning specifically. In the non-heredoc forms tested, the filter passed literal text containing
killin single-quoted arguments, double-quoted arguments,$'...'ANSI-C strings, and a simple quoted-assignment-plus-expansion case. The rejection appears only for heredoc bodies, both<<'DELIM'quoted and<<DELIMunquoted.This is closely related to #774, which describes the same interception filter rejecting command-like words in text arguments to non-bash tools. The present report covers a complementary case: the same filter scanning bash heredoc body data within a
bashinvocation.Steps to Reproduce
kill,pkill, orkillallas ordinary text into a program likecat,tee,ed, or any program that reads stdin.Example
Quoted heredoc
Unquoted heredoc
Both forms produce the same rejection:
The heredoc-body check is stricter than the quoted-argument check.
echo "kill"passes, but a heredoc body containing onlykillis rejected. This asymmetry suggests that heredoc bodies and ordinary quoted bash arguments are evaluated under different interception conditions.Tested non-heredoc forms that the filter passes
echo 'kill the lights before bed'echo "kill the lights before bed"echo "kill"printf '%s\n' "kill the lights before bed"x="kill the lights before bed"; echo "$x"printf $'kill the lights\nbefore bed\n'Heredoc-body behavior
kill the lights before bedpre kill the lights before bedkill the lights before bedkillpkill the lightspkillinterception messagethe lights got killedjust-kill-somethingThese tests show that the filter passes several common non-heredoc quoting/data contexts — single quotes, double quotes, ANSI-C quoting, and a simple quoted-assignment-plus-expansion case — while rejecting comparable text in heredoc bodies. The heredoc trigger appears to respect whole-word boundaries.
For unquoted heredocs, bash can still perform expansions inside the body. For example, command substitution such as
$(kill foo)would be executable syntax and may legitimately need scrutiny. The observation in this report is narrower: ordinary heredoc text without an expansion is being rejected as though it were shell command syntax.I have not exhaustively tested every bash construct containing literal text — for example here-strings (
<<<), process substitution (<(...)), command substitution ($(...)), or backticks. The claims here are limited to the tested contrast cases above and to the reproducible heredoc rejection.Expected Behavior
A heredoc-grammar-aware filter would:
<<'DELIM', treat the body through the matchingDELIMline as literal stdin data and not subject it to command-token interception.<<DELIM, not treat plain body lines as shell statements, while still permitting scrutiny of expansions such as parameter expansion, arithmetic expansion, and command substitution.Actual Behavior
The observed behavior is consistent with the filter scanning heredoc body bytes without distinguishing them from shell statements. It appears to have some awareness of common quoting forms in ordinary bash arguments. In the tested heredoc cases, the observed behavior does not distinguish between:
<<DELIM...DELIM) and ordinary bash arguments.<<'DELIM'produces a literal body; the filter still scans it).The heredoc-body behavior also appears stricter than the quoted-argument behavior:
echo "kill"passes, but a heredoc body containing onlykillis rejected. Whole-word boundaries are respected (killedandjust-kill-somethingpass), so the trigger is whole-word token interception inside heredoc data rather than substring matching.Impact
edheredocs carry source files whose contents mentionkill— including Lisp code with'killsymbols, shell scripts that documentkillsemantics, or any source that includes the wordkillnear a line boundary.Environment
edheredocs whose contents contain the wordkillin code, prose, or symbol names.Suggested Fix
A heredoc-aware filter would:
<<'DELIM', exclude the body from command-token interception entirely.<<DELIM, distinguish ordinary heredoc text from executable syntax introduced by expansions such as$(...), backticks, arithmetic expansion, or parameter expansion. Plain body text likekill the lightswould not be intercepted as a command, while command substitutions that bash would actually execute could still be inspected.Note: the filter already passes the tested single-quoted strings, double-quoted strings,
$'...'strings, and simple quoted-assignment-plus-expansion case. This report suggests comparable heredoc awareness.Related
sessiontool). Both reports describe behavior of the interception filter when text containing command-like tokens flows through contexts (bash heredoc framing in this report; tool-argument boundaries in Bug: CLI intercepts command names in text responses and attempts to execute them #774) where bash itself would not treat the text as shell statements.Note: Together with #774, this report describes interception behavior across multiple text-bearing contexts. The filter passes several tested bash quoting/data contexts, so a change for heredoc handling could be scoped specifically to heredoc parsing.
Affected version
GitHub Copilot CLI 1.0.48.
Steps to reproduce the behavior
No response
Expected behavior
No response
Additional context
No response