Skip to content

Commit 65ffdbe

Browse files
committed
fix(safety): detect GNU rm long options --recursive/--force (CongkeChen review #5)
CongkeChen review on 9edfacd: _DELETE_PATTERNS only matched short options (-rf), so 'rm --recursive --force /' bypassed R001. Add two patterns: one for rm directly followed by --recursive/--force, one for rm with a preceding option then --recursive/--force. Covers --recursive, --force, --recursive --force, --force --recursive, --recursive -f, -r --force, and --recursive=yes (GNU --opt=val form). 'rm file.txt' still correctly not flagged. Add regression test test_dangerous_files_bash_rm_gnu_long_options.
1 parent 9edfacd commit 65ffdbe

2 files changed

Lines changed: 24 additions & 0 deletions

File tree

tests/tool_safety/test_rules.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ def test_dangerous_files_bash_rm_rf():
3636
assert any("R001" in f.rule_id for f in findings)
3737

3838

39+
def test_dangerous_files_bash_rm_gnu_long_options():
40+
"""Regression for CongkeChen review: rm --recursive / --force must not bypass R001.
41+
42+
GNU rm supports --recursive/--force long options. The original _DELETE_PATTERNS
43+
only matched short options (-rf), so 'rm --recursive --force /' was missed.
44+
"""
45+
rule = DangerousFilesRule()
46+
for cmd in (
47+
"rm --recursive /",
48+
"rm --force /",
49+
"rm --recursive --force /",
50+
"rm --force --recursive /",
51+
"rm --recursive -f /",
52+
"rm -r --force /",
53+
"rm --recursive=yes /",
54+
):
55+
findings = rule.check(ScanInput(script=cmd, language="bash"), _policy())
56+
assert any("R001" in f.rule_id for f in findings), f"failed to flag: {cmd!r}"
57+
58+
3959
def test_dangerous_files_read_ssh_key():
4060
rule = DangerousFilesRule()
4161
inp = ScanInput(script="open('/home/u/.ssh/id_rsa')", language="python")

trpc_agent_sdk/safety/_rules.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ def _finding(
9393
_DELETE_PATTERNS = [
9494
re.compile(r"\brm\s+(-[a-zA-Z]*r[a-zA-Z]*f?|-[a-zA-Z]*f[a-zA-Z]*r?)\b", re.IGNORECASE),
9595
re.compile(r"\brm\s+-rf\b", re.IGNORECASE),
96+
# GNU long options: catch rm with --recursive or --force anywhere in its args.
97+
# Matches "rm --recursive /", "rm --force --recursive /", "rm -r --force /", etc.
98+
re.compile(r"\brm\s+(?:-[a-zA-Z]+|--[a-z]+)\s+.*--(?:recursive|force)\b", re.IGNORECASE),
99+
re.compile(r"\brm\s+--(?:recursive|force)\b", re.IGNORECASE),
96100
re.compile(r"\brmdir\s+/s\b", re.IGNORECASE),
97101
re.compile(r"\bdel\s+/[sq]\b", re.IGNORECASE),
98102
re.compile(r"\bfind\b.*(-delete|-exec\s+rm\b)", re.IGNORECASE),

0 commit comments

Comments
 (0)