Bash tool timeout leaks pipeline children: bundled grep escaped kill, ran 11.5h at 1199% CPU reparented to systemd --user

Status Open
Reported on v2.1.216
Maintainer reply None cached
Activity 0 comments · opened Jul 21, 2026

Summary

When a Bash tool call hits its timeout, Claude Code kills the shell but not the full process group. A long-running child of the pipeline (in this case Claude Code's own bundled grep) escapes the kill, gets reparented to systemd --user, and runs unowned — in my case pinning ~12 cores at 1199% CPU for 11.5 hours (≈136 CPU-hours) until I found and killed it manually.

Environment

  • Claude Code 2.1.216 (Linux, installed under ~/.local/share/claude/versions/2.1.216)
  • Ubuntu, kernel 6.17.0-35-generic
  • Session was running a multi-agent workflow (ultracode effort); the offending command came from a subagent

What happened

  1. A workflow subagent ran this Bash tool call (note the search path is / — a bad scope choice by the agent, but that's the trigger, not the bug):

``
grep -rl "verified-execution marketplace\|proof-of-work\|Emerald Cloud Lab\|cross-credit\|Iris Publishers" / 2>/dev/null | grep -v "/proc/" | grep -v "\.git/" | grep -iE "\.md$|\.html$|\.json$|\.txt$" | grep -v "<project wiki path>" | head -30
``

  1. The command ran past the Bash tool timeout. The subagent's transcript shows it gave up on the result and moved on ("NOT available to me on disk").
  2. The shell was killed on timeout, but the first stage of the pipeline — Claude Code's bundled grep, still crawling / — was not killed. It was reparented to systemd --user (PID of parent became the user systemd instance) and kept running.
  3. ~11.5 hours later it was still running:

``
USER PID %CPU %MEM TIME COMMAND
johnd 2513823 1199 1.1 8197:49 ugrep -G --ignore-files --hidden -I --exclude-dir=.git ... -rl <patterns> /
``

``
$ ls -l /proc/2513823/exe
/proc/2513823/exe -> /home/johnd/.local/share/claude/versions/2.1.216
$ ps -o ppid= -p 2513823
7250 # /usr/lib/systemd/systemd --user
``

Confirming it's the Claude-bundled binary (argv0 ugrep, exe → the versioned claude binary) with no living Claude Code ancestor.

Expected behavior

On Bash tool timeout (and on session exit), Claude Code should kill the entire process group / session of the spawned command (e.g. spawn with setsid/new pgid and send SIGKILL to -pgid after the grace period), so pipeline children can't outlive the tool call. A belt-and-braces sweep of surviving descendants on session shutdown would also have caught this.

Impact

  • 136 CPU-hours wasted; machine degraded for an entire workday overnight
  • Because the leaked process is Claude's own bundled grep with argv0 ugrep, it's non-obvious to users where it came from (ugrep isn't even on PATH — which ugrep returns nothing, which makes it look like malware at first glance)
  • Any long-running child survives this way (find /, a hung network call, etc.); a filesystem-root grep just makes it maximally visible

Repro sketch

  1. In a session, have the model run a Bash command guaranteed to exceed the tool timeout where the long-running stage is piped into another stage, e.g. grep -rl pattern / 2>/dev/null | head -30
  2. Wait for the tool call to time out
  3. ps -eo pid,ppid,comm,args | grep -i grep — the crawler is still running, reparented away from the claude process

🤖 Filed with Claude Code on behalf of the user

View original on GitHub ↗