Skip to content

fix(guard): detect catastrophic 'rm -rf .', '~', '*', '$HOME' (#470) - #480

Open
Rubyglask wants to merge 2 commits into
aliasrobotics:mainfrom
Rubyglask:fix/catastrophic-rm-guard
Open

fix(guard): detect catastrophic 'rm -rf .', '~', '*', '$HOME' (#470)#480
Rubyglask wants to merge 2 commits into
aliasrobotics:mainfrom
Rubyglask:fix/catastrophic-rm-guard

Conversation

@Rubyglask

Copy link
Copy Markdown

Summary

Fixes #470. CAI's sensitive-command guard is meant to prompt before dangerous
shell commands, but it never prompted on the most common way to wipe data:
rm -rf ., rm -rf ~, rm -rf *. A user reported CAI running rm -rf .
and deleting their home directory with no confirmation.

Root cause (src/cai/util/user_prompts.py)

Two things meant rm was effectively unguarded:

  1. The rm entry in _SENSITIVE_PATTERNS required the target to contain /:
    (r"rm\s+(-[^\s]*)*(r|f){2,}.*\s+/", "Recursive/forced removal from root filesystem", "destructive"),
    so rm -rf . / ~ / * / $HOME (no /) were never matched.
  2. Even the forms it did match textually (rm -rf /) never actually prompted:
    the destructive category is refined by a binary post-check in
    detect_sensitive_command (_DESTRUCTIVE_TOOL_NAMES = {mkfs, wipefs, fdisk, parted, shred}), and rm isn't in that set, so the match is filtered out
    before it can prompt. (Your own test_sensitive_guard_false_positives.py
    documents this post-check.) In practice the rm pattern never fired.

Net effect: no rm command prompted, including rm -rf . in #470.

Fix — a small predicate, not a regex

Add _is_catastrophic_rm(command), checked after the pattern loop so
sudo rm -rf / still resolves to the sudo category (it matches earlier). It
shlex-tokenizes, splits on shell operators (&&, ||, ;, |), and flags a
recursive rm whose target is a catastrophic root (., .., ~, $HOME,
*, /) or a top-level system directory (/etc, /home, …), including a glob
of their contents (~/*, ./*, /home/*).

It still prompts (never hard-blocks), and the guard still fails safe on the
headless-menu timeout — so this changes detection only, consistent with every
other pattern.

Coverage (before → after)

command before after
rm -rf . (the #470 command) no prompt prompt
rm -rf ~ · rm -rf * · rm -rf $HOME no prompt prompt
rm -rf ~/* · rm -rf /home/* no prompt prompt
rm -rf /etc · rm -rf / no prompt¹ prompt
rm -rf ./build · rm -rf /tmp/scratch (legit) no prompt no prompt
rm -rf ./build && cd ~ (legit compound) no prompt no prompt
sudo rm -rf / prompt (sudo) prompt (sudo)

¹ matched the old regex textually but was filtered by the destructive
binary post-check, so it never prompted.

The fix adds a prompt for the bare catastrophic forms (that's the point of
#470) while leaving legitimate named sub-paths (./build, /tmp/scratch,
node_modules, …) unflagged — no new false positives, verified by the tests.

Tests

tests/tools/test_catastrophic_rm_guard.py — parametrized catastrophic vs.
legitimate commands, asserted through both _is_catastrophic_rm and
detect_sensitive_command (category destructive), plus sudo rm -rf / still
sudo and the disabled-guard path. The existing
test_sensitive_guard_false_positives.py keeps passing.

Scope / notes

  • A heuristic for an interactive confirmation, not a sandbox. Deliberately
    obfuscated forms are out of scope, left to other guards / the model's
    judgement: command substitution ($(pwd)), wrapper binaries (env rm,
    xargs rm), and non-rm tree deleters (find … -delete).
  • Bare rm -rf * / rm -rf . now prompt in cleanup flows too — intended; those
    are exactly the forms that wiped a home directory. Named targets don't prompt.
  • The system-directory list is exact-match (every sub-path passes); happy to
    narrow it if you'd prefer a smaller set.

Fixes #470

…obotics#470)

The sensitive-command guard's rm pattern required a '/' in the target, so rm -rf . / ~ / * were never prompted (and it never fired anyway -- filtered by the destructive binary post-check). Adds _is_catastrophic_rm(); prompts on the catastrophic forms, leaves named sub-paths alone. Test-only additions to tests/tools/.
Add tests for catastrophic 'rm' command detection in the guard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CAI Deleted my Computer

1 participant