Add security and best_practices validators
This commit is contained in:
@@ -1,64 +1,35 @@
|
|||||||
"""Security vulnerability scanning module."""
|
"""Security vulnerability scanning."""
|
||||||
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from ..models import Rule, Finding
|
from ..models import Rule, Finding
|
||||||
|
|
||||||
|
|
||||||
class SecurityValidator:
|
class SecurityValidator:
|
||||||
"""Scans shell scripts for security vulnerabilities."""
|
|
||||||
|
|
||||||
DEFAULT_PATTERNS = [
|
DEFAULT_PATTERNS = [
|
||||||
Rule(
|
Rule(
|
||||||
id="SECURITY001",
|
id="SECURITY001", name="Unquoted variable",
|
||||||
name="Unquoted variable",
|
pattern=r"(?<![\"])(\$[a-zA-Z_][a-zA-Z0-9_]*)(?![\"])", severity="high",
|
||||||
pattern=r"(?<![\"'])(\$[a-zA-Z_][a-zA-Z0-9_]*)(?![\"'])",
|
|
||||||
severity="high",
|
|
||||||
message="Unquoted variable can cause word splitting and glob expansion",
|
message="Unquoted variable can cause word splitting and glob expansion",
|
||||||
suggestion="Always quote variables: \"$VAR\" instead of $VAR",
|
suggestion="Always quote variables: \"$VAR\" instead of $VAR",
|
||||||
),
|
),
|
||||||
Rule(
|
Rule(
|
||||||
id="SECURITY002",
|
id="SECURITY002", name="Command substitution",
|
||||||
name="Command substitution in variable context",
|
pattern=r"\$\([^)]+\)", severity="high",
|
||||||
pattern=r"\$\([^)]+\)",
|
|
||||||
severity="high",
|
|
||||||
message="Command substitution can be exploited if output contains special characters",
|
message="Command substitution can be exploited if output contains special characters",
|
||||||
suggestion="Validate and sanitize command substitution output",
|
suggestion="Validate and sanitize command substitution output",
|
||||||
),
|
),
|
||||||
Rule(
|
Rule(
|
||||||
id="SECURITY003",
|
id="SECURITY003", name="Path traversal pattern",
|
||||||
name="Path traversal pattern",
|
pattern=r"\$\w+/\.\./|\$\w+/\.\.\$", severity="high",
|
||||||
pattern=r"\$\w+/\.\./|\$\w+/\.\.\$",
|
|
||||||
severity="high",
|
|
||||||
message="Path traversal detected with variable - potential security vulnerability",
|
message="Path traversal detected with variable - potential security vulnerability",
|
||||||
suggestion="Validate and normalize paths. Use realpath() or similar to resolve paths.",
|
suggestion="Validate and normalize paths. Use realpath() or similar.",
|
||||||
),
|
|
||||||
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):
|
def __init__(self, custom_rules=None):
|
||||||
"""Initialize the security validator with optional custom rules."""
|
|
||||||
self.rules = self.DEFAULT_PATTERNS.copy()
|
self.rules = self.DEFAULT_PATTERNS.copy()
|
||||||
if custom_rules:
|
if custom_rules:
|
||||||
self.rules.extend(custom_rules)
|
self.rules.extend(custom_rules)
|
||||||
|
|
||||||
def validate(self, content: str, line_number: Optional[int] = None) -> List[Finding]:
|
def validate(self, content, line_number=None):
|
||||||
"""Validate content for security vulnerabilities."""
|
|
||||||
findings = []
|
findings = []
|
||||||
for rule in self.rules:
|
for rule in self.rules:
|
||||||
if not rule.enabled:
|
if not rule.enabled:
|
||||||
@@ -68,17 +39,3 @@ class SecurityValidator:
|
|||||||
finding = Finding.from_match(rule, match, line_number, content)
|
finding = Finding.from_match(rule, match, line_number, content)
|
||||||
findings.append(finding)
|
findings.append(finding)
|
||||||
return findings
|
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