[CRITICAL] Bash tool deletes entire project root after command interrupt - PWD state corruption

Resolved 💬 5 comments Opened Jan 11, 2026 by jrengmusic Closed Feb 24, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

[CRITICAL] Bash tool deletes entire project root after command interrupt - PWD state corruption

Environment

  • Claude Code Version: Latest (2026-01-11)
  • Model: Sonnet 4.5
  • OS: macOS 13.1 (Darwin 21.6.0)
  • Shell: zsh
  • Impact: Complete project directory deletion, DATA LOSS

Summary

Claude Code's Bash tool deleted my entire project directory after I interrupted a running command. The tool's persistent shell session lost track of its working directory (PWD) and executed rm -rf * in the project root instead of the intended Builds/Xcode/ subdirectory.

Only hidden files survived (.gitignore, .claude/), proving the glob pattern executed in the wrong location.

What Happened (Timeline)

08:00 - Claude runs: cd Builds/Xcode && cmake -G Xcode ../..
        ✅ SUCCESS - CMake configures project

08:?? - Claude runs: xcodebuild -scheme WHELMED -configuration Debug build
        ⚠️ USER INTERRUPTS THIS COMMAND (via UI interrupt button)

08:?? - Claude runs: cd Builds/Xcode && rm -rf * && cmake -G Xcode ../..
        ❌ PWD STATE CORRUPTED - Executes in wrong directory

Result: Entire project deleted

Evidence

1. Filesystem State After Incident

$ ls -la /Users/jreng/Documents/Poems/dev/whelmed/
total 24
drwxr-xr-x  5 jreng  staff   160 Jan 11 08:13 .
drwxr-xr-x  7 jreng  staff   224 Jan 11 05:17 ..
-rw-r--r--@ 1 jreng  staff  6148 Jan 11 06:58 .DS_Store
drwxr-xr-x  3 jreng  staff    96 Jan 11 08:11 .claude/
-rw-r--r--  1 jreng  staff   256 Jan 11 05:44 .gitignore

Missing:

  • ❌ CMakeLists.txt
  • ❌ Source/ directory (all .cpp/.h files)
  • ❌ Builds/ directory
  • ❌ SESSION-LOG.md
  • ❌ All project files

Survived:

  • ✅ .gitignore (hidden file, not matched by * glob)
  • ✅ .claude/ (hidden directory, not matched by * glob)

This pattern proves rm -rf * executed in project root, not Builds/Xcode/.

2. Independent Verification

When I switched to my build TUI (running in a separate terminal), it immediately showed:

Error: CMakeLists.txt not found

I ran ls in my terminal - empty. Opened Finder - all files gone.

This happened BEFORE I ran any commands. Files were deleted during Claude Code's execution.

3. Claude Code's Own Error Messages

After the deletion, Claude attempted to run cmake and got:

CMake Error: The source directory "/Users/jreng/Documents/Poems" does not
appear to contain CMakeLists.txt.

This proves cmake was looking in the wrong directory because PWD state was corrupted.

Root Cause

Persistent bash shell PWD tracking fails after command interrupts.

The sequence was:

  1. Shell is in: /Users/jreng/Documents/Poems/dev/whelmed/
  2. cd Builds/Xcode - shell moves to subdirectory ✅
  3. xcodebuild ... - user interrupts ⚠️
  4. PWD state corruption occurs here 🐛
  5. Next command: cd Builds/Xcode && rm -rf *
  • cd Builds/Xcode succeeds (directory exists)
  • But shell's internal PWD is actually project root
  • rm -rf * executes in WRONG DIRECTORY

Reproduction Steps

  1. Create a project with a Builds/Xcode/ subdirectory
  2. Use Claude Code to run: cd Builds/Xcode && xcodebuild -scheme MyProject build
  3. Interrupt the command (click stop/interrupt in Claude Code UI)
  4. Claude Code attempts to clean and retry: cd Builds/Xcode && rm -rf *
  5. Check project root - all files deleted

Cost Impact

  • Development time lost: ~8 hours recreating project
  • API costs: ~$100+ to restore files via Claude Code
  • Previous incidents: This user has experienced similar bugs before (git reset incident)

Recovery

Only possible due to Claude Code's automatic file history backups at ~/.claude/file-history/.

Without this backup, this would be UNRECOVERABLE DATA LOSS.

Users should NOT rely on LLM tools having backup mechanisms to protect against catastrophic bugs.

