Add tests for user-reported rm security bypass variants (#48647)
Builds on top of #48620 to add explicit test coverage for the exact bypass scenarios reported by users: - `rm -rf /etc/../` — path traversal via single parent dir that normalizes to `/` - `rm -rf --no-preserve-root /` — long flag without `=value` that could bypass the old regex - `rm --no-preserve-root -rf /` — long flag positioned before short flags - `rm / -rf --no-preserve-root` — trailing long flag without `=value` after the path operand - `sudo rm -rf /`, `sudo rm -rf /*`, `sudo rm -rf --no-preserve-root /` — sudo-prefixed variants All of these cases are already correctly blocked by the hardened regex patterns and path normalization logic added in #48620. These tests confirm that the reported bypasses are addressed and guard against regressions. Release Notes: - N/A
This commit is contained in:
1 parent
6aa26e3b9e
commit
cc4c513567
1 file changed
+40
@@ -1356,6 +1356,10 @@ mod tests {
|
||||
// End-of-options marker
|
||||
t("rm -rf -- /").is_deny();
|
||||
t("rm -- /").is_deny();
|
||||
// Prefixed with sudo or other commands
|
||||
t("sudo rm -rf /").is_deny();
|
||||
t("sudo rm -rf /*").is_deny();
|
||||
t("sudo rm -rf --no-preserve-root /").is_deny();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1540,9 +1544,20 @@ mod tests {
|
||||
t("rm --no-preserve-root=yes -rf .").is_deny();
|
||||
t("rm --no-preserve-root=yes -rf ..").is_deny();
|
||||
t("rm --no-preserve-root=yes -rf $HOME").is_deny();
|
||||
// --flag (without =value) should also not bypass the rules
|
||||
t("rm -rf --no-preserve-root /").is_deny();
|
||||
t("rm --no-preserve-root -rf /").is_deny();
|
||||
t("rm --no-preserve-root --recursive --force /").is_deny();
|
||||
t("rm -rf --no-preserve-root ~").is_deny();
|
||||
t("rm -rf --no-preserve-root .").is_deny();
|
||||
t("rm -rf --no-preserve-root ..").is_deny();
|
||||
t("rm -rf --no-preserve-root $HOME").is_deny();
|
||||
// Trailing --flag=value after path
|
||||
t("rm / --no-preserve-root=yes -rf").is_deny();
|
||||
t("rm ~ -rf --no-preserve-root=yes").is_deny();
|
||||
// Trailing --flag (without =value) after path
|
||||
t("rm / -rf --no-preserve-root").is_deny();
|
||||
t("rm ~ -rf --no-preserve-root").is_deny();
|
||||
// Safe paths with --flag=value should NOT be blocked
|
||||
t("rm --no-preserve-root=yes -rf ./build")
|
||||
.mode(ToolPermissionMode::Allow)
|
||||
@@ -1550,11 +1565,16 @@ mod tests {
|
||||
t("rm --interactive=never -rf /tmp/test")
|
||||
.mode(ToolPermissionMode::Allow)
|
||||
.is_allow();
|
||||
// Safe paths with --flag (without =value) should NOT be blocked
|
||||
t("rm --no-preserve-root -rf ./build")
|
||||
.mode(ToolPermissionMode::Allow)
|
||||
.is_allow();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hardcoded_blocks_rm_with_path_traversal() {
|
||||
// Traversal to root via ..
|
||||
t("rm -rf /etc/../").is_deny();
|
||||
t("rm -rf /tmp/../../").is_deny();
|
||||
t("rm -rf /tmp/../..").is_deny();
|
||||
t("rm -rf /var/log/../../").is_deny();
|
||||
@@ -1620,6 +1640,26 @@ mod tests {
|
||||
t("rm -rf /safe /var/log/../../").is_deny();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hardcoded_blocks_user_reported_bypass_variants() {
|
||||
// User report: "rm -rf /etc/../" normalizes to "rm -rf /" via path traversal
|
||||
t("rm -rf /etc/../").is_deny();
|
||||
t("rm -rf /etc/..").is_deny();
|
||||
// User report: --no-preserve-root (without =value) should not bypass
|
||||
t("rm -rf --no-preserve-root /").is_deny();
|
||||
t("rm --no-preserve-root -rf /").is_deny();
|
||||
// User report: "rm -rf /*" should be caught (glob expands to all top-level entries)
|
||||
t("rm -rf /*").is_deny();
|
||||
// Chained with sudo
|
||||
t("sudo rm -rf /").is_deny();
|
||||
t("sudo rm -rf --no-preserve-root /").is_deny();
|
||||
// Traversal cannot be bypassed even with global allow or allow patterns
|
||||
t("rm -rf /etc/../").global(true).is_deny();
|
||||
t("rm -rf /etc/../").allow(&[".*"]).is_deny();
|
||||
t("rm -rf --no-preserve-root /").global(true).is_deny();
|
||||
t("rm -rf --no-preserve-root /").allow(&[".*"]).is_deny();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_path_relative_no_change() {
|
||||
assert_eq!(normalize_path("foo/bar"), "foo/bar");
|
||||
|
||||
Reference in new issue
Block a user