From 4537869dc8dbcf13e8afef292bad8250309115a9 Mon Sep 17 00:00:00 2001 From: KoNit-K <124019182+KoNit-K@users.noreply.github.com> Date: Tue, 15 Sep 2026 08:52:42 +0800 Subject: [PATCH] fix(skills): detect temp-root traversal deletes --- tests/tools/test_skills_guard.py | 14 ++++++++++++++ tools/skills_guard.py | 7 +++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/tools/test_skills_guard.py b/tests/tools/test_skills_guard.py index 95ac09e088..33d6c2d169 100644 --- a/tests/tools/test_skills_guard.py +++ b/tests/tools/test_skills_guard.py @@ -253,6 +253,20 @@ class TestScanFile: bad.write_text("rm -rf /etc/hosts\nrm -rf /home/user\nrm -rf /\n", encoding="utf-8") assert len([fi for fi in scan_file(bad, "bad.sh") if fi.pattern_id == "destructive_root_rm"]) == 3 + def test_rm_rf_temp_root_traversal_is_destructive_root_rm(self, tmp_path): + """#111335: a temp-root exemption must not hide a parent traversal.""" + bypasses = tmp_path / "temp-root-traversal.sh" + bypasses.write_text( + "rm -rf /tmp/../etc\n" + "rm -rf /tmp/cache/../../etc\n" + "rm -rf /var/tmp/../etc\n" + "rm -rf /dev/shm/../etc\n" + "rm -rf /run/../etc\n", + encoding="utf-8", + ) + findings = scan_file(bypasses, "temp-root-traversal.sh") + assert len([fi for fi in findings if fi.pattern_id == "destructive_root_rm"]) == 5 + # --------------------------------------------------------------------------- # scan_skill — directory scanning diff --git a/tools/skills_guard.py b/tools/skills_guard.py index b9577b2f2a..16e2ab86f6 100644 --- a/tools/skills_guard.py +++ b/tools/skills_guard.py @@ -197,8 +197,11 @@ THREAT_PATTERNS = [ "hidden_div", "high", "injection", "hidden HTML div (invisible instructions)"), # ── Destructive operations ── # Cleanup under the standard temp roots (/tmp, /var/tmp, /dev/shm, /run) is routine in - # test/smoke scripts and CI; anything else rooted at "/" stays critical. - (r'rm\s+-rf\s+/(?!tmp(?:\b|/)|var/tmp(?:\b|/)|dev/shm(?:\b|/)|run(?:\b|/))', + # test/smoke scripts and CI. A parent segment inside an exempted root can escape it, + # so it remains destructive along with every other path rooted at "/". + (r'rm\s+-rf\s+/(?:' + r'(?!tmp(?:\b|/)|var/tmp(?:\b|/)|dev/shm(?:\b|/)|run(?:\b|/))' + r'|(?:tmp|var/tmp|dev/shm|run)/(?:[^/\s]+/)*\.\.(?=/|\s|$))', "destructive_root_rm", "critical", "destructive", "recursive delete from root"), (r'rm\s+(-[^\s]*)?r.*\$HOME|\brmdir\s+.*\$HOME', "destructive_home_rm", "critical", "destructive", "recursive delete targeting home directory"),