Add validators module
This commit is contained in:
84
src/validators/security.py
Normal file
84
src/validators/security.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""Security vulnerability scanning module."""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from ..models import Rule, Finding
|
||||
|
||||
|
||||
class SecurityValidator:
|
||||
"""Scans shell scripts for security vulnerabilities."""
|
||||
|
||||
DEFAULT_PATTERNS = [
|
||||
Rule(
|
||||
id="SECURITY001",
|
||||
name="Unquoted variable",
|
||||
pattern=r"(?<![\"'])(\$[a-zA-Z_][a-zA-Z0-9_]*)(?![\"'])",
|
||||
severity="high",
|
||||
message="Unquoted variable can cause word splitting and glob expansion",
|
||||
suggestion="Always quote variables: \"$VAR\" instead of $VAR",
|
||||
),
|
||||
Rule(
|
||||
id="SECURITY002",
|
||||
name="Command substitution in variable context",
|
||||
pattern=r"\$\([^)]+\)",
|
||||
severity="high",
|
||||
message="Command substitution can be exploited if output contains special characters",
|
||||
suggestion="Validate and sanitize command substitution output",
|
||||
),
|
||||
Rule(
|
||||
id="SECURITY003",
|
||||
name="Path traversal pattern",
|
||||
pattern=r"\$\w+/\.\./|\$\w+/\.\.\$",
|
||||
severity="high",
|
||||
message="Path traversal detected with variable - potential security vulnerability",
|
||||
suggestion="Validate and normalize paths. Use realpath() or similar to resolve paths.",
|
||||
),
|
||||
Rule(
|
||||
id="SECURITY004",
|
||||
name="Shell metacharacter injection",
|
||||
pattern=r"[;&|\`$!#()*?<>{}]\s*\$\w+",
|
||||
severity="high",
|
||||
message="Shell metacharacters followed by variable can lead to injection",
|
||||
suggestion="Sanitize variables to remove or escape shell metacharacters",
|
||||
),
|
||||
Rule(
|
||||
id="SECURITY005",
|
||||
name="exec with shell variable",
|
||||
pattern=r"exec\s+.*\$\w+",
|
||||
severity="high",
|
||||
message="exec with variable can be exploited",
|
||||
suggestion="Avoid using variables with exec. Use explicit command paths.",
|
||||
),
|
||||
]
|
||||
|
||||
def __init__(self, custom_rules: Optional[List[Rule]] = None):
|
||||
"""Initialize the security 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 security vulnerabilities."""
|
||||
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 security vulnerabilities."""
|
||||
return self.validate(command)
|
||||
Reference in New Issue
Block a user