diff --git a/src/remoteshell_mcp/command_validator.py b/src/remoteshell_mcp/command_validator.py index 58ac4d0..5784ac8 100644 --- a/src/remoteshell_mcp/command_validator.py +++ b/src/remoteshell_mcp/command_validator.py @@ -48,8 +48,13 @@ class CommandValidator: (r'\bchmod\s+.*777\s+.*/', 'Modify root directory permissions'), (r'\bchown\s+.*root\s+.*/', 'Modify root directory ownership'), - # Other dangerous operations - (r'>\s*/dev/', 'Redirect to device file'), + # Other dangerous operations. + # Only block redirection to real storage devices (block devices that a + # stray write can destroy). Harmless character devices such as + # /dev/null, /dev/stdout, /dev/stderr, /dev/full are intentionally + # allowed: `2>/dev/null` is the standard idiom for discarding stderr. + (r'>\s*/dev/(?:sd[a-z]|hd[a-z]|vd[a-z]|xvd[a-z]|nvme|mmcblk|loop|mapper|sr\d|fd\d)', + 'Overwrite block device'), (r':\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;', 'Fork bomb'), (r'\bhalt\b', 'System halt'), (r'\bpoweroff\b', 'System poweroff'), diff --git a/tests/test_command_validator_integration.py b/tests/test_command_validator_integration.py index 5ba5378..b5a04b8 100644 --- a/tests/test_command_validator_integration.py +++ b/tests/test_command_validator_integration.py @@ -19,6 +19,9 @@ def test_command_validator_blocks_dangerous_commands(self): "rm -rf /root", "dd if=/dev/zero of=/dev/sda", "mkfs.ext4 /dev/sda", + "echo x > /dev/sda", + "echo x >/dev/nvme0n1", + "echo x > /dev/mapper/vg-root", "halt", "shutdown -h now", ":(){ :|:& };:", @@ -40,6 +43,10 @@ def test_command_validator_allows_safe_commands(self): "mkdir test_dir", "cp file1 file2", "grep pattern file.txt", + "echo hello 2>/dev/null", + "cmd > /dev/null 2>&1", + "cat /etc/hostname > /dev/full", + "echo x 1>/dev/stdout 2>/dev/stderr", ] for command in safe_commands: