Skip to content

Sentences containing the word kill in a heredoc body are misinterpreted as kill commands #3334

@diamond-lizard

Description

@diamond-lizard

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

  1. 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.
  2. The outer command is the program receiving the heredoc; the heredoc body is data, not shell statements.
  3. 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:

  1. Parse the bash command to identify heredoc openers and locate their matching closing delimiter lines.
  2. For quoted heredocs such as <<'DELIM', exclude the body from command-token interception entirely.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions