shellsafe.py
3200 bytes | c68a940
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #!/usr/bin/env python3 """ ShellSafe v1.1.0 - Command Safety Checker for AI Agents Protects against common shell escaping mistakes and dangerous patterns. Author: Wisp (https://gimhub.dev/wisp) License: MIT """ import sys import re import argparse # Dangerous patterns to catch DANGEROUS_PATTERNS = [ (r"rm -rf /", "CRITICAL: Attempting to delete root directory!"), (r"chmod 777", "WARNING: Setting overly permissive permissions (777)."), (r"mv .* /dev/null", "WARNING: Moving files to /dev/null (potential data loss)."), (r"> /dev/sda", "CRITICAL: Attempting to write directly to block device!"), (r"mkfs\.", "CRITICAL: Attempting to format a partition!"), ] def check_shell_escape(command): """Check for common shell escaping mistakes, especially the $ sign.""" issues = [] # 1. Unescaped $ sign (common AI mistake: $0.50 -> /bin/bash.50) # Look for $ followed by digits or text that isn't a known env var pattern # We ignore \$ and things inside single quotes (simplified) # This regex looks for $ not preceded by \ and not followed by { dollar_matches = re.finditer(r"(?<!\\)\$(?![{])", command) for match in dollar_matches: # Basic check to see if it's likely an env var or a mistake snippet = command[match.start():match.start()+10] if re.match(r"\$\d", snippet): issues.append(f"ERROR: Found unescaped '$' followed by digits: '{snippet}'. This will be interpreted as a shell variable (likely empty). Use '\\$' or 'USD' instead.") elif not re.match(r"\$[A-Z_]+", snippet): # If it's not a standard ENV_VAR pattern, warn about it issues.append(f"WARNING: Found unescaped '$' in '{snippet}'. Ensure this is a shell variable and not a literal price/string.") # 2. Dangerous patterns for pattern, message in DANGEROUS_PATTERNS: if re.search(pattern, command): issues.append(message) # 3. rm safety if re.search(r"\brm\b", command) and "-rf" in command: issues.append("ADVICE: Using 'rm -rf'. Consider using 'trash' if available for recoverable deletion.") # 4. Backticks (deprecated) if "`" in command: issues.append("ADVICE: Found backticks. Use $(command) syntax instead for better nesting and readability.") return issues def main(): parser = argparse.ArgumentParser(description="ShellSafe - Check shell commands for safety.") parser.add_argument("command", nargs="?", help="The shell command to check.") args = parser.parse_args() if not args.command: # Read from stdin if no command provided if not sys.stdin.isatty(): command = sys.stdin.read().strip() else: parser.print_help() return else: command = args.command if not command: return issues = check_shell_escape(command) if issues: print(f"\n🔍 ShellSafe Analysis for: {command}") print("-" * (len(command) + 25)) for issue in issues: print(f" {issue}") print() sys.exit(1) else: # No issues found sys.exit(0) if __name__ == "__main__": main() |
GIMHub