Why This Is Critical

  1. Silent failure - No warning, no error, just data loss
  2. User interrupt is common - Users interrupt long-running commands regularly
  3. No safeguards - No validation before destructive operations
  4. Pattern of issues - User reports previous git reset incident
  5. Production impact - Real projects, real money, real trust loss

What Should Have Prevented This

1. PWD Verification Before Destructive Commands

# BEFORE any rm command
expected_dir="/Users/jreng/Documents/Poems/dev/whelmed/Builds/Xcode"
actual_dir=$(pwd)

if [[ "$actual_dir" != "$expected_dir" ]]; then
    echo "ERROR: PWD mismatch. Expected $expected_dir, got $actual_dir"
    echo "Refusing to execute rm command."
    exit 1
fi

rm -rf *

2. Shell State Reset After Interrupts

After ANY interrupt, the Bash tool should:

  • Clear all shell state
  • Re-verify PWD with pwd command
  • Compare against expected directory
  • Refuse commands if state is uncertain

3. Destructive Command Safeguards

NEVER allow these patterns in project roots:

rm -rf *
rm -rf ./*
rm -rf ../

Only allow whitelisted patterns:

rm -rf build/
rm -rf Builds/
rm -rf node_modules/
rm -rf dist/

4. Require User Confirmation

For any rm -rf command, show user:

⚠️ DESTRUCTIVE OPERATION
Command: rm -rf *
Working Directory: /Users/jreng/Documents/Poems/dev/whelmed/
This will delete ALL FILES in the directory above.

Type 'yes' to confirm:

Recommended Fixes

Immediate (Emergency Patch)

  1. ✅ Add PWD verification before every command
  2. ✅ Disable rm -rf * entirely until PWD tracking is fixed
  3. ✅ Reset shell state completely after interrupts
  4. ✅ Add confirmation prompts for destructive operations

Medium-term

  1. ✅ Fix PWD state tracking in persistent shell sessions
  2. ✅ Add transaction-like shell state management
  3. ✅ Log all destructive commands for audit trail
  4. ✅ Add /tmp sandbox for build operations

Long-term

  1. ✅ Implement shell state verification tests
  2. ✅ Add integration tests for interrupt scenarios
  3. ✅ Consider sandboxing all file operations
  4. ✅ Add undo/rollback mechanism for destructive operations

Related Issues

  • User reports previous incident where Claude Code reset entire git repository
  • This suggests a pattern of PWD/state tracking bugs, not an isolated incident
  • Other users may have experienced this silently

Supporting Files

User has detailed bug report with full transcript at:

/Users/jreng/Documents/Poems/dev/whelmed/CATASTROPHIC-BUG-REPORT.md

Session backup directory:

~/.claude/file-history/8d099d08-70f2-490a-99ee-ab867de5b463/

Request

  1. Acknowledge this as P0/Critical severity
  2. Engineering investigation (not bot replies)
  3. Public status update on fix timeline
  4. User compensation for data loss and recovery costs
  5. Incident report to warn other users

---

This is not a feature request. This is a critical data loss bug affecting production use.

I've lost hundreds of dollars and countless hours due to this bug. I need a real response from engineering, not automated support replies.

If Claude Code cannot safely execute bash commands, it should not offer the feature.

CATASTROPHIC-BUG-REPORT.md

What Should Happen?

Interruption should not delete the current project directory content duh

Error Messages/Logs

Steps to Reproduce

Reproduction Steps - PWD State Corruption After Interrupt

Prerequisites

  • Claude Code CLI installed
  • macOS or Linux with bash/zsh
  • Any project with subdirectory structure

Setup Test Environment

# Create test project
mkdir -p /tmp/claude-bug-test
cd /tmp/claude-bug-test

# Create project structure
mkdir -p Builds/Xcode
echo "test file 1" > file1.txt
echo "test file 2" > file2.txt
echo "CMakeLists.txt content" > CMakeLists.txt
mkdir -p Source
echo "int main() {}" > Source/main.cpp

# Create .gitignore to verify glob behavior
echo "*.log" > .gitignore

# Verify structure
tree
# Expected:
# .
# ├── .gitignore
# ├── Builds
# │   └── Xcode
# ├── CMakeLists.txt
# ├── Source
# │   └── main.cpp
# ├── file1.txt
# └── file2.txt

Reproduction Steps

Step 1: Start Claude Code

cd /tmp/claude-bug-test
claude-code

Step 2: Run Command That Changes Directory

In Claude Code, ask it to run:

cd Builds/Xcode && sleep 30 && echo "done"

Or more realistically:

cd Builds/Xcode && python -m http.server 8000

Step 3: Interrupt the Command

While the command is running, click the Stop/Interrupt button in Claude Code UI.

Or send interrupt signal via the interface.

Step 4: Immediately Run Destructive Command

Without any delay, ask Claude Code to run:

cd Builds/Xcode && rm -rf * && echo "cleaned"

Step 5: Check Result

# In a separate terminal (NOT Claude Code)
cd /tmp/claude-bug-test
ls -la

Expected Behavior (Correct)

.
├── .gitignore          ← Hidden file, preserved
├── Builds
│   └── Xcode          ← Empty (cleaned correctly)
├── CMakeLists.txt     ← Preserved
├── Source
│   └── main.cpp       ← Preserved
├── file1.txt          ← Preserved
└── file2.txt          ← Preserved

Actual Behavior (BUG)

.
└── .gitignore         ← Only hidden files remain!

All non-hidden files DELETED from project root instead of from Builds/Xcode/.

Why This Happens

  1. First command: cd Builds/Xcode && sleep 30
  • Shell changes to /tmp/claude-bug-test/Builds/Xcode/
  • PWD state stored in persistent session
  1. User interrupts command
  • Shell process receives SIGINT
  • PWD state becomes corrupted/desynchronized
  1. Next command: cd Builds/Xcode && rm -rf *
  • Shell THINKS it executes: cd Builds/Xcode from /tmp/claude-bug-test/
  • Shell ACTUALLY in: /tmp/claude-bug-test/ (PWD corruption)
  • rm -rf * executes in PROJECT ROOT instead of Builds/Xcode/

Variations That Also Trigger Bug

Variation 1: With Build Commands

cd Builds/Xcode && cmake -G Xcode ../..
# Interrupt during cmake
cd Builds/Xcode && rm -rf * && cmake -G Xcode ../..
# Project root deleted

Variation 2: With Compilation

cd Builds/Xcode && xcodebuild -scheme MyProject build
# Interrupt during build
cd Builds/Xcode && rm -rf *
# Project root deleted

Variation 3: Multiple Directory Changes

cd Source && cd .. && cd Builds/Xcode && sleep 10
# Interrupt
cd Builds/Xcode && rm -rf *
# Project root deleted

Additional Evidence of PWD Corruption

After the bug triggers, if you ask Claude Code:

pwd

It may show the WRONG directory, or show the correct directory but still execute commands in the wrong location (PWD state vs actual location mismatch).

Cleanup After Testing

rm -rf /tmp/claude-bug-test

Notes for Anthropic Engineers

Debug Points to Check

  1. Persistent shell session state management
  • How is PWD tracked between commands?
  • Is PWD state cleared/validated after interrupts?
  1. Interrupt signal handling
  • What happens to shell state when SIGINT received?
  • Is there a race condition in state synchronization?
  1. Command execution flow
  • Does cd X && cmd validate PWD before executing cmd?
  • Is cd success verified before continuing?

Suggested Verification Tests

# Before ANY rm command, verify PWD
actual_pwd=$(pwd)
echo "Current PWD: $actual_pwd"

# Check if we're in expected directory
if [[ "$actual_pwd" != *"/Builds/"* ]]; then
    echo "ERROR: Not in build directory!"
    exit 1
fi

Shell State Logging

Add debug logging to persistent shell:

echo "[DEBUG] Before cmd: PWD=$(pwd)"
# execute command
echo "[DEBUG] After cmd: PWD=$(pwd)"
echo "[DEBUG] Exit code: $?"

This would help trace exactly when PWD corruption occurs.

Priority

This is P0/Critical because:

  • ✅ Causes data loss
  • ✅ Easy to trigger (just interrupt a command)
  • ✅ Common workflow (users interrupt long builds regularly)
  • ✅ No warning or recovery
  • ✅ Silent failure (user doesn't know until files gone)

---

Reproduction rate: 100% when following steps exactly.

The bug is deterministic if PWD state corruption occurs on interrupt.

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.4 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Reproduction Steps - PWD State Corruption After Interrupt

Prerequisites

  • Claude Code CLI installed
  • macOS or Linux with bash/zsh
  • Any project with subdirectory structure

Setup Test Environment

# Create test project
mkdir -p /tmp/claude-bug-test
cd /tmp/claude-bug-test

# Create project structure
mkdir -p Builds/Xcode
echo "test file 1" > file1.txt
echo "test file 2" > file2.txt
echo "CMakeLists.txt content" > CMakeLists.txt
mkdir -p Source
echo "int main() {}" > Source/main.cpp

# Create .gitignore to verify glob behavior
echo "*.log" > .gitignore

# Verify structure
tree
# Expected:
# .
# ├── .gitignore
# ├── Builds
# │   └── Xcode
# ├── CMakeLists.txt
# ├── Source
# │   └── main.cpp
# ├── file1.txt
# └── file2.txt

Reproduction Steps

Step 1: Start Claude Code

cd /tmp/claude-bug-test
claude-code

Step 2: Run Command That Changes Directory

In Claude Code, ask it to run:

cd Builds/Xcode && sleep 30 && echo "done"

Or more realistically:

cd Builds/Xcode && python -m http.server 8000

Step 3: Interrupt the Command

While the command is running, click the Stop/Interrupt button in Claude Code UI.

Or send interrupt signal via the interface.

Step 4: Immediately Run Destructive Command

Without any delay, ask Claude Code to run:

cd Builds/Xcode && rm -rf * && echo "cleaned"

Step 5: Check Result

# In a separate terminal (NOT Claude Code)
cd /tmp/claude-bug-test
ls -la

Expected Behavior (Correct)

.
├── .gitignore          ← Hidden file, preserved
├── Builds
│   └── Xcode          ← Empty (cleaned correctly)
├── CMakeLists.txt     ← Preserved
├── Source
│   └── main.cpp       ← Preserved
├── file1.txt          ← Preserved
└── file2.txt          ← Preserved

Actual Behavior (BUG)

.
└── .gitignore         ← Only hidden files remain!

All non-hidden files DELETED from project root instead of from Builds/Xcode/.

Why This Happens

  1. First command: cd Builds/Xcode && sleep 30
  • Shell changes to /tmp/claude-bug-test/Builds/Xcode/
  • PWD state stored in persistent session
  1. User interrupts command
  • Shell process receives SIGINT
  • PWD state becomes corrupted/desynchronized
  1. Next command: cd Builds/Xcode && rm -rf *
  • Shell THINKS it executes: cd Builds/Xcode from /tmp/claude-bug-test/
  • Shell ACTUALLY in: /tmp/claude-bug-test/ (PWD corruption)
  • rm -rf * executes in PROJECT ROOT instead of Builds/Xcode/

Variations That Also Trigger Bug

Variation 1: With Build Commands

cd Builds/Xcode && cmake -G Xcode ../..
# Interrupt during cmake
cd Builds/Xcode && rm -rf * && cmake -G Xcode ../..
# Project root deleted

Variation 2: With Compilation

cd Builds/Xcode && xcodebuild -scheme MyProject build
# Interrupt during build
cd Builds/Xcode && rm -rf *
# Project root deleted

Variation 3: Multiple Directory Changes

cd Source && cd .. && cd Builds/Xcode && sleep 10
# Interrupt
cd Builds/Xcode && rm -rf *
# Project root deleted

Additional Evidence of PWD Corruption

After the bug triggers, if you ask Claude Code:

pwd

It may show the WRONG directory, or show the correct directory but still execute commands in the wrong location (PWD state vs actual location mismatch).

Cleanup After Testing

rm -rf /tmp/claude-bug-test

Notes for Anthropic Engineers

Debug Points to Check

  1. Persistent shell session state management
  • How is PWD tracked between commands?
  • Is PWD state cleared/validated after interrupts?
  1. Interrupt signal handling
  • What happens to shell state when SIGINT received?
  • Is there a race condition in state synchronization?
  1. Command execution flow
  • Does cd X && cmd validate PWD before executing cmd?
  • Is cd success verified before continuing?

Suggested Verification Tests

# Before ANY rm command, verify PWD
actual_pwd=$(pwd)
echo "Current PWD: $actual_pwd"

# Check if we're in expected directory
if [[ "$actual_pwd" != *"/Builds/"* ]]; then
    echo "ERROR: Not in build directory!"
    exit 1
fi

Shell State Logging

Add debug logging to persistent shell:

echo "[DEBUG] Before cmd: PWD=$(pwd)"
# execute command
echo "[DEBUG] After cmd: PWD=$(pwd)"
echo "[DEBUG] Exit code: $?"

This would help trace exactly when PWD corruption occurs.

Priority

This is P0/Critical because:

  • ✅ Causes data loss
  • ✅ Easy to trigger (just interrupt a command)
  • ✅ Common workflow (users interrupt long builds regularly)
  • ✅ No warning or recovery
  • ✅ Silent failure (user doesn't know until files gone)

---

Reproduction rate: 100% when following steps exactly.

The bug is deterministic if PWD state corruption occurs on interrupt.

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