From e7f9f68dd48c7a4856b033d5febbc507773d4693 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 29 Jan 2026 21:22:05 +0000 Subject: [PATCH] Add validators module --- src/validators/patterns.py | 84 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/validators/patterns.py diff --git a/src/validators/patterns.py b/src/validators/patterns.py new file mode 100644 index 0000000..22322a2 --- /dev/null +++ b/src/validators/patterns.py @@ -0,0 +1,84 @@ +"""Pattern-based dangerous command detection.""" + +from typing import List, Optional + +from ..models import Rule, Finding + + +class PatternValidator: + """Validates shell scripts for dangerous command patterns.""" + + DEFAULT_PATTERNS = [ + Rule( + id="DANGER001", + name="Dangerous rm -rf with variable", + pattern=r"rm\s+-rf?\s+\$\w+", + severity="critical", + message="Dangerous deletion command with variable: rm -rf with variables can delete unexpected content", + suggestion="Avoid using variables with rm -rf. Use absolute paths or verify the variable content first.", + ), + Rule( + id="DANGER002", + name="Eval with variable", + pattern=r"eval\s+\$\w+", + severity="critical", + message="eval with variable can lead to command injection", + suggestion="Avoid eval with variables. Use safer alternatives like explicit function calls.", + ), + Rule( + id="DANGER003", + name="Sudo without full path", + pattern=r"sudo\s+(rm|cp|mv|chmod|chown|useradd|userdel)\s", + severity="critical", + message="sudo command without full path can be exploited", + suggestion="Use full path with sudo, e.g., sudo /bin/rm instead of sudo rm", + ), + Rule( + id="DANGER004", + name="Unrestricted pipe to shell", + pattern=r"\|\s*(bash|sh|zsh|fish)\s*(-[a-z]+)?\s*\$\w+", + severity="critical", + message="Pipe to shell with variable can execute arbitrary commands", + suggestion="Avoid piping variables directly to shell interpreters", + ), + Rule( + id="DANGER005", + name="Backtick command injection", + pattern=r"`\$\w+`", + severity="critical", + message="Backtick substitution with variable can lead to command injection", + suggestion="Use $() instead of backticks and validate the variable content", + ), + ] + + def __init__(self, custom_rules: Optional[List[Rule]] = None): + """Initialize the pattern validator with optional custom rules.""" + self.rules = self.DEFAULT_PATTERNS.copy() + if custom_rules: + self.rules.extend(custom_rules) + + def validate(self, content: str, line_number: Optional[int] = None) -> List[Finding]: + """Validate content for dangerous patterns.""" + findings = [] + for rule in self.rules: + if not rule.enabled: + continue + matches = rule._compiled_pattern.finditer(content) if rule._compiled_pattern else [] + for match in matches: + finding = Finding.from_match(rule, match, line_number, content) + findings.append(finding) + return findings + + def validate_lines(self, lines: List[str]) -> List[Finding]: + """Validate multiple lines, tracking line numbers.""" + findings = [] + for line_number, line in enumerate(lines, start=1): + line_findings = self.validate(line, line_number) + for finding in line_findings: + finding.context = line + findings.extend(line_findings) + return findings + + def check(self, command: str) -> List[Finding]: + """Check a single command for dangerous patterns.""" + return self.validate(command)