Now I have the full picture. Here's my analysis:
What 2.1.81 is: Claude Code v2.1.81. You had 5 Claude Code instances running at shutdown time.
Shutdown timeline:
- 01:36:33 — Force shutdown initiated
- 01:36:36 — Shutdown stall captured (162 processes still running, 21 of them Python)
- 01:37:11 — System booted
Process tree at shutdown:
Normal Claude Code MCP servers (2 instances):
Claude Code [82193] → python3.13 [88842] → node [88854] (416MB)
Claude Code [35621] → python3.13 [45088] → node [45091] (228MB)These are MCP server bridges — Python wraps a Node.js MCP server. Normal behavior.
A uv run chain:
zsh → uv [74172] (deadlocked) → python3.13 [74174] (running a .py file)
→ python3.13 [74180] (python -c "...", reading pipe)
→ python3.13 [86263] (running .py file, sleeping + os.stat)
→ python3.13 [86264] (python -c "...", reading pipe)14 orphaned python -c processes (two batches of 7):
- PIDs 89759-89765 (~38 hours old)
- PIDs 67956-67962 (different age)
- All running
_PyRun_SimpleStringFlagsWithName— this ispython -c "exec(base64.b64decode(...))" - All orphaned (parent died, reparented to launchd)
- All stuck reading from a dead pipe
What likely happened:
The exec(base64.b64decode('...')) pattern is not malware — it's how Python tooling (including Claude Code's Bash tool) passes code snippets to python -c while avoiding shell escaping issues. The base64 encoding is just a safe transport mechanism.
The 11k process storm was likely a runaway spawning loop from one of these sources:
- A Claude Code tool/agent interaction that got stuck in a loop spawning
python -cprocesses - A
uv runscript (the 74174 chain) that had a subprocess spawning bug
Good news:
- No persistence mechanisms found — no suspicious crontabs, launch agents, or launchd jobs
- No suspicious Python processes running now — clean after reboot
- All processes used your local uv Python — nothing from unknown paths
- No malicious indicators — all parents trace back to Claude Code, uv, or zsh
Recommendations:
- Check if you had a Claude Code agent running in a loop before the incident
- If it happens again, try
killall python3.13before force-shutting down - Consider setting a process limit:
ulimit -u 2048in your.zshrcto prevent fork bombs
Initial theory was completely wrong, Claude blaming Claude