# Copyright (c) 2026 MergeGuide, Inc. All rights reserved.
# SPDX-License-Identifier: Proprietary
"""Default built-in security policies."""

from __future__ import annotations

from mergeguide.engine.rules import Rule, RuleType, Severity

from .schema import Policy, PolicyFile, PolicyMetadata, PolicyRule

# Default policies as a PolicyFile
DEFAULT_POLICY_FILE = PolicyFile(
    version="1.0",
    metadata=PolicyMetadata(
        name="MergeGuide Default Policies",
        description="Built-in security and code quality policies",
        author="MergeGuide",
        url="https://github.com/MergeGuide/mergeguide",
    ),
    policies=[
        Policy(
            id="no-hardcoded-secrets",
            name="No Hardcoded Secrets",
            description="Detect potential hardcoded API keys, passwords, and tokens",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(api[_-]?key|apikey|api_secret|access[_-]?key|client[_-]?secret)\s*[=:]\s*['\"][a-zA-Z0-9_\-]{8,}['\"]",
                    message="Potential hardcoded API key detected",
                    flags="i",
                    remediation="Use environment variables or a secrets manager instead",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    pattern=r"(?i)(password|passwd|pwd)\s*[=:]\s*['\"][^\$'\"]{10,}['\"]",
                    message="Potential hardcoded password detected",
                    flags="i",
                    remediation="Use environment variables or a secrets manager instead",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    # BUG-224: Tightened to reduce false positives on clean code.
                    # Excludes common safe patterns: variable references (env vars,
                    # config lookups), placeholder/example values, and test fixtures.
                    # The negative lookahead after the value rejects known safe value
                    # patterns (placeholder, example, changeme, test, TODO, etc.).
                    pattern=r"(?i)(secret|token|auth[_-]?token|bearer)\s*[=:]\s*['\"](?!placeholder|example|changeme|your[_-]|test[_-]|TODO|REPLACE|xxx|dummy|sample|mock)[a-zA-Z0-9_\-]{16,}['\"]",
                    message="Potential hardcoded secret or token detected",
                    flags="i",
                    remediation="Use environment variables or a secrets manager instead",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    pattern=r"(?i)(aws_access_key_id|aws_secret_access_key)\s*[=:]\s*['\"][A-Z0-9]{16,}['\"]",
                    message="Potential hardcoded AWS credentials detected",
                    flags="i",
                    remediation="Use AWS IAM roles or environment variables instead",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    pattern=r"-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----",
                    message="Private key detected in source code",
                    remediation="Store private keys in a secure secrets manager",
                    cwe_id="CWE-321",
                ),
                PolicyRule(
                    # BUG-224: Removed overly broad prefixes (api, key, token) that
                    # caused false positives on common identifiers like "api_version",
                    # "key_name", "token_type". Kept high-confidence prefixes only.
                    # Raised minimum suffix length to 16 for ambiguous prefixes (sk, pk).
                    pattern=r"['\"](?:ghp|gho|ghu|ghs|ghr|glpat|pypi|npm|slack|xox[baprs])[_\-]?[a-zA-Z0-9]{8,}['\"]"
                    r"|['\"](?:sk|pk)[_\-][a-zA-Z0-9]{16,}['\"]",
                    message="Potential API key with known prefix detected",
                    remediation="Use environment variables or a secrets manager instead",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="no-console-log",
            name="No Console Log in Production",
            description="Prevent console.log statements in production code",
            severity="info",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"console\.(log|debug)\s*\(",
                    message="console.log/debug statement detected (code quality, not security)",
                    remediation="Use a proper logging library with configurable log levels",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-todo-in-code",
            name="No TODO Comments",
            description="Flag TODO and FIXME comments for tracking",
            severity="info",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)\b(TODO|FIXME|HACK|XXX)\b[:\s]",
                    message="TODO/FIXME comment detected",
                    flags="i",
                    remediation="Create a tracked issue instead of leaving TODO comments",
                ),
            ],
        ),
        Policy(
            id="no-debug-statements",
            name="No Debug Statements",
            description="Detect debug statements that shouldn't be in production",
            severity="warning",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"\bbreakpoint\s*\(\s*\)",
                    message="Python breakpoint() detected",
                    remediation="Remove debug breakpoints before committing",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"\bpdb\.set_trace\s*\(\s*\)",
                    message="Python debugger statement detected",
                    remediation="Remove pdb.set_trace() before committing",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"\bipdb\.set_trace\s*\(\s*\)",
                    message="Python debugger statement detected",
                    remediation="Remove ipdb.set_trace() before committing",
                    cwe_id="CWE-489",
                ),
            ],
        ),
        Policy(
            id="no-unsafe-regex",
            name="No Unsafe Regular Expressions",
            description="Detect potentially unsafe regex patterns (ReDoS)",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\(\.\*\)\+|\(\.\+\)\*|\(\.\+\)\+",
                    message="Potentially unsafe nested quantifier in regex (ReDoS risk)",
                    remediation="Simplify the regex to avoid catastrophic backtracking",
                    cwe_id="CWE-1333",
                ),
            ],
        ),
        Policy(
            id="no-sql-string-concat",
            name="No SQL String Concatenation",
            description="Detect potential SQL injection vulnerabilities",
            severity="error",
            languages=["python", "javascript", "typescript", "java"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(execute|query|cursor|prepare|raw)\s*\(\s*['\"]?\s*(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER)\s+.*\+",
                    message="Potential SQL injection via string concatenation in database call",
                    flags="i",
                    remediation="Use parameterized queries or an ORM",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    # Require SQL keyword to appear BEFORE the {variable} interpolation.
                    # This matches f'SELECT * FROM t WHERE id={uid}' (real SQL injection)
                    # but NOT f"Marked {x['id']} as deleted" (logging, keyword after variable).
                    pattern=r"(?i)(execute|query|cursor)\s*\(\s*f['\"].*\b(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER)\b.*\{",
                    message="Potential SQL injection via f-string in database call",
                    flags="i",
                    remediation="Use parameterized queries instead of string formatting",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"(?i)(execute|query|cursor)\s*\(\s*['\"].*(?:SELECT|INSERT|UPDATE|DELETE).*['\"]?\s*\%\s*\(",
                    message="Potential SQL injection via % formatting in database call",
                    flags="i",
                    remediation="Use parameterized queries instead of string formatting",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"(?i)(execute|query|cursor)\s*\(\s*['\"](?:SELECT|INSERT|UPDATE|DELETE)\b[^'\"]*['\"]?\s*\+\s*\w",
                    message="Potential SQL injection via single concatenation in database call",
                    flags="i",
                    remediation="Use parameterized queries instead of string concatenation",
                    cwe_id="CWE-89",
                ),
            ],
        ),
        Policy(
            id="no-eval",
            name="No Eval Statements",
            description="Detect dangerous eval() usage",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"\beval\s*\(",
                    message="Dangerous eval() usage detected",
                    remediation=(
                        "Avoid eval() - use safe alternatives like "
                        "JSON.parse() or ast.literal_eval()"
                    ),
                    cwe_id="CWE-95",
                ),
            ],
        ),
        # Input Validation Analysis Policies (SEN-153)
        Policy(
            id="no-command-injection",
            name="No Command Injection",
            description="Detect potential command injection vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"subprocess\.(run|call|Popen|check_output|check_call)\s*\([^)]*\+",
                    message="Potential command injection: user input concatenated in subprocess call",
                    remediation="Use a list of arguments instead of shell=True with string concatenation",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"subprocess\.(run|call|Popen|check_output|check_call)\s*\([^)]*f['\"]",
                    message="Potential command injection: f-string used in subprocess call",
                    remediation="Use a list of arguments and avoid string formatting for commands",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"subprocess\.(run|call|Popen|check_output|check_call)\s*\([^)]*\.format\s*\(",
                    message="Potential command injection: .format() used in subprocess call",
                    remediation="Use a list of arguments and avoid string formatting for commands",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"subprocess\.(run|call|Popen|check_output|check_call)\s*\([^)]*%\s*[(\[]",
                    message="Potential command injection: % formatting used in subprocess call",
                    remediation="Use a list of arguments and avoid string formatting for commands",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"os\.system\s*\([^)]*[\+%]",
                    message="Potential command injection: string operations in os.system()",
                    remediation="Use subprocess with a list of arguments instead of os.system()",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"os\.system\s*\([^)]*f['\"]",
                    message="Potential command injection: f-string in os.system()",
                    remediation="Use subprocess with a list of arguments instead of os.system()",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"os\.popen\s*\([^)]*[\+%]",
                    message="Potential command injection: string operations in os.popen()",
                    remediation="Use subprocess with a list of arguments instead of os.popen()",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="no-command-injection-js",
            name="No Command Injection (JavaScript)",
            description="Detect potential command injection in JavaScript/Node.js",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"child_process\.(exec|execSync|spawn|spawnSync)\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in child_process",
                    remediation="Use spawn with an array of arguments and avoid shell interpolation",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"child_process\.(exec|execSync|spawn|spawnSync)\s*\([^)]*`[^`]*\$\{",
                    message="Potential command injection: template literal with interpolation in child_process",
                    remediation="Use spawn with an array of arguments and avoid shell interpolation",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"require\s*\(\s*['\"]child_process['\"]\s*\)\s*\.\s*(exec|execSync)\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in exec",
                    remediation="Use spawn with an array of arguments instead",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="no-path-traversal",
            name="No Path Traversal",
            description="Detect potential path traversal vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"open\s*\([^)]*request\.(args|form|values|json|data|get)",
                    message="Potential path traversal: user input in file open()",
                    remediation="Validate and sanitize file paths; use os.path.basename() or pathlib",
                    cwe_id="CWE-22",
                ),
                PolicyRule(
                    pattern=r"open\s*\([^)]*(?:params|input|arg|user|query|request)\w*\s*[\+\)]",
                    message="Potential path traversal: user-controlled variable in file open()",
                    flags="i",
                    remediation="Use pathlib.Path for safe path construction and validate input",
                    cwe_id="CWE-22",
                ),
                PolicyRule(
                    pattern=r"shutil\.(copy|move|rmtree)\s*\([^)]*request\.",
                    message="Potential path traversal: user input in shutil operation",
                    remediation="Validate and sanitize file paths before file operations",
                    cwe_id="CWE-22",
                ),
                PolicyRule(
                    pattern=r"os\.(remove|unlink|rmdir|rename)\s*\([^)]*(?:request\.|params|input|arg|user|query)",
                    message="Potential path traversal: user-controlled input in file operation",
                    flags="i",
                    remediation="Validate paths and use pathlib for safe path construction",
                    cwe_id="CWE-22",
                ),
            ],
        ),
        Policy(
            id="no-path-traversal-js",
            name="No Path Traversal (JavaScript)",
            description="Detect potential path traversal in JavaScript/Node.js",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"fs\.(readFile|writeFile|readFileSync|writeFileSync|unlink|rmdir)\s*\([^)]*req\.(params|query|body)",
                    message="Potential path traversal: request input in fs operation",
                    remediation="Validate paths and use path.resolve() with basename validation",
                    cwe_id="CWE-22",
                ),
                PolicyRule(
                    pattern=r"path\.join\s*\([^)]*req\.(params|query|body)",
                    message="Potential path traversal: unvalidated request input in path.join()",
                    remediation="Validate that the resolved path is within expected directory",
                    cwe_id="CWE-22",
                ),
            ],
        ),
        Policy(
            id="no-unsafe-redirect",
            name="No Unsafe Redirects",
            description="Detect potential open redirect vulnerabilities",
            severity="warning",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"redirect\s*\([^)]*request\.(args|form|values|json|data)",
                    message="Potential open redirect: user input in redirect URL",
                    remediation="Validate redirect URLs against a whitelist of allowed domains",
                    cwe_id="CWE-601",
                ),
                PolicyRule(
                    pattern=r"redirect\s*\([^)]*\+",
                    message="Potential open redirect: string concatenation in redirect URL",
                    remediation="Use url_for() or validate redirect URLs against allowed domains",
                    cwe_id="CWE-601",
                ),
                PolicyRule(
                    pattern=r"Response\s*\([^)]*headers\s*=.*Location.*request\.",
                    message="Potential open redirect: user input in Location header",
                    flags="i",
                    remediation="Validate redirect URLs against a whitelist of allowed domains",
                    cwe_id="CWE-601",
                ),
            ],
        ),
        Policy(
            id="no-unsafe-redirect-js",
            name="No Unsafe Redirects (JavaScript)",
            description="Detect potential open redirect in JavaScript",
            severity="warning",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"res\.redirect\s*\([^)]*req\.(params|query|body)",
                    message="Potential open redirect: request input in redirect",
                    remediation="Validate redirect URLs against a whitelist of allowed domains",
                    cwe_id="CWE-601",
                ),
                PolicyRule(
                    pattern=r"(window\.)?location\s*=\s*[^;]*(params|query|searchParams)",
                    message="Potential open redirect: URL parameters in location assignment",
                    remediation="Validate URLs before redirecting",
                    cwe_id="CWE-601",
                ),
                PolicyRule(
                    pattern=r"(window\.)?location\.href\s*=\s*[^;]*\+",
                    message="Potential open redirect: string concatenation in location.href",
                    remediation="Validate and sanitize URLs before redirecting",
                    cwe_id="CWE-601",
                ),
            ],
        ),
        Policy(
            id="no-template-injection",
            name="No Template Injection",
            description="Detect potential server-side template injection (SSTI)",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"Template\s*\([^)]*request\.(args|form|values|json|data)",
                    message="Potential template injection: user input in Template()",
                    remediation="Never pass user input directly to template constructors",
                    cwe_id="CWE-1336",
                ),
                PolicyRule(
                    pattern=r"render_template_string\s*\([^)]*request\.",
                    message="Potential template injection: user input in render_template_string()",
                    remediation="Use render_template() with template files instead",
                    cwe_id="CWE-1336",
                ),
                PolicyRule(
                    pattern=r"Environment\s*\(\s*\)\s*\.from_string\s*\([^)]*request\.",
                    message="Potential template injection: user input in Jinja2 from_string()",
                    remediation="Use pre-defined templates instead of user-controlled strings",
                    cwe_id="CWE-1336",
                ),
                PolicyRule(
                    pattern=r"\.render\s*\([^)]*\%[^)]*request\.",
                    message="Potential template injection: user input with % formatting in render()",
                    remediation="Pass user input as template variables, not in template source",
                    cwe_id="CWE-1336",
                ),
            ],
        ),
        Policy(
            id="no-xss-sinks",
            name="No XSS Vulnerable Sinks",
            description="Detect potential cross-site scripting vulnerabilities",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"\.(innerHTML|outerHTML)\s*=\s*[^;]*[\+`]",
                    message="Potential XSS: dynamic content in innerHTML/outerHTML",
                    remediation="Use textContent for text or sanitize HTML with DOMPurify",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"document\.write\s*\([^)]*[\+`]",
                    message="Potential XSS: dynamic content in document.write()",
                    remediation="Avoid document.write(); use DOM methods with proper escaping",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"\.insertAdjacentHTML\s*\([^)]*[\+`]",
                    message="Potential XSS: dynamic content in insertAdjacentHTML()",
                    remediation="Sanitize HTML content with DOMPurify before insertion",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html:\s*(?!\s*JSON\.stringify)",
                    message="Potential XSS: dangerouslySetInnerHTML in React component",
                    remediation="Sanitize content with DOMPurify before using dangerouslySetInnerHTML",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"\[innerHTML\]\s*=",
                    message="Potential XSS: Angular innerHTML binding",
                    remediation="Use Angular's DomSanitizer to sanitize HTML content",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"v-html\s*=",
                    message="Potential XSS: Vue v-html directive with dynamic content",
                    remediation="Sanitize content before using v-html",
                    cwe_id="CWE-79",
                ),
            ],
        ),
        Policy(
            id="no-ldap-injection",
            name="No LDAP Injection",
            description="Detect potential LDAP injection vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"ldap\.(search|search_s)\s*\([^)]*\%",
                    message="Potential LDAP injection: % formatting in LDAP search",
                    remediation="Use ldap.filter.escape_filter_chars() for user input",
                    cwe_id="CWE-90",
                ),
                PolicyRule(
                    pattern=r"ldap\.(search|search_s)\s*\([^)]*f['\"]",
                    message="Potential LDAP injection: f-string in LDAP search",
                    remediation="Use ldap.filter.escape_filter_chars() for user input",
                    cwe_id="CWE-90",
                ),
                PolicyRule(
                    pattern=r"ldap\.(search|search_s)\s*\([^)]*\.format\s*\(",
                    message="Potential LDAP injection: .format() in LDAP search",
                    remediation="Use ldap.filter.escape_filter_chars() for user input",
                    cwe_id="CWE-90",
                ),
            ],
        ),
        Policy(
            id="no-xpath-injection",
            name="No XPath Injection",
            description="Detect potential XPath injection vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"\.xpath\s*\([^)]*\%",
                    message="Potential XPath injection: % formatting in XPath query",
                    remediation="Use parameterized XPath queries or escape user input",
                    cwe_id="CWE-643",
                ),
                PolicyRule(
                    pattern=r"\.xpath\s*\([^)]*f['\"]",
                    message="Potential XPath injection: f-string in XPath query",
                    remediation="Use parameterized XPath queries or escape user input",
                    cwe_id="CWE-643",
                ),
                PolicyRule(
                    pattern=r"\.xpath\s*\([^)]*\.format\s*\(",
                    message="Potential XPath injection: .format() in XPath query",
                    remediation="Use parameterized XPath queries or escape user input",
                    cwe_id="CWE-643",
                ),
            ],
        ),
        Policy(
            id="no-deserialization",
            name="No Unsafe Deserialization",
            description="Detect potential insecure deserialization vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"pickle\.(loads?|Unpickler)\s*\([^)]*request\.",
                    message="Potential insecure deserialization: user input in pickle",
                    remediation="Never unpickle data from untrusted sources; use JSON instead",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"pickle\.loads?\s*\(",
                    message="Insecure deserialization: pickle.loads() can execute arbitrary code",
                    remediation="Never unpickle untrusted data; use JSON or other safe formats",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"yaml\.load\s*\([^)]*request\.",
                    message="Potential insecure deserialization: user input in yaml.load()",
                    remediation="Use yaml.safe_load() instead of yaml.load()",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"yaml\.load\s*\([^)]*Loader\s*=\s*yaml\.Loader",
                    message="Insecure YAML loading: using unsafe Loader",
                    remediation="Use yaml.safe_load() or Loader=yaml.SafeLoader",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"yaml\.load\s*\([^,)]+\)\s*$",
                    message="Insecure YAML loading: yaml.load() without SafeLoader",
                    remediation="Use yaml.safe_load() or pass Loader=yaml.SafeLoader",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"marshal\.loads?\s*\([^)]*request\.",
                    message="Potential insecure deserialization: user input in marshal",
                    remediation="Never unmarshal data from untrusted sources",
                    cwe_id="CWE-502",
                ),
            ],
        ),
        Policy(
            id="no-deserialization-php",
            name="No Unsafe Deserialization (PHP)",
            description="Detect potential insecure deserialization in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"unserialize\s*\(\s*\$_(GET|POST|REQUEST|COOKIE)",
                    message="Insecure deserialization: unserialize() with user input",
                    remediation="Use json_decode() instead of unserialize() for user data",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"unserialize\s*\([^)]*\)",
                    message="Potential insecure deserialization: unserialize() can execute arbitrary code",
                    remediation="Use json_decode() or pass allowed_classes option",
                    cwe_id="CWE-502",
                ),
            ],
        ),
        Policy(
            id="no-xxe",
            name="No XML External Entity Injection",
            description="Detect potential XXE vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"etree\.XMLParser\s*\([^)]*resolve_entities\s*=\s*True",
                    message="XXE: lxml XMLParser with resolve_entities=True",
                    remediation="Set resolve_entities=False to prevent XXE attacks",
                    cwe_id="CWE-611",
                ),
                PolicyRule(
                    pattern=r"etree\.XMLParser\s*\([^)]*load_dtd\s*=\s*True",
                    message="XXE: lxml XMLParser with load_dtd=True enables DTD processing",
                    remediation="Set load_dtd=False or use defusedxml",
                    cwe_id="CWE-611",
                ),
                PolicyRule(
                    pattern=r"etree\.(parse|fromstring|XML)\s*\([^)]*request\.",
                    message="Potential XXE: user input in XML parsing",
                    remediation="Use defusedxml or configure parser with resolve_entities=False",
                    cwe_id="CWE-611",
                ),
            ],
        ),
        Policy(
            id="no-csrf-exempt",
            name="No CSRF Exemption",
            description="Detect CSRF protection being disabled",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"@csrf_exempt",
                    message="CSRF protection disabled via @csrf_exempt decorator",
                    remediation="Only exempt API endpoints with token-based authentication",
                    cwe_id="CWE-352",
                ),
                PolicyRule(
                    pattern=r"WTF_CSRF_ENABLED\s*=\s*False",
                    message="Flask-WTF CSRF protection disabled",
                    remediation="Enable WTF_CSRF_ENABLED for form protection",
                    cwe_id="CWE-352",
                ),
            ],
        ),
        Policy(
            id="no-ssrf",
            name="No Server-Side Request Forgery",
            description="Detect potential SSRF vulnerabilities",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"urllib\.request\.urlopen\s*\([^)]*request\.(args|form|values|json|data|GET|POST)",
                    message="Potential SSRF: user input in urllib.request.urlopen()",
                    remediation="Validate URLs against an allowlist before making server-side requests",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    pattern=r"requests\.(get|post|put|delete|head)\s*\([^)]*request\.(args|form|values|json|data|GET|POST)",
                    message="Potential SSRF: user input in requests library call",
                    remediation="Validate URLs against an allowlist before making server-side requests",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    # BUG-224: Tightened — require that the concatenation involves
                    # a variable (not just string literal continuation).
                    pattern=r"urllib\.request\.urlopen\s*\([^)]*\+\s*\w",
                    message="Potential SSRF: string concatenation in urlopen URL",
                    remediation="Validate URLs against an allowlist before making requests",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    # BUG-224: Tightened to require user-input indicators in the
                    # f-string interpolation. The old pattern fired on ANY f-string
                    # URL (e.g., requests.get(f"https://api.internal/{endpoint}"))
                    # causing false positives on clean code.
                    # Now requires: request., user_input, params, query, body, argv,
                    # sys.stdin, or input() in the interpolated expression.
                    pattern=r"requests\.(get|post|put|delete|head)\s*\(\s*f['\"][^'\"]*\{[^}]*(request\.|user_?input|params|query|body|argv|sys\.stdin|input\s*\()",
                    message="Potential SSRF: f-string with user input in requests URL",
                    remediation="Validate URLs against an allowlist before making requests",
                    cwe_id="CWE-918",
                ),
            ],
        ),
        Policy(
            id="no-ssrf-php",
            name="No Server-Side Request Forgery (PHP)",
            description="Detect potential SSRF vulnerabilities in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"file_get_contents\s*\(\s*\$_(GET|POST|REQUEST)",
                    message="Potential SSRF: user input in file_get_contents()",
                    remediation="Validate URLs against an allowlist before fetching",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    pattern=r"curl_setopt\s*\([^,]*,\s*CURLOPT_URL\s*,\s*\$_(GET|POST|REQUEST)",
                    message="Potential SSRF: user input in curl URL",
                    remediation="Validate URLs against an allowlist before making requests",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    pattern=r"curl_init\s*\(\s*\$_(GET|POST|REQUEST)",
                    message="Potential SSRF: user input in curl_init()",
                    remediation="Validate URLs against an allowlist before making requests",
                    cwe_id="CWE-918",
                ),
            ],
        ),
        Policy(
            id="no-ssrf-js",
            name="No Server-Side Request Forgery (JavaScript)",
            description="Detect potential SSRF vulnerabilities in JavaScript",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(fetch|axios\.get|axios\.post|http\.get|https\.get|needle\.get|got)\s*\([^)]*req\.(params|query|body)",
                    message="Potential SSRF: user input in HTTP request URL",
                    remediation="Validate URLs against an allowlist before making server-side requests",
                    cwe_id="CWE-918",
                ),
                PolicyRule(
                    pattern=r"(fetch|axios\.get|axios\.post|http\.get|https\.get)\s*\([^)]*`[^`]*\$\{.*req\.",
                    message="Potential SSRF: template literal with user input in HTTP request",
                    remediation="Validate URLs against an allowlist before making requests",
                    cwe_id="CWE-918",
                ),
            ],
        ),
        Policy(
            id="no-unsafe-regex-input",
            name="No Unsafe Regex from Input",
            description="Detect potential ReDoS from user-controlled regex",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"re\.(compile|match|search|findall|sub)\s*\([^)]*request\.",
                    message="Potential ReDoS: user input used as regex pattern",
                    remediation="Never use user input directly as regex; validate or escape it",
                    cwe_id="CWE-1333",
                ),
                PolicyRule(
                    pattern=r"new\s+RegExp\s*\([^)]*req\.(params|query|body)",
                    message="Potential ReDoS: user input used as regex pattern",
                    remediation="Never use user input directly as regex; validate or escape it",
                    cwe_id="CWE-1333",
                ),
            ],
        ),
        # Sensitive Data Logging Detection Policies (SEN-154)
        Policy(
            id="no-ssn-logging",
            name="No SSN in Logs",
            description="Detect Social Security Numbers being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*\b(?<![/\.\d])\d{3}-\d{2}-\d{4}(?![/\.\d])\b",
                    message="Potential SSN detected in log statement",
                    flags="i",
                    remediation="Never log Social Security Numbers; mask or remove PII before logging",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(ssn|social_security|socialSecurity)",
                    message="SSN variable being logged",
                    flags="i",
                    remediation="Never log Social Security Numbers; mask or remove PII before logging",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-credit-card-logging",
            name="No Credit Card in Logs",
            description="Detect credit card numbers being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b\s*[^;]*\b(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b",
                    message="Potential credit card number detected in log statement",
                    remediation="Never log credit card numbers; mask all but last 4 digits",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(credit_?card|card_?number|cardNumber|ccNumber|cc_num)",
                    message="Credit card variable being logged",
                    flags="i",
                    remediation="Never log credit card numbers; mask all but last 4 digits",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(cvv|cvc|security_?code|securityCode)",
                    message="CVV/security code variable being logged",
                    flags="i",
                    remediation="Never log CVV/security codes",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-password-logging",
            name="No Password in Logs",
            description="Detect passwords being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    # Detect when a password/secret variable is actually passed to a logger.
                    #
                    # Pattern 1 (f-string interpolation): Match when a variable whose name
                    # contains password/secret/etc. is interpolated in an f-string, with the
                    # keyword NOT followed by a reference suffix (_arn, _name, _id, etc.).
                    # Matches {secret}, {webhook_secret}, {api_secret}
                    # Does NOT match {secret_arn}, {secret_name} (reference/pointer, not value).
                    #
                    # Pattern 2 (direct variable): Match when a variable (possibly with member
                    # access like self.password) whose name contains the keyword is passed
                    # directly as a logger argument.
                    # Matches logger.info(password), print(user_password), logger.debug(self.secret)
                    # Does NOT match logger.error("...secret unavailable...") (string literal).
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*\{[^}]*(password|passwd|pwd|secret|credentials?)(?!_arn|_name|_id|_path|_ref|_url|_uri|_location|_store)[^}]*\}"
                    r"|\b(log|print|console\.|logger\.|logging\.)\b[^(]*\(\s*(?:\w+\.)?\w*(password|passwd|pwd|secret|credentials?)\w*\b",
                    message="Password or secret variable being logged — ensure no sensitive value is exposed",
                    flags="i",
                    remediation="Never log passwords or secret values; use masked placeholders or omit sensitive fields",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(api_?key|apiKey|auth_?token|authToken|bearer|access_?token)",
                    message="API key or auth token being logged",
                    flags="i",
                    remediation="Never log API keys or tokens; use masked placeholders",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-email-logging-bulk",
            name="No Bulk Email Logging",
            description="Detect email addresses being logged in bulk operations",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b",
                    message="Email address detected in log statement",
                    remediation="Consider masking email addresses in logs (e.g., j***@example.com)",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"for\s+.*\s+in\s+.*:\s*\n?\s*\b(log|print|console\.|logger\.|logging\.)\b[^;]*(email|user)",
                    message="Potential bulk email/user logging in loop",
                    flags="i",
                    remediation="Avoid logging user emails in loops; use aggregated counts instead",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-phone-logging",
            name="No Phone Number in Logs",
            description="Detect phone numbers being logged",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b",
                    message="Potential phone number detected in log statement",
                    remediation="Mask phone numbers in logs (e.g., ***-***-1234)",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(phone|mobile|cell|telephone)",
                    message="Phone number variable being logged",
                    flags="i",
                    remediation="Mask phone numbers before logging",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-health-info-logging",
            name="No Health Information in Logs",
            description="Detect Protected Health Information (PHI) being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(patient_?id|patientId|medical_?record|medicalRecord|mrn|health_?record)",
                    message="Patient/medical record ID being logged",
                    flags="i",
                    remediation="Never log PHI; use anonymized identifiers for debugging",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(diagnosis|treatment|prescription|medication|condition)",
                    message="Medical information being logged",
                    flags="i",
                    remediation="Never log PHI; remove health information before logging",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(insurance_?id|insuranceId|policy_?number|policyNumber|member_?id|memberId)",
                    message="Insurance information being logged",
                    flags="i",
                    remediation="Never log insurance details; mask or remove before logging",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-financial-logging",
            name="No Financial Data in Logs",
            description="Detect financial information being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(bank_?account|bankAccount|account_?number|accountNumber|routing_?number|routingNumber)",
                    message="Bank account information being logged",
                    flags="i",
                    remediation="Never log bank account details; mask all but last 4 digits",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(iban|swift|bic)[^a-zA-Z]",
                    message="International bank identifier being logged",
                    flags="i",
                    remediation="Never log IBAN/SWIFT codes; use masked placeholders",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(tax_?id|taxId|ein|tin)[^a-zA-Z]",
                    message="Tax ID being logged",
                    flags="i",
                    remediation="Never log tax identification numbers",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-ip-address-logging",
            name="No IP Address Logging",
            description="Detect IP addresses being logged without consideration",
            severity="info",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*\b(?:\d{1,3}\.){3}\d{1,3}\b",
                    message="IP address detected in log statement",
                    remediation="Consider anonymizing IP addresses for privacy compliance (GDPR)",
                    cwe_id="CWE-532",
                ),
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(ip_?address|ipAddress|client_?ip|clientIp|remote_?addr|remoteAddr|x_forwarded_for)",
                    message="IP address variable being logged",
                    flags="i",
                    remediation="Consider anonymizing IP addresses for privacy compliance",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-dob-logging",
            name="No Date of Birth in Logs",
            description="Detect dates of birth being logged",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(dob|date_?of_?birth|dateOfBirth|birth_?date|birthDate|birthday)",
                    message="Date of birth being logged",
                    flags="i",
                    remediation="Never log dates of birth; mask or remove PII before logging",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-biometric-logging",
            name="No Biometric Data in Logs",
            description="Detect biometric data references being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(fingerprint|biometric|face_?id|faceId|retina|iris_?scan|voice_?print)",
                    message="Biometric data reference being logged",
                    flags="i",
                    remediation="Never log biometric data or identifiers",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="no-government-id-logging",
            name="No Government ID in Logs",
            description="Detect government IDs being logged",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(log|print|console\.|logger\.|logging\.)\b[^;]*(passport|driver_?license|driverLicense|national_?id|nationalId|visa_?number|visa_?id)",
                    message="Government ID being logged",
                    flags="i",
                    remediation="Never log government-issued IDs",
                    cwe_id="CWE-532",
                ),
            ],
        ),
        # Error Handling Analysis Policies (SEN-155)
        Policy(
            id="no-stack-trace-exposure",
            name="No Stack Trace Exposure",
            description="Detect stack traces being exposed to users",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"traceback\.(print_exc|format_exc|print_exception)\s*\(",
                    message="Stack trace may be exposed to users",
                    remediation="Log stack traces server-side only; return generic error messages to users",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(return|response|jsonify|Response)\s*[^;]*traceback\.",
                    message="Stack trace being returned in response",
                    remediation="Never return stack traces to users; log them server-side instead",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(return|response|jsonify|Response)\s*[^;]*str\s*\(\s*e\s*\)",
                    message="Exception message being returned directly",
                    remediation="Return generic error messages; log detailed exceptions server-side",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"except\s*.*:\s*\n?\s*(print|return)\s*\(\s*e\s*\)",
                    message="Exception being printed or returned directly",
                    remediation="Log exceptions properly; don't expose to users",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-stack-trace-exposure-js",
            name="No Stack Trace Exposure (JavaScript)",
            description="Detect stack traces being exposed in JavaScript",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(res\.send|res\.json|response\.send|response\.json)\s*\([^)]*\.stack",
                    message="Stack trace being sent in response",
                    remediation="Never send stack traces to clients; log them server-side",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(res\.send|res\.json|response\.send|response\.json)\s*\([^)]*error\.message",
                    message="Error message being sent directly to client",
                    remediation="Sanitize error messages before sending to clients",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"catch\s*\([^)]*\)\s*\{[^}]*res\.(send|json)\s*\([^)]*err",
                    message="Exception details being returned in catch block",
                    remediation="Return generic error messages; log detailed errors server-side",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-debug-mode-production",
            name="No Debug Mode in Production",
            description="Detect debug mode enabled in production code",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"DEBUG\s*=\s*True",
                    message="DEBUG mode enabled",
                    remediation="Use environment variables for DEBUG; never hardcode True in production",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"app\.run\s*\([^)]*debug\s*=\s*True",
                    message="Flask app running in debug mode",
                    remediation="Disable debug mode in production; use environment variable",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"FLASK_DEBUG\s*=\s*['\"]?1['\"]?",
                    message="Flask debug mode enabled",
                    remediation="Set FLASK_DEBUG=0 in production",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"settings\.DEBUG\s*=\s*True",
                    message="Django DEBUG setting enabled",
                    remediation="Set DEBUG=False in production settings",
                    cwe_id="CWE-489",
                ),
            ],
        ),
        Policy(
            id="no-debug-mode-production-js",
            name="No Debug Mode in Production (JavaScript)",
            description="Detect debug/development mode in JavaScript",
            severity="warning",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"NODE_ENV\s*[!=]==?\s*['\"]development['\"]",
                    message="Development mode check - ensure production uses NODE_ENV=production",
                    remediation="Verify NODE_ENV is set to 'production' in production deployments",
                    cwe_id="CWE-489",
                ),
                PolicyRule(
                    pattern=r"process\.env\.DEBUG\s*=\s*['\"]true['\"]",
                    message="DEBUG environment variable set to true",
                    flags="i",
                    remediation="Remove hardcoded DEBUG values; use environment configuration",
                    cwe_id="CWE-489",
                ),
            ],
        ),
        Policy(
            id="no-verbose-errors",
            name="No Verbose Error Responses",
            description="Detect verbose error information in responses",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"(return|jsonify|Response)\s*\([^)]*['\"]error['\"]\s*:\s*str\s*\(\s*(e|exception|err)",
                    message="Exception string being included in error response",
                    remediation="Return generic error codes; log detailed errors server-side",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(return|jsonify)\s*\(\s*\{[^}]*(exception|traceback|stack_trace|stacktrace)",
                    message="Exception details in JSON response",
                    flags="i",
                    remediation="Remove exception details from API responses",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-verbose-errors-js",
            name="No Verbose Error Responses (JavaScript)",
            description="Detect verbose error information in JavaScript responses",
            severity="error",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(res\.json|res\.send)\s*\(\s*\{[^}]*(stack|stackTrace|trace)[^}]*\}",
                    message="Stack trace in JSON response",
                    flags="i",
                    remediation="Remove stack traces from API responses",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(res\.status\s*\(\s*\d+\s*\)\s*\.)?(json|send)\s*\(\s*\{[^}]*error:\s*err",
                    message="Error object being sent in response",
                    remediation="Sanitize errors before sending; use generic messages",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-internal-path-exposure",
            name="No Internal Path Exposure",
            description="Detect internal file paths being exposed",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(return|response|send|json)\s*[^;]*(__file__|__path__|__name__|os\.path|Path\s*\()",
                    message="Internal path may be exposed in response",
                    remediation="Never expose file system paths to users",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(return|response|send|json)[^;]*(/home/|/var/|/etc/|/usr/|C:\\\\|D:\\\\)",
                    message="Absolute file path in response",
                    remediation="Remove absolute paths from user-facing responses",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-database-error-exposure",
            name="No Database Error Exposure",
            description="Detect database errors being exposed to users",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(return|response|send|json)\s*[^;]*(SQLException|DatabaseError|OperationalError|IntegrityError|ProgrammingError)",
                    message="Database error being exposed in response",
                    remediation="Catch database errors and return generic messages",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"(return|response|send|json)\s*[^;]*(mysql|postgres|sqlite|mongodb|redis)\.(error|Error)",
                    message="Database-specific error in response",
                    flags="i",
                    remediation="Handle database errors gracefully; don't expose to users",
                    cwe_id="CWE-209",
                ),
                PolicyRule(
                    pattern=r"except\s*(SQLException|DatabaseError|OperationalError)[^:]*:\s*\n?\s*(return|response)",
                    message="Database exception being returned directly",
                    remediation="Log database errors; return generic error to users",
                    cwe_id="CWE-209",
                ),
            ],
        ),
        Policy(
            id="no-connection-string-exposure",
            name="No Connection String Exposure",
            description="Detect database connection strings in errors",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(return|response|send|json|log|print|console)[^;]*(mongodb\+srv://|mysql://|postgres://|redis://|amqp://)",
                    message="Database connection string may be exposed",
                    remediation="Never include connection strings in responses or logs",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    pattern=r"(return|response|send|json)[^;]*(connection_?string|connectionString|db_?url|database_?url)",
                    message="Connection string variable in response",
                    flags="i",
                    remediation="Never expose connection strings to users",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="no-server-info-exposure",
            name="No Server Information Exposure",
            description="Detect server/environment info being exposed",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"\b(return|response|send|json)\b[^;]*(sys\.version|platform\.|os\.uname|process\.version|process\.env)",
                    message="System information may be exposed",
                    remediation="Don't expose server/environment details to users",
                    cwe_id="CWE-200",
                ),
                PolicyRule(
                    pattern=r"(X-Powered-By|Server):\s*[^,\n]+",
                    message="Server header exposing technology stack",
                    remediation="Remove or customize X-Powered-By and Server headers",
                    cwe_id="CWE-200",
                ),
            ],
        ),
        Policy(
            id="no-bare-except",
            name="No Bare Except Clauses",
            description="Detect bare except clauses that hide errors",
            severity="warning",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"except\s*:\s*$",
                    message="Bare except clause - catches all errors indiscriminately",
                    flags="m",
                    remediation="Catch specific exceptions and handle or log them properly",
                    cwe_id="CWE-754",
                ),
                PolicyRule(
                    pattern=r"except\s*:\s*pass",
                    message="Bare except with pass - errors are silently swallowed",
                    remediation="Catch specific exceptions and handle or log them properly",
                    cwe_id="CWE-754",
                ),
                PolicyRule(
                    pattern=r"except\s+Exception\s*:\s*pass",
                    message="Catching all exceptions and ignoring - errors hidden",
                    remediation="Log exceptions even if you continue execution",
                    cwe_id="CWE-754",
                ),
            ],
        ),
        Policy(
            id="no-empty-catch",
            name="No Empty Catch Blocks",
            description="Detect empty catch blocks in JavaScript",
            severity="warning",
            languages=["javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"catch\s*\([^)]*\)\s*\{\s*\}",
                    message="Empty catch block - errors are silently swallowed",
                    remediation="Log errors in catch blocks; don't swallow them silently",
                    cwe_id="CWE-754",
                ),
                PolicyRule(
                    pattern=r"\.catch\s*\(\s*\(\s*\)\s*=>\s*\{\s*\}\s*\)",
                    message="Empty promise catch handler",
                    remediation="Handle promise rejections properly; log errors",
                    cwe_id="CWE-754",
                ),
            ],
        ),
        # Go Security Policies (SEN-431)
        Policy(
            id="go-unsafe-package",
            name="No Unsafe Package (Go)",
            description="Detect usage of Go's unsafe package",
            severity="warning",
            languages=["go"],
            rules=[
                PolicyRule(
                    pattern=r'"unsafe"',
                    message="Usage of unsafe package detected",
                    remediation="Avoid the unsafe package; use safe alternatives from the standard library",
                    cwe_id="CWE-787",
                ),
                PolicyRule(
                    pattern=r"unsafe\.(Pointer|Sizeof|Offsetof|Alignof)",
                    message="Direct unsafe operation detected",
                    remediation="Avoid unsafe pointer operations; use encoding/binary for low-level work",
                    cwe_id="CWE-787",
                ),
            ],
        ),
        Policy(
            id="go-error-suppression",
            name="No Error Suppression (Go)",
            description="Detect suppressed errors in Go",
            severity="warning",
            languages=["go"],
            rules=[
                PolicyRule(
                    pattern=r"\b\w+\s*,\s*_\s*[:=]=\s*\w+",
                    message="Error return value discarded with _",
                    remediation="Handle errors explicitly; don't discard them with _",
                    cwe_id="CWE-754",
                ),
            ],
        ),
        Policy(
            id="go-command-injection",
            name="No Command Injection (Go)",
            description="Detect potential command injection in Go",
            severity="error",
            languages=["go"],
            rules=[
                PolicyRule(
                    pattern=r"exec\.Command\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in exec.Command",
                    remediation="Validate and sanitize inputs before passing to exec.Command",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r'exec\.Command\s*\(\s*"(sh|bash|cmd)"\s*,\s*"-c"',
                    message="Shell execution via exec.Command — potential injection risk",
                    remediation="Avoid shell execution; use exec.Command with explicit arguments",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="go-insecure-tls",
            name="No Insecure TLS (Go)",
            description="Detect insecure TLS configuration in Go",
            severity="error",
            languages=["go"],
            rules=[
                PolicyRule(
                    pattern=r"InsecureSkipVerify\s*:\s*true",
                    message="TLS certificate verification disabled",
                    remediation="Enable TLS verification; use proper CA certificates",
                    cwe_id="CWE-295",
                ),
            ],
        ),
        Policy(
            id="go-goroutine-leak",
            name="No Goroutine Leaks (Go)",
            description="Detect unbounded goroutine creation in Go",
            severity="warning",
            languages=["go"],
            rules=[
                PolicyRule(
                    pattern=r"for\s+.*\{[^}]*go\s+\w+",
                    message="Goroutine launched inside loop — potential goroutine leak",
                    remediation="Use a worker pool or semaphore to bound concurrent goroutines",
                    cwe_id="CWE-404",
                ),
                PolicyRule(
                    pattern=r"go\s+func\s*\(",
                    message="Anonymous goroutine — ensure it terminates and errors are handled",
                    remediation="Use sync.WaitGroup or errgroup to manage goroutine lifecycle",
                    cwe_id="CWE-404",
                ),
            ],
        ),
        # Rust Security Policies (SEN-431)
        Policy(
            id="rust-unsafe-block",
            name="No Unnecessary Unsafe (Rust)",
            description="Flag unsafe blocks for review",
            severity="warning",
            languages=["rust"],
            rules=[
                PolicyRule(
                    pattern=r"\bunsafe\s*\{",
                    message="Unsafe block detected — requires careful review",
                    remediation="Minimize unsafe code; document safety invariants with // SAFETY: comments",
                    cwe_id="CWE-787",
                ),
            ],
        ),
        Policy(
            id="rust-unwrap-on-input",
            name="No Unwrap on User Input (Rust)",
            description="Detect .unwrap() that may panic on untrusted data",
            severity="warning",
            languages=["rust"],
            rules=[
                PolicyRule(
                    pattern=r"\.(unwrap|expect)\s*\(",
                    message="unwrap()/expect() may panic on invalid input",
                    remediation="Use pattern matching or ? operator for error handling instead of unwrap()",
                    cwe_id="CWE-248",
                ),
            ],
        ),
        Policy(
            id="rust-command-injection",
            name="No Command Injection (Rust)",
            description="Detect potential command injection in Rust",
            severity="error",
            languages=["rust"],
            rules=[
                PolicyRule(
                    pattern=r"Command::new\s*\([^)]*format!",
                    message="Potential command injection: format! in Command::new",
                    remediation="Validate and sanitize inputs; use .arg() for arguments",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"Command::new\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in Command::new",
                    remediation="Use .arg() to pass arguments separately",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="rust-transmute",
            name="No Transmute (Rust)",
            description="Detect std::mem::transmute usage",
            severity="warning",
            languages=["rust"],
            rules=[
                PolicyRule(
                    pattern=r"(std::mem::)?transmute\s*[:<(]",
                    message="transmute detected — extremely unsafe type coercion",
                    remediation="Use safe conversion methods (From/Into traits, as casts) instead of transmute",
                    cwe_id="CWE-843",
                ),
            ],
        ),
        Policy(
            id="rust-raw-pointer",
            name="No Raw Pointer Deref (Rust)",
            description="Detect raw pointer dereference in Rust",
            severity="warning",
            languages=["rust"],
            rules=[
                PolicyRule(
                    pattern=r"\*\s*(mut|const)\s+\w+",
                    message="Raw pointer type detected — requires unsafe to dereference",
                    remediation="Prefer references (&/&mut) over raw pointers; document safety invariants",
                    cwe_id="CWE-787",
                ),
                PolicyRule(
                    pattern=r"as\s+\*\s*(mut|const)",
                    message="Cast to raw pointer detected",
                    remediation="Minimize raw pointer usage; use safe abstractions where possible",
                    cwe_id="CWE-787",
                ),
            ],
        ),
        # Ruby Security Policies (SEN-431)
        Policy(
            id="ruby-dangerous-eval",
            name="No Dangerous Eval (Ruby)",
            description="Detect dangerous eval/send/system in Ruby",
            severity="error",
            languages=["ruby"],
            rules=[
                PolicyRule(
                    pattern=r"\b(eval|class_eval|instance_eval|module_eval)\s*[\(\s]",
                    message="Dangerous eval usage detected",
                    remediation="Avoid eval; use safe alternatives like case/when or method dispatch",
                    cwe_id="CWE-95",
                ),
                PolicyRule(
                    pattern=r"\b(send|public_send)\s*\([^)]*params",
                    message="Dynamic method dispatch with user input",
                    remediation="Validate method names against an allowlist before using send()",
                    cwe_id="CWE-95",
                ),
                PolicyRule(
                    pattern=r"\b(system|exec)\s*\(",
                    message="Shell command execution detected",
                    remediation="Validate and sanitize inputs; use Shellwords.escape for arguments",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"`[^`]+`|%x\[",
                    message="Shell command execution via backticks or %x",
                    remediation="Avoid backtick execution; use Open3 for safer subprocess handling",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="ruby-marshal-load",
            name="No Unsafe Deserialization (Ruby)",
            description="Detect unsafe Marshal.load in Ruby",
            severity="error",
            languages=["ruby"],
            rules=[
                PolicyRule(
                    pattern=r"Marshal\.(load|restore)\s*\(",
                    message="Unsafe deserialization with Marshal.load",
                    remediation="Never unmarshal untrusted data; use JSON.parse instead",
                    cwe_id="CWE-502",
                ),
            ],
        ),
        Policy(
            id="ruby-sql-interpolation",
            name="No SQL Interpolation (Ruby)",
            description="Detect SQL injection via string interpolation in Ruby",
            severity="error",
            languages=["ruby"],
            rules=[
                PolicyRule(
                    pattern=r'(where|find_by_sql|execute|select)\s*\(\s*"[^"]*#\{',
                    message="Potential SQL injection via string interpolation",
                    remediation="Use parameterized queries: where('col = ?', value)",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"(where|find_by_sql|execute|select)\s*\(\s*'[^']*'\s*\+",
                    message="Potential SQL injection via string concatenation",
                    remediation="Use parameterized queries: where('col = ?', value)",
                    cwe_id="CWE-89",
                ),
            ],
        ),
        Policy(
            id="ruby-open-with-pipe",
            name="No Open with Pipe (Ruby)",
            description="Detect Ruby open() with pipe command execution",
            severity="error",
            languages=["ruby"],
            rules=[
                PolicyRule(
                    pattern=r'\bopen\s*\(\s*["\']?\s*\|',
                    message="open() with pipe executes shell commands",
                    remediation="Use File.open for file operations; avoid pipe syntax",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\bopen\s*\([^)]*params",
                    message="open() with user input may allow command execution via pipe",
                    remediation="Use File.open and validate input; never pass user input to open()",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="ruby-mass-assignment",
            name="No Mass Assignment (Ruby)",
            description="Detect unsafe mass assignment in Ruby on Rails",
            severity="error",
            languages=["ruby"],
            rules=[
                PolicyRule(
                    pattern=r"params\.permit!",
                    message="params.permit! allows all parameters — mass assignment vulnerability",
                    remediation="Use params.require(:model).permit(:field1, :field2) to whitelist fields",
                    cwe_id="CWE-915",
                ),
                PolicyRule(
                    pattern=r"update_attributes?\s*\(\s*params\b",
                    message="Updating with raw params — mass assignment risk",
                    remediation="Use strong parameters: params.require(:model).permit(:allowed_fields)",
                    cwe_id="CWE-915",
                ),
            ],
        ),
        # Terraform / HCL Security Policies (SEN-433)
        Policy(
            id="terraform-hardcoded-secrets",
            name="No Hardcoded Secrets (Terraform)",
            description="Detect hardcoded secrets in Terraform",
            severity="error",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r'(?i)(password|secret|api_key|access_key|token)\s*=\s*"[^"]{4,}"',
                    message="Potential hardcoded secret in Terraform",
                    flags="i",
                    remediation="Use variables with sensitive=true or a secrets manager",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="terraform-public-access",
            name="No Public Access (Terraform)",
            description="Detect publicly accessible resources in Terraform",
            severity="error",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r"publicly_accessible\s*=\s*true",
                    message="Resource is publicly accessible",
                    remediation="Set publicly_accessible = false unless explicitly required",
                    cwe_id="CWE-284",
                ),
                PolicyRule(
                    # BUG-NEW TF egress fix: Only match 0.0.0.0/0 in ingress blocks.
                    # Egress 0.0.0.0/0 on 443 is standard (HTTPS to internet).
                    # Regex uses positive lookbehind for "ingress" within ~200 chars.
                    pattern=r'(?s)ingress\s*\{[^}]{0,200}cidr_blocks\s*=\s*\[\s*"0\.0\.0\.0/0"\s*\]',
                    message="Ingress security group rule open to all IPs (0.0.0.0/0)",
                    remediation="Restrict ingress CIDR blocks to specific IP ranges",
                    cwe_id="CWE-284",
                ),
                PolicyRule(
                    pattern=r'ipv6_cidr_blocks\s*=\s*\[\s*"::/0"\s*\]',
                    message="Security group open to all IPv6 addresses",
                    remediation="Restrict IPv6 CIDR blocks to specific ranges",
                    cwe_id="CWE-284",
                ),
            ],
        ),
        Policy(
            id="terraform-missing-encryption",
            name="No Missing Encryption (Terraform)",
            description="Detect unencrypted resources in Terraform",
            severity="error",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r"encrypted\s*=\s*false",
                    message="Resource encryption is disabled",
                    remediation="Set encrypted = true to enable encryption at rest",
                    cwe_id="CWE-311",
                ),
            ],
        ),
        Policy(
            id="terraform-overprivileged-iam",
            name="No Overprivileged IAM (Terraform)",
            description="Detect overly permissive IAM policies in Terraform",
            severity="error",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r'"Action"\s*:\s*"\*"',
                    message='IAM policy with "Action": "*" grants all permissions',
                    remediation="Follow least privilege: specify only required actions",
                    cwe_id="CWE-250",
                ),
                PolicyRule(
                    pattern=r'"Resource"\s*:\s*"\*"',
                    message='IAM policy with "Resource": "*" applies to all resources',
                    remediation="Restrict resources to specific ARNs",
                    cwe_id="CWE-250",
                ),
            ],
        ),
        Policy(
            id="terraform-missing-logging",
            name="No Missing Logging (Terraform)",
            description="Detect missing logging and monitoring in Terraform",
            severity="warning",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r"enable_logging\s*=\s*false",
                    message="Logging explicitly disabled",
                    remediation="Enable logging for audit and security monitoring",
                    cwe_id="CWE-778",
                ),
                PolicyRule(
                    pattern=r"flow_logs_enabled\s*=\s*false",
                    message="VPC flow logs disabled",
                    remediation="Enable VPC flow logs for network traffic monitoring",
                    cwe_id="CWE-778",
                ),
            ],
        ),
        Policy(
            id="terraform-http-without-https",
            name="No HTTP Without HTTPS (Terraform)",
            description="Detect HTTP listeners without HTTPS redirect",
            severity="error",
            languages=["terraform"],
            rules=[
                PolicyRule(
                    pattern=r'protocol\s*=\s*"HTTP"',
                    message="HTTP protocol used — consider requiring HTTPS",
                    remediation="Use HTTPS protocol or configure HTTP-to-HTTPS redirect",
                    cwe_id="CWE-319",
                ),
                PolicyRule(
                    pattern=r'ssl_policy\s*=\s*""',
                    message="Empty SSL policy — TLS not configured",
                    remediation="Configure a valid SSL policy for HTTPS listeners",
                    cwe_id="CWE-319",
                ),
            ],
        ),
        # Dockerfile Security Policies (SEN-434)
        Policy(
            id="dockerfile-latest-tag",
            name="No Latest Tag (Dockerfile)",
            description="Detect use of :latest tag in Dockerfiles",
            severity="warning",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"^FROM\s+\S+:latest\b",
                    message="Using :latest tag — builds are not reproducible",
                    flags="m",
                    remediation="Pin to a specific image version (e.g., node:20.11-alpine)",
                    cwe_id="CWE-1104",
                ),
                PolicyRule(
                    pattern=r"^FROM\s+[^\s:]+\s*$",
                    message="No tag specified — defaults to :latest",
                    flags="m",
                    remediation="Pin to a specific image version",
                    cwe_id="CWE-1104",
                ),
            ],
        ),
        Policy(
            id="dockerfile-no-user",
            name="No USER Directive (Dockerfile)",
            description="Detect Dockerfiles running as root",
            severity="warning",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"^(?!.*\bUSER\b).*^(CMD|ENTRYPOINT)\s+",
                    message="No USER directive — container runs as root",
                    flags="m",
                    remediation="Add a USER directive to run as non-root user",
                    cwe_id="CWE-250",
                ),
            ],
        ),
        Policy(
            id="dockerfile-add-vs-copy",
            name="Prefer COPY over ADD (Dockerfile)",
            description="Detect ADD that should be COPY",
            severity="info",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"^ADD\s+(?!https?://)\S+",
                    message="ADD used for local file — prefer COPY",
                    flags="m",
                    remediation="Use COPY instead of ADD for local files (ADD has implicit tar extraction)",
                    cwe_id="CWE-829",
                ),
            ],
        ),
        Policy(
            id="dockerfile-secrets-in-env",
            name="No Secrets in ENV/ARG (Dockerfile)",
            description="Detect secrets in Dockerfile ENV or ARG",
            severity="error",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)^(ENV|ARG)\s+(PASSWORD|SECRET|API_KEY|TOKEN|AWS_SECRET|PRIVATE_KEY)\s*=",
                    message="Secret value in ENV/ARG is baked into the image layer",
                    flags="im",
                    remediation="Use Docker secrets or runtime environment variables instead",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="dockerfile-apt-recommends",
            name="Minimize apt-get Install (Dockerfile)",
            description="Detect apt-get without --no-install-recommends",
            severity="info",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"apt-get\s+install\s+(?!.*--no-install-recommends)",
                    message="apt-get install without --no-install-recommends increases image size",
                    remediation="Add --no-install-recommends to reduce image size",
                    cwe_id="CWE-1104",
                ),
            ],
        ),
        Policy(
            id="dockerfile-privileged-port",
            name="No Privileged Ports (Dockerfile)",
            description="Detect EXPOSE on privileged ports",
            severity="warning",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"^EXPOSE\s+([0-9]{1,3})\b",
                    message="Exposing privileged port (<1024) — container may need root",
                    flags="m",
                    remediation="Use non-privileged ports (>=1024); map privileged ports at runtime",
                    cwe_id="CWE-250",
                ),
            ],
        ),
        Policy(
            id="dockerfile-missing-healthcheck",
            name="Missing HEALTHCHECK (Dockerfile)",
            description="Detect Dockerfiles without HEALTHCHECK",
            severity="info",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"^(?!.*HEALTHCHECK).*^(CMD|ENTRYPOINT)\s+",
                    message="No HEALTHCHECK directive — orchestrator cannot detect unhealthy containers",
                    flags="m",
                    remediation="Add HEALTHCHECK to enable container health monitoring",
                    cwe_id="CWE-693",
                ),
            ],
        ),
        Policy(
            id="dockerfile-curl-bash",
            name="No Curl Pipe Bash (Dockerfile)",
            description="Detect curl|bash anti-pattern in Dockerfiles",
            severity="error",
            languages=["dockerfile"],
            rules=[
                PolicyRule(
                    pattern=r"curl\s+[^|]*\|\s*(bash|sh)",
                    message="curl piped to shell — executes unverified remote code",
                    remediation="Download scripts first, verify checksums, then execute",
                    cwe_id="CWE-829",
                ),
                PolicyRule(
                    pattern=r"wget\s+[^|]*\|\s*(bash|sh)",
                    message="wget piped to shell — executes unverified remote code",
                    remediation="Download scripts first, verify checksums, then execute",
                    cwe_id="CWE-829",
                ),
            ],
        ),
        # C# Security Policies (SEN-439)
        Policy(
            id="csharp-binary-formatter",
            name="No BinaryFormatter (C#)",
            description="Detect unsafe BinaryFormatter deserialization in C#",
            severity="error",
            languages=["csharp"],
            rules=[
                PolicyRule(
                    pattern=r"BinaryFormatter\s*\(\s*\)",
                    message="BinaryFormatter is insecure — allows arbitrary code execution on deserialization",
                    remediation="Use System.Text.Json or JsonSerializer instead of BinaryFormatter",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"(SoapFormatter|LosFormatter|ObjectStateFormatter|NetDataContractSerializer)\s*\(",
                    message="Insecure .NET deserializer detected",
                    remediation="Use System.Text.Json or JsonSerializer; avoid legacy serializers",
                    cwe_id="CWE-502",
                ),
            ],
        ),
        Policy(
            id="csharp-sql-injection",
            name="No SQL Injection (C#)",
            description="Detect SQL injection via string concatenation in C#",
            severity="error",
            languages=["csharp"],
            rules=[
                PolicyRule(
                    pattern=r'(SqlCommand|SqlDataAdapter)\s*\([^)]*"[^"]*"\s*\+',
                    message="Potential SQL injection: string concatenation in SQL command",
                    remediation="Use parameterized queries with SqlParameter",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r'(SqlCommand|SqlDataAdapter)\s*\([^)]*\$"',
                    message="Potential SQL injection: string interpolation in SQL command",
                    remediation="Use parameterized queries with SqlParameter",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r'ExecuteSqlRaw\s*\([^)]*\$"',
                    message="Potential SQL injection: interpolation in ExecuteSqlRaw",
                    remediation="Use ExecuteSqlInterpolated or parameterized queries",
                    cwe_id="CWE-89",
                ),
            ],
        ),
        Policy(
            id="csharp-process-injection",
            name="No Process Injection (C#)",
            description="Detect command injection via Process.Start in C#",
            severity="error",
            languages=["csharp"],
            rules=[
                PolicyRule(
                    pattern=r"Process\.Start\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in Process.Start",
                    remediation="Validate and sanitize inputs; use ProcessStartInfo with separate arguments",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r'Process\.Start\s*\([^)]*\$"',
                    message="Potential command injection: string interpolation in Process.Start",
                    remediation="Use ProcessStartInfo with Arguments property; validate input",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"ProcessStartInfo\s*\{[^}]*FileName\s*=\s*[^}]*\+",
                    message="Potential command injection in ProcessStartInfo",
                    remediation="Validate file names and arguments; avoid string concatenation",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="csharp-hardcoded-connection-string",
            name="No Hardcoded Connection Strings (C#)",
            description="Detect hardcoded database connection strings in C#",
            severity="error",
            languages=["csharp"],
            rules=[
                PolicyRule(
                    pattern=r'(?i)(connection\s*string|connectionString)\s*=\s*"[^"]*(?:Server|Data Source|Initial Catalog|Password)[^"]*"',
                    message="Hardcoded database connection string detected",
                    flags="i",
                    remediation="Store connection strings in configuration files or Azure Key Vault",
                    cwe_id="CWE-798",
                ),
                PolicyRule(
                    pattern=r'(?i)new\s+SqlConnection\s*\(\s*"[^"]*(?:Server|Data Source)[^"]*"',
                    message="Hardcoded connection string in SqlConnection constructor",
                    flags="i",
                    remediation="Use IConfiguration or secrets manager for connection strings",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="csharp-xxe",
            name="No XXE Vulnerabilities (C#)",
            description="Detect XML External Entity vulnerabilities in C#",
            severity="error",
            languages=["csharp"],
            rules=[
                PolicyRule(
                    pattern=r"XmlReaderSettings\s*\{[^}]*DtdProcessing\s*=\s*DtdProcessing\.Parse",
                    message="DTD processing enabled — XXE vulnerability risk",
                    remediation="Set DtdProcessing = DtdProcessing.Prohibit",
                    cwe_id="CWE-611",
                ),
                PolicyRule(
                    pattern=r"XmlDocument\s*\(\s*\)",
                    message="XmlDocument without safe settings — may be vulnerable to XXE",
                    remediation="Use XmlReader with DtdProcessing.Prohibit, or set XmlResolver = null",
                    cwe_id="CWE-611",
                ),
                PolicyRule(
                    pattern=r"XmlTextReader\s*\(",
                    message="XmlTextReader is vulnerable to XXE by default",
                    remediation="Use XmlReader.Create() with secure XmlReaderSettings",
                    cwe_id="CWE-611",
                ),
            ],
        ),
        # PHP Security Policies (SEN-439)
        Policy(
            id="php-dangerous-functions",
            name="No Dangerous Functions (PHP)",
            description="Detect dangerous exec/system functions in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"\beval\s*\([^)]*\$",
                    message="Dangerous code execution function with variable argument — code injection risk",
                    remediation="Avoid dynamic code execution; use safe alternatives or refactor logic",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\bassert\s*\([^)]*\$_(GET|POST|REQUEST|COOKIE)",
                    message="Dangerous assert with user input — code injection vulnerability",
                    remediation="Avoid assert with dynamic input; use safe alternatives or refactor logic",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\b(exec|system|passthru|shell_exec|popen|proc_open)\s*\([^)]*\$",
                    message="Shell command execution with variable argument — command injection risk",
                    remediation="Validate and escape inputs with escapeshellarg(); avoid shell execution",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\bpreg_replace\s*\([^)]*['\"]/.*/e['\"]",
                    message="preg_replace with /e modifier executes code",
                    remediation="Use preg_replace_callback() instead of the /e modifier",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="php-sql-injection",
            name="No SQL Injection (PHP)",
            description="Detect SQL injection via string concatenation in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(mysql_query|mysqli_query|pg_query)\s*\([^)]*\.\s*\$_(GET|POST|REQUEST|COOKIE)",
                    message="SQL injection: user input concatenated directly in SQL query",
                    flags="i",
                    remediation="Use prepared statements with PDO or mysqli_prepare()",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r'(?i)(mysql_query|mysqli_query|pg_query)\s*\([^)]*"[^"]*\$_(GET|POST|REQUEST|COOKIE)',
                    message="SQL injection: user input interpolated in SQL query",
                    flags="i",
                    remediation="Use prepared statements with PDO or mysqli_prepare()",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r'(?i)(mysql_query|mysqli_query|pg_query)\s*\([^,)]*,\s*"[^"]*\$[a-zA-Z_]',
                    message="SQL injection: variable interpolated in SQL query string",
                    flags="i",
                    remediation="Use prepared statements with PDO or mysqli_prepare()",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"(?i)(mysql_query|mysqli_query|pg_query|->query)\s*\([^)]*(?:SELECT|INSERT|UPDATE|DELETE)[^)]*\.\s*\$",
                    message="Potential SQL injection: variable concatenation in SQL query",
                    flags="i",
                    remediation="Use prepared statements: $stmt = $pdo->prepare(); $stmt->execute()",
                    cwe_id="CWE-89",
                ),
            ],
        ),
        Policy(
            id="php-unserialize",
            name="No Unsafe Unserialize (PHP)",
            description="Detect unsafe unserialize() in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"\bunserialize\s*\(\s*\$_(GET|POST|REQUEST|COOKIE)",
                    message="Unsafe unserialize of user input — object injection vulnerability",
                    remediation="Use json_decode() instead; never unserialize untrusted data",
                    cwe_id="CWE-502",
                ),
                PolicyRule(
                    pattern=r"\bunserialize\s*\(",
                    message="unserialize() usage detected — review for object injection",
                    remediation="Prefer json_decode(); if unserialize is needed, use allowed_classes option",
                    cwe_id="CWE-502",
                ),
            ],
        ),
        Policy(
            id="php-extract",
            name="No Extract from User Input (PHP)",
            description="Detect extract() with user-controlled data in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"\bextract\s*\(\s*\$_(GET|POST|REQUEST|COOKIE|SERVER)",
                    message="extract() with user input overwrites local variables",
                    remediation="Access superglobals directly; never extract() user input",
                    cwe_id="CWE-621",
                ),
            ],
        ),
        Policy(
            id="php-include-injection",
            name="No Include Injection (PHP)",
            description="Detect file inclusion with user-controlled paths in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"\b(include|require|include_once|require_once)\s*\(\s*\$_(GET|POST|REQUEST)",
                    message="File inclusion with user input — LFI/RFI vulnerability",
                    remediation="Never use user input in include/require; use a whitelist of allowed files",
                    cwe_id="CWE-98",
                ),
                PolicyRule(
                    pattern=r"\b(include|require|include_once|require_once)\s*\([^)]*\.\s*\$",
                    message="File inclusion with variable concatenation — potential LFI/RFI",
                    remediation="Validate paths against a whitelist; never concatenate user input",
                    cwe_id="CWE-98",
                ),
            ],
        ),
        Policy(
            id="php-unsanitized-superglobals",
            name="No Unsanitized Superglobals (PHP)",
            description="Detect direct output of unsanitized $_GET/$_POST in PHP",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"echo\s+\$_(GET|POST|REQUEST|COOKIE)\s*\[",
                    message="Direct echo of user input — XSS vulnerability",
                    remediation="Use htmlspecialchars() or htmlentities() to escape output",
                    cwe_id="CWE-79",
                ),
                PolicyRule(
                    pattern=r"print\s+\$_(GET|POST|REQUEST|COOKIE)\s*\[",
                    message="Direct print of user input — XSS vulnerability",
                    remediation="Use htmlspecialchars() or htmlentities() to escape output",
                    cwe_id="CWE-79",
                ),
            ],
        ),
        # C/C++ Security Policies (SEN-439)
        Policy(
            id="c-buffer-overflow",
            name="No Buffer Overflow Functions (C/C++)",
            description="Detect unsafe buffer manipulation functions in C/C++",
            severity="error",
            languages=["c", "cpp"],
            rules=[
                PolicyRule(
                    pattern=r"\b(strcpy|strcat|sprintf|vsprintf)\s*\(",
                    message="Unsafe buffer function — no bounds checking, buffer overflow risk",
                    remediation="Use bounded variants: strncpy, strncat, snprintf, vsnprintf",
                    cwe_id="CWE-120",
                ),
                PolicyRule(
                    pattern=r"\bgets\s*\(",
                    message="gets() is always unsafe — no bounds checking possible",
                    remediation="Use fgets() with explicit buffer size",
                    cwe_id="CWE-120",
                ),
                PolicyRule(
                    pattern=r"\bscanf\s*\(\s*\"[^\"]*%s",
                    message="scanf with %s has no length limit — buffer overflow risk",
                    remediation="Use %Ns with a length limit (e.g., %255s) or fgets()",
                    cwe_id="CWE-120",
                ),
            ],
        ),
        Policy(
            id="c-format-string",
            name="No Format String Vulnerabilities (C/C++)",
            description="Detect format string vulnerabilities in C/C++",
            severity="error",
            languages=["c", "cpp"],
            rules=[
                PolicyRule(
                    pattern=r"\b(printf|fprintf|sprintf|snprintf|syslog)\s*\(\s*[^\"'\s,][^,)]*\)",
                    message="Format string vulnerability: user-controlled format argument",
                    remediation='Always use a literal format string: printf("%s", user_input)',
                    cwe_id="CWE-134",
                ),
            ],
        ),
        Policy(
            id="c-system-injection",
            name="No System Injection (C/C++)",
            description="Detect command injection via system() in C/C++",
            severity="error",
            languages=["c", "cpp"],
            rules=[
                PolicyRule(
                    pattern=r"\bsystem\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in system()",
                    remediation="Avoid system(); use exec-family functions with separate arguments",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\bsystem\s*\(\s*[^\"'\s)]",
                    message="system() with variable argument — potential command injection",
                    remediation="Avoid system(); use execvp() with an argument array",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"\bpopen\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in popen()",
                    remediation="Validate and sanitize inputs before passing to popen()",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="c-use-after-free",
            name="No Use-After-Free Patterns (C/C++)",
            description="Detect potential use-after-free patterns in C/C++",
            severity="error",
            languages=["c", "cpp"],
            rules=[
                PolicyRule(
                    pattern=r"\bfree\s*\([^)]+\)\s*;(?!\s*\w+\s*=\s*NULL)",
                    message="free() without setting pointer to NULL — use-after-free risk",
                    remediation="Set pointer to NULL after free: free(ptr); ptr = NULL;",
                    cwe_id="CWE-416",
                ),
                PolicyRule(
                    pattern=r"\bdelete\s+\w+\s*;(?!\s*\w+\s*=\s*nullptr)",
                    message="delete without setting pointer to nullptr — use-after-free risk",
                    remediation="Set pointer to nullptr after delete, or use smart pointers",
                    cwe_id="CWE-416",
                ),
            ],
        ),
        # Kotlin Security Policies (SEN-432)
        Policy(
            id="kotlin-command-injection",
            name="No Command Injection (Kotlin)",
            description="Detect command injection via Runtime.exec and ProcessBuilder in Kotlin",
            severity="error",
            languages=["kotlin"],
            rules=[
                PolicyRule(
                    pattern=r"Runtime\.getRuntime\(\)\s*\.exec\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in Runtime.exec()",
                    remediation="Validate inputs; use ProcessBuilder with separate arguments",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"Runtime\.getRuntime\(\)\s*\.exec\s*\([^)]*\$",
                    message="Potential command injection: string template in Runtime.exec()",
                    remediation="Use ProcessBuilder with an argument list; validate input",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"ProcessBuilder\s*\([^)]*\+",
                    message="Potential command injection: string concatenation in ProcessBuilder",
                    remediation="Pass arguments as separate list elements; validate input",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"ProcessBuilder\s*\([^)]*\$\{",
                    message="Potential command injection: string template in ProcessBuilder",
                    remediation="Pass arguments as separate list elements; validate input",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="kotlin-weak-crypto",
            name="No Weak Cryptography (Kotlin)",
            description="Detect weak cryptographic algorithms in Kotlin",
            severity="error",
            languages=["kotlin"],
            rules=[
                PolicyRule(
                    pattern=r'Cipher\.getInstance\s*\(\s*"DES',
                    message="DES is a weak cipher — easily brute-forced",
                    remediation='Use AES-256 with GCM mode: Cipher.getInstance("AES/GCM/NoPadding")',
                    cwe_id="CWE-327",
                ),
                PolicyRule(
                    pattern=r'MessageDigest\.getInstance\s*\(\s*"(MD5|SHA-?1)"',
                    message="MD5/SHA-1 is cryptographically broken for security use",
                    remediation="Use SHA-256 or SHA-3 for security-sensitive hashing",
                    cwe_id="CWE-328",
                ),
                PolicyRule(
                    pattern=r'SecretKeySpec\s*\([^)]*"DES"',
                    message="DES key detected — weak encryption",
                    remediation="Use AES with a 256-bit key",
                    cwe_id="CWE-327",
                ),
            ],
        ),
        Policy(
            id="kotlin-hardcoded-secrets",
            name="No Hardcoded Secrets (Kotlin)",
            description="Detect hardcoded API keys and secrets in Kotlin",
            severity="error",
            languages=["kotlin"],
            rules=[
                PolicyRule(
                    pattern=r'(?i)(api[_-]?key|apiKey|secret[_-]?key|secretKey|auth[_-]?token)\s*=\s*"[^"]{8,}"',
                    message="Potential hardcoded API key or secret in Kotlin",
                    flags="i",
                    remediation="Use BuildConfig fields, environment variables, or a secrets manager",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="kotlin-sql-injection",
            name="No SQL Injection (Kotlin)",
            description="Detect SQL injection via string templates in Kotlin",
            severity="error",
            languages=["kotlin"],
            rules=[
                PolicyRule(
                    pattern=r'(?i)(execute|executeQuery|executeUpdate)\s*\(\s*"[^"]*\$\{',
                    message="Potential SQL injection: string template in SQL statement",
                    flags="i",
                    remediation="Use parameterized queries with PreparedStatement",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"(?i)(execute|executeQuery|executeUpdate)\s*\([^)]*\+",
                    message="Potential SQL injection: string concatenation in SQL statement",
                    flags="i",
                    remediation="Use parameterized queries with PreparedStatement",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r'(?i)rawQuery\s*\(\s*"[^"]*\$\{',
                    message="Potential SQL injection: string template in rawQuery (Android)",
                    flags="i",
                    remediation='Use parameterized rawQuery: rawQuery("SELECT ... WHERE id=?", arrayOf(id))',
                    cwe_id="CWE-89",
                ),
            ],
        ),
        # Swift Security Policies (SEN-432)
        Policy(
            id="swift-keychain-misuse",
            name="No Keychain Misuse (Swift)",
            description="Detect secrets stored in UserDefaults instead of Keychain",
            severity="error",
            languages=["swift"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)UserDefaults\.\w+\.set\s*\([^)]*(?:password|secret|token|apiKey|api_key|auth)",
                    message="Sensitive data stored in UserDefaults — not encrypted",
                    flags="i",
                    remediation="Use Keychain Services (SecItemAdd) for sensitive data storage",
                    cwe_id="CWE-922",
                ),
                PolicyRule(
                    pattern=r"(?i)UserDefaults\.\w+\.set\s*\([^)]*(?:credential|private_key|privateKey)",
                    message="Credentials stored in UserDefaults — not encrypted",
                    flags="i",
                    remediation="Use Keychain Services for credential storage",
                    cwe_id="CWE-922",
                ),
            ],
        ),
        Policy(
            id="swift-insecure-http",
            name="No Insecure HTTP (Swift)",
            description="Detect insecure HTTP URLs and ATS exceptions in Swift",
            severity="warning",
            languages=["swift"],
            rules=[
                PolicyRule(
                    pattern=r'URL\s*\(\s*string:\s*"http://',
                    message="Insecure HTTP URL — data transmitted in plaintext",
                    remediation="Use HTTPS URLs for all network requests",
                    cwe_id="CWE-319",
                ),
                PolicyRule(
                    pattern=r"NSAppTransportSecurity.*NSAllowsArbitraryLoads.*true",
                    message="App Transport Security disabled — allows insecure HTTP",
                    remediation="Remove NSAllowsArbitraryLoads; add per-domain HTTPS exceptions if needed",
                    cwe_id="CWE-319",
                ),
            ],
        ),
        Policy(
            id="swift-hardcoded-secrets",
            name="No Hardcoded Secrets (Swift)",
            description="Detect hardcoded API keys and secrets in Swift",
            severity="error",
            languages=["swift"],
            rules=[
                PolicyRule(
                    pattern=r'(?i)(api[_-]?key|apiKey|secret[_-]?key|secretKey|auth[_-]?token)\s*[:=]\s*"[^"]{8,}"',
                    message="Potential hardcoded API key or secret in Swift",
                    flags="i",
                    remediation="Use Keychain, environment variables, or a configuration file excluded from source control",
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="swift-command-injection",
            name="No Command Injection (Swift)",
            description="Detect command injection via Process/NSTask in Swift",
            severity="error",
            languages=["swift"],
            rules=[
                PolicyRule(
                    pattern=r"Process\s*\(\s*\)[\s\S]*?launchPath\s*=\s*.*\+",
                    message="Potential command injection: string concatenation in Process launchPath",
                    remediation="Validate inputs; use arguments array instead of shell interpolation",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r'Process\s*\(\s*\)[\s\S]*?arguments\s*=.*\[.*"(-c|/bin/sh|/bin/bash)',
                    message="Shell execution via Process — potential injection risk",
                    remediation="Avoid shell execution; pass arguments directly to the executable",
                    cwe_id="CWE-78",
                ),
                PolicyRule(
                    pattern=r"NSTask\s*\(",
                    message="NSTask usage detected (deprecated) — review for command injection",
                    remediation="Use Process class; validate all inputs and use arguments array",
                    cwe_id="CWE-78",
                ),
            ],
        ),
        Policy(
            id="swift-insecure-urlsession",
            name="No Insecure URLSession (Swift)",
            description="Detect insecure URLSession configuration in Swift",
            severity="error",
            languages=["swift"],
            rules=[
                PolicyRule(
                    pattern=r"allowsExpiredCertificates\s*=\s*true",
                    message="Expired TLS certificates allowed — insecure connection",
                    remediation="Do not allow expired certificates in production",
                    cwe_id="CWE-295",
                ),
                PolicyRule(
                    pattern=r"allowsExpiredRoots\s*=\s*true",
                    message="Expired root certificates allowed — insecure connection",
                    remediation="Do not allow expired root certificates",
                    cwe_id="CWE-295",
                ),
                PolicyRule(
                    pattern=r"\.performDefaultHandling\s*.*ServerTrust",
                    message="Server trust evaluation bypassed — TLS not properly validated",
                    remediation="Implement proper certificate pinning or validation",
                    cwe_id="CWE-295",
                ),
            ],
        ),
        # ---- Five missing detection rules (Phase 1.3 — IAA gap analysis) ----
        # JS RegExp equivalents documented inline for future TypeScript engine parity.
        Policy(
            id="py-verify-false",
            name="No SSL Verification Bypass (Python)",
            description="Detect disabled SSL/TLS certificate verification in Python HTTP calls",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    # JS equivalent: /verify\s*=\s*False/gi
                    pattern=r"verify\s*=\s*False",
                    message="SSL/TLS certificate verification disabled — enables man-in-the-middle attacks",
                    flags="i",
                    remediation=(
                        "Remove verify=False or set verify=True. "
                        "For self-signed certs in dev, use verify='/path/to/cert.pem' "
                        "or set the REQUESTS_CA_BUNDLE environment variable"
                    ),
                    cwe_id="CWE-295",
                ),
            ],
        ),
        Policy(
            id="py-cert-none",
            name="No SSL Certificate Validation Bypass (Python)",
            description="Detect disabled SSL certificate validation via ssl module settings",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    # JS equivalent: /ssl\.CERT_NONE|check_hostname\s*=\s*False/gi
                    # Split into two rules for Python engine (no alternation at top level
                    # keeps patterns simple and debuggable).
                    pattern=r"ssl\.CERT_NONE",
                    message="SSL certificate validation disabled (CERT_NONE)",
                    flags="i",
                    remediation=(
                        "Use ssl.CERT_REQUIRED instead of ssl.CERT_NONE. "
                        "Load trusted CA certificates with load_default_certs() or load_verify_locations()"
                    ),
                    cwe_id="CWE-295",
                ),
                PolicyRule(
                    pattern=r"check_hostname\s*=\s*False",
                    message="SSL hostname checking disabled — allows certificate spoofing",
                    flags="i",
                    remediation=(
                        "Set check_hostname=True (the default). "
                        "Disabling hostname checking defeats the purpose of TLS"
                    ),
                    cwe_id="CWE-295",
                ),
            ],
        ),
        Policy(
            id="phi-cache-key",
            name="No PHI as Cache/Dictionary Key",
            description="Detect PHI identifiers used as cache or dictionary keys, violating data minimization",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    # JS equivalent: /(key|cache|redis|memcache)[^;\n]{0,50}\b(ssn|social.security|dob|date.of.birth|diagnosis)\b/gi
                    pattern=r"(key|cache|redis|memcache)[^;\n]{0,50}\b(ssn|social[\._]security|dob|date[\._]of[\._]birth|diagnosis)\b",
                    message="PHI identifier used as cache/dictionary key — violates data minimization",
                    flags="i",
                    remediation=(
                        "Use an opaque, non-reversible identifier (e.g., SHA-256 hash or UUID) "
                        "as the cache key instead of raw PHI data. "
                        "PHI should never appear in cache key namespaces"
                    ),
                    cwe_id="CWE-524",
                ),
            ],
        ),
        Policy(
            id="connection-string-credentials",
            name="No Hardcoded Credentials in Connection Strings",
            description="Detect database connection strings with embedded credentials",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    # JS equivalent: /(postgres|postgresql|mysql|mongodb|mongodb\+srv|redis|amqp):\/\/[^\/\s:]+:[^\/@\s]+@/gi
                    pattern=r"(postgres|postgresql|mysql|mongodb|mongodb\+srv|redis|amqp)://[^/\s:]+:[^/@\s]+@",
                    message="Database connection string with embedded credentials — use environment variables or a secrets manager",
                    flags="i",
                    remediation=(
                        "Store connection strings in environment variables (e.g., DATABASE_URL) "
                        "or a secrets manager. Never hardcode credentials in source code."
                    ),
                    cwe_id="CWE-798",
                ),
            ],
        ),
        Policy(
            id="sensitive-logging",
            name="No Sensitive Credentials in Logs",
            description="Detect logging of sensitive credential data such as auth headers, tokens, and cookies",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    # JS equivalent: /(log|logger)\.\w+\([^)]{0,100}\b(header|authorization|bearer|cookie|session[_-]?token|token)\b/gi
                    pattern=r"(log|logger)\.\w+\([^)]{0,100}\b(header|authorization|bearer|cookie|session[_\-]?token)\b",
                    message="Sensitive credential data in log statement",
                    flags="i",
                    remediation=(
                        "Never log raw authentication headers, cookies, or session tokens. "
                        "Log only sanitized/masked values (e.g., last 4 characters). "
                        "Use a structured logger with automatic PII redaction"
                    ),
                    cwe_id="CWE-532",
                ),
            ],
        ),
        Policy(
            id="phi-file-export",
            name="No PHI in File Write/Export",
            description="Detect PHI data in file write or export operations",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    # JS equivalent: /(write|csv|export|dump|open)[^;]{0,50}(ssn|social.security|date.of.birth|diagnosis)/gi
                    pattern=r"(write|csv|export|dump|open)[^;]{0,50}(ssn|social[\._]security|date[\._]of[\._]birth|diagnosis)",
                    message="PHI data in file write/export operation",
                    flags="i",
                    remediation=(
                        "Do not export raw PHI to files. Use tokenized or de-identified values. "
                        "If export is required, ensure encryption at rest, audit logging, "
                        "and compliance with HIPAA Minimum Necessary standard"
                    ),
                    cwe_id="CWE-532",
                ),
            ],
        ),
        # ---- Phase 3: Recall improvement — regex rules for Semgrep gaps ----
        # These rules catch vulnerability patterns that Semgrep taint analysis
        # may miss, particularly in PHP and Python codebases (DVWA, Juice Shop).
        Policy(
            id="no-weak-crypto-md5-php",
            name="No Weak Hash: md5() in PHP (CWE-328)",
            description="Detect PHP md5() used for password hashing or sensitive data",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"md5\s*\(\s*\$",
                    message="Weak hash: md5() used on a variable — md5 is cryptographically broken for password hashing and integrity checks",
                    remediation="Use password_hash() with PASSWORD_BCRYPT for passwords, or hash('sha256', ...) for non-password use cases",
                    cwe_id="CWE-328",
                ),
            ],
        ),
        Policy(
            id="no-weak-crypto-sha1-php",
            name="No Weak Hash: sha1() in PHP (CWE-328)",
            description="Detect PHP sha1() used for token generation or integrity checks",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"sha1\s*\(",
                    message="Weak hash: sha1() is cryptographically broken — do not use for tokens, passwords, or integrity verification",
                    remediation="Use hash('sha256', ...) or password_hash() for passwords; use random_bytes() for token generation",
                    cwe_id="CWE-328",
                ),
            ],
        ),
        Policy(
            id="no-xss-echo-superglobal",
            name="No Direct Echo of Superglobals (CWE-79)",
            description="Detect reflected XSS via direct echo of PHP superglobals",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"echo\s+\$_(GET|POST|REQUEST|COOKIE)\s*\[",
                    message="Reflected XSS: unsanitized superglobal echoed directly to output",
                    remediation="Use htmlspecialchars($var, ENT_QUOTES, 'UTF-8') before echoing user input",
                    cwe_id="CWE-79",
                ),
            ],
        ),
        Policy(
            id="no-file-inclusion-dynamic-include",
            name="No Dynamic Include/Require (CWE-98)",
            description="Detect PHP include/require with variable arguments (file inclusion / path traversal)",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"\b(include|require|include_once|require_once)\s*\(\s*\$",
                    message="Dynamic file inclusion: variable passed to include/require enables Local/Remote File Inclusion (LFI/RFI)",
                    remediation="Use a whitelist of allowed files or map user input to fixed paths instead of including variables directly",
                    cwe_id="CWE-98",
                ),
            ],
        ),
        Policy(
            id="no-file-upload-unrestricted",
            name="No Unrestricted File Upload (CWE-434)",
            description="Detect PHP move_uploaded_file() without apparent validation",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"move_uploaded_file\s*\(",
                    message="Unrestricted file upload: move_uploaded_file() detected — ensure file type, size, and name validation",
                    remediation=(
                        "Validate file extension against an allowlist, check MIME type, "
                        "enforce size limits, and store files outside the web root with randomized names"
                    ),
                    cwe_id="CWE-434",
                ),
            ],
        ),
        Policy(
            id="no-ssrf-urlopen",
            name="No SSRF via urlopen() (CWE-918)",
            description="Detect Python urllib.request.urlopen() with non-literal URL argument",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"urlopen\s*\(\s*(?![\'\"]https?://)[a-zA-Z_]",
                    message="Potential SSRF: urlopen() called with a variable URL — server may fetch attacker-controlled resources",
                    remediation="Validate URLs against an allowlist of permitted hosts/schemes before passing to urlopen()",
                    cwe_id="CWE-918",
                ),
            ],
        ),
        Policy(
            id="no-code-injection-exec-nonliteral",
            name="No Dynamic Code Execution with Non-Literal Argument (CWE-94)",
            description="Detect Python dynamic code execution with variable or expression argument",
            severity="error",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"\bexec\s*\(\s*(?!['\"])[a-zA-Z_]",
                    message="Code injection: dynamic code execution with a non-literal argument — attacker-controlled input may allow arbitrary code to run",
                    remediation="Use ast.literal_eval() for data parsing or a sandboxed interpreter if dynamic code is required",
                    cwe_id="CWE-94",
                ),
            ],
        ),
        Policy(
            id="no-sqli-mysqli-variable",
            name="No SQL Injection via mysqli_query() (CWE-89)",
            description="Detect PHP mysqli_query() with variable interpolation in query string",
            severity="error",
            languages=["php"],
            rules=[
                PolicyRule(
                    pattern=r"mysqli_query\s*\(\s*\$\w+\s*,\s*[\"'][^\"']*\$",
                    message="SQL injection: mysqli_query() with variable interpolation in query string",
                    remediation="Use prepared statements with mysqli_prepare() and bind_param() instead of string interpolation",
                    cwe_id="CWE-89",
                ),
                PolicyRule(
                    pattern=r"mysqli_query\s*\(\s*\$\w+\s*,\s*\$",
                    message="SQL injection: mysqli_query() with variable query — ensure parameterized queries",
                    remediation="Use prepared statements with mysqli_prepare() and bind_param() instead of passing variable queries",
                    cwe_id="CWE-89",
                ),
            ],
        ),
        # ── PHI/PII Detection Policies (DEV-1109) ──────────────────────────
        Policy(
            id="phi-plaintext-ssn-orm",
            name="Plaintext SSN in ORM Model (CWE-312)",
            description="Detect Social Security Numbers stored as plaintext in ORM model definitions",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"models\.(CharField|TextField)\s*\([^)]*\b(ssn|social_security|social_security_number)\b",
                    message="Django ORM model stores SSN as plaintext CharField/TextField",
                    flags="i",
                    remediation="Use django-encrypted-model-fields or django-fernet-fields to encrypt SSN at rest",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"Column\s*\(\s*(String|Text)\b[^)]*\).*\b(ssn|social_security|social_security_number)\b",
                    message="SQLAlchemy model stores SSN as plaintext String/Text column",
                    flags="i",
                    remediation="Use sqlalchemy-utils EncryptedType or a custom encrypted column for SSN fields",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(ssn|social_security|social_security_number)\s*=\s*Column\s*\(\s*(String|Text)\b",
                    message="SQLAlchemy model stores SSN as plaintext String/Text column",
                    flags="i",
                    remediation="Use sqlalchemy-utils EncryptedType or a custom encrypted column for SSN fields",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(ssn|social_security|socialSecurityNumber|social_security_number)\s*:\s*\{?\s*type\s*:\s*(String|DataTypes\.STRING|DataTypes\.TEXT)",
                    message="Sequelize/Mongoose model stores SSN as plaintext String type",
                    flags="i",
                    remediation="Encrypt SSN before storage using crypto.createCipheriv() or a field-level encryption library",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"DataTypes\.(STRING|TEXT)\b[^}]*\b(ssn|social_security|socialSecurityNumber)\b",
                    message="Sequelize model stores SSN as plaintext DataTypes.STRING/TEXT",
                    flags="i",
                    remediation="Encrypt SSN before storage using crypto.createCipheriv() or a field-level encryption library",
                    cwe_id="CWE-312",
                ),
            ],
        ),
        Policy(
            id="phi-plaintext-medical-orm",
            name="Plaintext PHI in ORM Model (CWE-312)",
            description="Detect Protected Health Information stored as plaintext in ORM model definitions",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"models\.(CharField|TextField)\s*\([^)]*\b(diagnosis|medical_record|patient_name|medical_history|treatment_plan|prescription|health_condition)\b",
                    message="Django ORM model stores PHI field as plaintext CharField/TextField",
                    flags="i",
                    remediation="Use django-encrypted-model-fields or django-fernet-fields to encrypt PHI at rest (HIPAA requirement)",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(diagnosis|medical_record|patient_name|medical_history|treatment_plan|prescription|health_condition)\s*=\s*Column\s*\(\s*(String|Text)\b",
                    message="SQLAlchemy model stores PHI field as plaintext String/Text column",
                    flags="i",
                    remediation="Use sqlalchemy-utils EncryptedType for PHI fields (HIPAA requirement)",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"Column\s*\(\s*(String|Text)\b[^)]*\).*\b(diagnosis|medical_record|patient_name|medical_history|treatment_plan|prescription|health_condition)\b",
                    message="SQLAlchemy model stores PHI field as plaintext String/Text column",
                    flags="i",
                    remediation="Use sqlalchemy-utils EncryptedType for PHI fields (HIPAA requirement)",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(diagnosis|medicalRecord|patientName|medicalHistory|treatmentPlan|prescription|healthCondition)\s*:\s*\{?\s*type\s*:\s*(String|DataTypes\.STRING|DataTypes\.TEXT)",
                    message="Sequelize/Mongoose model stores PHI field as plaintext String type",
                    flags="i",
                    remediation="Encrypt PHI fields before storage (HIPAA requirement)",
                    cwe_id="CWE-312",
                ),
            ],
        ),
        Policy(
            id="phi-plaintext-dob-orm",
            name="Plaintext Date of Birth in ORM Model (CWE-312)",
            description="Detect date of birth stored as plaintext in ORM model definitions without encryption",
            severity="warning",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"models\.(CharField|TextField|DateField|DateTimeField)\s*\([^)]*\b(dob|date_of_birth|birth_date|birthdate)\b",
                    message="Django ORM model stores date of birth as plaintext field",
                    flags="i",
                    remediation="Consider encrypting DOB at rest — it is PII under HIPAA and GDPR",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(dob|date_of_birth|birth_date|birthdate)\s*=\s*Column\s*\(\s*(String|Text|Date|DateTime)\b",
                    message="SQLAlchemy model stores date of birth as plaintext column",
                    flags="i",
                    remediation="Consider encrypting DOB at rest — it is PII under HIPAA and GDPR",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(dob|dateOfBirth|birthDate|birth_date)\s*:\s*\{?\s*type\s*:\s*(String|Date|DataTypes\.STRING|DataTypes\.DATE|DataTypes\.DATEONLY)",
                    message="Sequelize/Mongoose model stores date of birth as plaintext field",
                    flags="i",
                    remediation="Consider encrypting DOB at rest — it is PII under HIPAA and GDPR",
                    cwe_id="CWE-312",
                ),
            ],
        ),
        Policy(
            id="phi-endpoint-no-audit-log",
            name="PHI Endpoint Without Audit Logging (CWE-778)",
            description="Detect API route handlers for PHI/medical data that lack audit logging calls",
            severity="warning",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    # BUG-NEW-9: Exclude standalone /health, /healthcheck, /health/ready, /health/live endpoints
                    pattern=r"@(app|router|api)\.(get|post|put|patch|delete)\s*\(\s*['\"][^'\"]*/(patient|medical|(?:health(?![\s'\"/]|check|/ready|/live|/status)\w+)|phi|diagnosis|prescription)[^'\"]*['\"]",
                    message="PHI-related API endpoint detected — verify audit logging is implemented in this handler",
                    flags="i",
                    remediation="Add audit logging (who accessed what PHI, when, from where) per HIPAA access control requirements",
                    cwe_id="CWE-778",
                ),
                PolicyRule(
                    # BUG-NEW-9: Exclude standalone /health, /healthcheck, /health/ready, /health/live endpoints
                    pattern=r"(router|app)\.(get|post|put|patch|delete)\s*\(\s*['\"][^'\"]*/(patient|medical|(?:health(?![\s'\"/]|check|/ready|/live|/status)\w+)|phi|diagnosis|prescription)[^'\"]*['\"]",
                    message="PHI-related Express/Fastify endpoint detected — verify audit logging is implemented",
                    flags="i",
                    remediation="Add audit logging middleware for all PHI endpoints per HIPAA access control requirements",
                    cwe_id="CWE-778",
                ),
            ],
        ),
        Policy(
            id="phi-plaintext-credit-card-orm",
            name="Plaintext Credit Card in ORM Model (CWE-312)",
            description="Detect credit card numbers stored as plaintext in ORM model definitions",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"models\.(CharField|TextField)\s*\([^)]*\b(credit_card|card_number|cc_number|pan_number)\b",
                    message="Django ORM model stores credit card number as plaintext CharField/TextField",
                    flags="i",
                    remediation="Never store full credit card numbers — use a payment processor (Stripe, etc.) or encrypt with PCI DSS compliant field-level encryption",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(credit_card|card_number|cc_number|pan_number|creditCard|cardNumber|ccNumber)\s*=\s*Column\s*\(\s*(String|Text)\b",
                    message="SQLAlchemy model stores credit card number as plaintext String/Text column",
                    flags="i",
                    remediation="Never store full credit card numbers — use a payment processor or PCI DSS compliant encryption",
                    cwe_id="CWE-312",
                ),
                PolicyRule(
                    pattern=r"\b(creditCard|cardNumber|ccNumber|credit_card|card_number|cc_number|pan_number)\s*:\s*\{?\s*type\s*:\s*(String|DataTypes\.STRING|DataTypes\.TEXT)",
                    message="Sequelize/Mongoose model stores credit card number as plaintext String type",
                    flags="i",
                    remediation="Never store full credit card numbers — use a payment processor or PCI DSS compliant encryption",
                    cwe_id="CWE-312",
                ),
            ],
        ),
        # ──────────────────────────────────────────────────────────────
        # WS5: Six New Compliance Framework Policies
        # Added 2026-03-25 for GA Sprint v2.0.0
        # ──────────────────────────────────────────────────────────────
        # NYDFS Part 500 — Regex policies (supplement Semgrep rules)
        Policy(
            id="nydfs-mfa-enforcement",
            name="NYDFS 500.12 MFA Enforcement",
            description="Detect authentication code missing multi-factor authentication verification (NYDFS Part 500.12)",
            severity="error",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    # BUG-NEW-10: Require endpoint/handler context — exclude standalone utility definitions.
                    # Match password verification calls that appear in handler functions (after route decorator
                    # or inside a handler/view function), not utility function definitions like def verify_password().
                    pattern=r"(?i)(?:await\s+|=\s*)(authenticate|login|sign.?in|check.?password|verify.?password|compare.?password)\s*\([^)]*password[^)]*\)",
                    message="NYDFS 500.12: Authentication handler verifies password — ensure MFA/TOTP verification follows",
                    flags="i",
                    remediation="Add multi-factor authentication (TOTP, SMS, or hardware token) after password verification per NYDFS Part 500.12",
                    cwe_id="CWE-308",
                ),
            ],
        ),
        Policy(
            id="nydfs-encryption-at-rest",
            name="NYDFS 500.15 Encryption of Nonpublic Information",
            description="Detect unencrypted storage of nonpublic information (NYDFS Part 500.15)",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(plaintext|plain_text|unencrypted|no.?encrypt)\s*[=:]\s*True",
                    message="NYDFS 500.15: Storage marked as plaintext/unencrypted — nonpublic information must be encrypted at rest",
                    flags="i",
                    remediation="Enable encryption at rest for all nonpublic information per NYDFS Part 500.15",
                    cwe_id="CWE-311",
                ),
            ],
        ),
        # CMMC 2.0 Level 2 — Regex policies
        Policy(
            id="cmmc-security-flaw-comments",
            name="CMMC SI.L2-3.14.1 Security Flaw Remediation",
            description="Detect TODO/FIXME comments with security keywords indicating unresolved security flaws (CMMC SI.L2-3.14.1)",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)\b(TODO|FIXME|HACK|XXX)\b[:\s].*\b(security|vuln|exploit|injection|xss|csrf|auth|permission|privilege|bypass|sanitiz|encry|decrypt|credential|secret|token|password|overflow|dos|ddos)\b",
                    message="CMMC SI.L2-3.14.1: Security-related TODO/FIXME comment indicates unresolved flaw",
                    flags="i",
                    remediation="Remediate security flaws in a timely manner per CMMC SI.L2-3.14.1. Create a tracked issue and fix the vulnerability.",
                    cwe_id="CWE-546",
                ),
            ],
        ),
        Policy(
            id="cmmc-cui-handling",
            name="CMMC MP.L2-3.8.1 CUI Media Protection",
            description="Detect CUI data handling without classification markers (CMMC MP.L2-3.8.1)",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(cui|controlled.?unclassified|fouo|for.?official.?use.?only)\s*[=:]\s*['\"][^'\"]+['\"]",
                    message="CMMC MP.L2-3.8.1: CUI data handling detected — ensure proper classification marking and protection",
                    flags="i",
                    remediation="Apply CUI marking banners and handle according to NIST SP 800-171 media protection requirements",
                    cwe_id="CWE-312",
                ),
            ],
        ),
        # NIST AI RMF — Regex policies
        Policy(
            id="nist-ai-rmf-bias-testing",
            name="NIST AI RMF MAP 2.3 Bias Testing",
            description="Detect ML training code without bias/fairness testing imports (NIST AI RMF MAP 2.3)",
            severity="warning",
            languages=["python"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(model\.fit|model\.train|\.fit\(|\.train\(|trainer\.train)\s*\(",
                    message="NIST AI RMF MAP 2.3: ML model training detected — verify bias testing is performed (fairlearn, aequitas, AIF360)",
                    flags="i",
                    remediation="Import and use bias testing libraries (fairlearn, aequitas, or AIF360) to evaluate model fairness before deployment",
                    cwe_id="CWE-1254",
                ),
            ],
        ),
        Policy(
            id="nist-ai-rmf-human-oversight",
            name="NIST AI RMF GOVERN 1.3 Human Oversight",
            description="Detect automated decision functions without human approval/review workflow (NIST AI RMF GOVERN 1.3)",
            severity="warning",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(auto.?approve|auto.?decision|auto.?reject|automated.?decision|auto.?deny)\s*[=(]",
                    message="NIST AI RMF GOVERN 1.3: Automated decision function detected — ensure human oversight mechanism exists",
                    flags="i",
                    remediation="Implement human-in-the-loop review for consequential automated decisions per NIST AI RMF GOVERN 1.3",
                    cwe_id="CWE-693",
                ),
            ],
        ),
        # FFIEC D&A — Regex policies
        Policy(
            id="ffiec-separation-of-duties",
            name="FFIEC D&A Separation of Duties",
            description="Detect deployment scripts that also modify production data (FFIEC D&A separation of duties)",
            severity="error",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(deploy|deployment|push.?to.?prod|release)\s*[=(].*\b(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE|migrate|seed)\b",
                    message="FFIEC D&A: Deployment code contains data modification — violates separation of duties",
                    flags="i",
                    remediation="Separate deployment and data modification into distinct scripts with different access controls per FFIEC D&A guidelines",
                    cwe_id="CWE-250",
                ),
                PolicyRule(
                    pattern=r"(?i)(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE)\b.*\b(deploy|push|release|promote)\b",
                    message="FFIEC D&A: Data modification code mixed with deployment operations — violates separation of duties",
                    flags="i",
                    remediation="Separate data modification and deployment operations into distinct scripts with different access controls",
                    cwe_id="CWE-250",
                ),
            ],
        ),
        Policy(
            id="ffiec-code-review-gates",
            name="FFIEC D&A Independent Code Review",
            description="Detect direct push commands without PR/review gates (FFIEC D&A independent review)",
            severity="warning",
            languages=["*"],
            rules=[
                PolicyRule(
                    pattern=r"git\s+push\s+.*\b(main|master|prod|production|release)\b",
                    message="FFIEC D&A: Direct push to protected branch — use pull request workflow for independent code review",
                    remediation="Use pull requests with required reviewers instead of direct pushes to production branches per FFIEC D&A guidelines",
                    cwe_id="CWE-1127",
                ),
                PolicyRule(
                    pattern=r"(?i)--force\s+push|push\s+--force|push\s+-f\b",
                    message="FFIEC D&A: Force push detected — may bypass code review controls",
                    remediation="Avoid force pushes; use pull request workflow to maintain audit trail and independent review",
                    cwe_id="CWE-1127",
                ),
            ],
        ),
        # HITRUST CSF v11 — Crosswalk regex policies
        # HITRUST is a meta-framework; most controls map to existing rules.
        # These policies catch HITRUST-specific labeling and awareness gaps.
        Policy(
            id="hitrust-access-control-logging",
            name="HITRUST 01.b User Registration (Access Control Logging)",
            description="Detect user registration/provisioning without audit logging (HITRUST 01.b)",
            severity="warning",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(create.?user|register.?user|add.?user|provision.?user|signup|sign.?up)\s*[=(]",
                    message="HITRUST 01.b: User registration/provisioning detected — ensure audit logging is implemented",
                    flags="i",
                    remediation="Log all user registration and provisioning events to an audit trail per HITRUST CSF 01.b",
                    cwe_id="CWE-778",
                ),
            ],
        ),
        Policy(
            id="hitrust-session-timeout",
            name="HITRUST 01.t Session Time-out",
            description="Detect session configuration without timeout settings (HITRUST 01.t)",
            severity="warning",
            languages=["python", "javascript", "typescript"],
            rules=[
                PolicyRule(
                    pattern=r"(?i)(session|cookie)[_\-.]?(max.?age|expir|timeout|lifetime|ttl)\s*[=:]\s*(0|None|null|undefined|false)",
                    message="HITRUST 01.t: Session configured with no timeout or expiration disabled",
                    flags="i",
                    remediation="Set appropriate session timeout values per HITRUST CSF 01.t. Recommended: 15-30 minutes for sensitive applications.",
                    cwe_id="CWE-613",
                ),
            ],
        ),
    ],
)


def get_default_policies() -> PolicyFile:
    """Get the default built-in policies.

    Returns:
        PolicyFile containing all default policies
    """
    return DEFAULT_POLICY_FILE


# Module-level cache for compiled default rules (~30-50ms cold start savings)
_CACHED_DEFAULT_RULES: list[Rule] | None = None


def get_default_rules() -> list[Rule]:
    """Get default policies as Rule objects for the engine.

    Returns cached rules on subsequent calls to avoid regex recompilation.

    Returns:
        List of Rule objects
    """
    global _CACHED_DEFAULT_RULES

    if _CACHED_DEFAULT_RULES is not None:
        return _CACHED_DEFAULT_RULES

    rules: list[Rule] = []

    for policy in DEFAULT_POLICY_FILE.policies:
        if not policy.enabled:
            continue

        for i, rule_def in enumerate(policy.rules):
            rule_id = f"{policy.id}-{i}" if len(policy.rules) > 1 else policy.id
            rules.append(
                Rule(
                    id=rule_id,
                    name=policy.name,
                    pattern=rule_def.pattern,
                    message=rule_def.message,
                    severity=Severity.from_string(policy.severity),
                    rule_type=RuleType.REGEX,
                    languages=policy.languages,
                    remediation=rule_def.remediation,
                    flags=rule_def.flags,
                    cwe_id=rule_def.cwe_id or "",  # BUG-401: pass CWE ID through
                )
            )

    _CACHED_DEFAULT_RULES = rules
    return rules


# YAML representation for reference/export
DEFAULT_POLICIES_YAML = """
version: "1.0"

metadata:
  name: "MergeGuide Default Policies"
  description: "Built-in security and code quality policies"
  author: "MergeGuide"
  url: "https://github.com/MergeGuide/mergeguide"

policies:
  - id: "no-hardcoded-secrets"
    name: "No Hardcoded Secrets"
    description: "Detect potential hardcoded API keys, passwords, and tokens"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(?i)(api[_-]?key|apikey|api_secret)\\\\s*[=:]\\\\s*['\"][a-zA-Z0-9_\\\\-]{16,}['\"]"
        flags: "i"
        message: "Potential hardcoded API key detected"
        remediation: "Use environment variables or a secrets manager instead"
      - pattern: "(?i)(password|passwd|pwd)\\\\s*[=:]\\\\s*['\"][^'\"]{4,}['\"]"
        flags: "i"
        message: "Potential hardcoded password detected"
        remediation: "Use environment variables or a secrets manager instead"
      - pattern: "(?i)(secret|token|auth[_-]?token)\\\\s*[=:]\\\\s*['\"][a-zA-Z0-9_\\\\-]{8,}['\"]"
        flags: "i"
        message: "Potential hardcoded secret or token detected"
        remediation: "Use environment variables or a secrets manager instead"
      - pattern: "-----BEGIN\\\\s+(RSA\\\\s+)?PRIVATE\\\\s+KEY-----"
        message: "Private key detected in source code"
        remediation: "Store private keys in a secure secrets manager"

  - id: "no-console-log"
    name: "No Console Log in Production"
    description: "Prevent console.log statements in production code"
    severity: warning
    languages: ["javascript", "typescript"]
    rules:
      - pattern: "console\\\\.(log|debug|info|warn|error)\\\\s*\\\\("
        message: "console.log statement detected"
        remediation: "Use a proper logging library with configurable log levels"

  - id: "no-todo-in-code"
    name: "No TODO Comments"
    description: "Flag TODO and FIXME comments for tracking"
    severity: info
    languages: ["*"]
    rules:
      - pattern: "(?i)\\\\b(TODO|FIXME|HACK|XXX)\\\\b[:\\\\s]"
        flags: "i"
        message: "TODO/FIXME comment detected"
        remediation: "Create a tracked issue instead of leaving TODO comments"

  - id: "no-debug-statements"
    name: "No Debug Statements"
    description: "Detect debug statements that shouldn't be in production"
    severity: warning
    languages: ["python"]
    rules:
      - pattern: "\\\\bbreakpoint\\\\s*\\\\(\\\\s*\\\\)"
        message: "Python breakpoint() detected"
        remediation: "Remove debug breakpoints before committing"
      - pattern: "\\\\bpdb\\\\.set_trace\\\\s*\\\\(\\\\s*\\\\)"
        message: "Python debugger statement detected"
        remediation: "Remove pdb.set_trace() before committing"

  - id: "no-eval"
    name: "No Eval Statements"
    description: "Detect dangerous eval() usage"
    severity: error
    languages: ["python", "javascript", "typescript"]
    rules:
      - pattern: "\\\\beval\\\\s*\\\\("
        message: "Dangerous eval() usage detected"
        remediation: "Avoid eval() - use safe alternatives"

  # ---- Phase 1.3: Five missing detection rules (IAA gap analysis) ----

  - id: "py-verify-false"
    name: "No SSL Verification Bypass (Python)"
    description: "Detect disabled SSL/TLS certificate verification in Python HTTP calls"
    severity: error
    languages: ["python"]
    rules:
      - pattern: "verify\\\\s*=\\\\s*False"
        flags: "i"
        message: "SSL/TLS certificate verification disabled — enables man-in-the-middle attacks"
        remediation: "Remove verify=False or set verify=True"

  - id: "py-cert-none"
    name: "No SSL Certificate Validation Bypass (Python)"
    description: "Detect disabled SSL certificate validation via ssl module settings"
    severity: error
    languages: ["python"]
    rules:
      - pattern: "ssl\\\\.CERT_NONE"
        flags: "i"
        message: "SSL certificate validation disabled (CERT_NONE)"
        remediation: "Use ssl.CERT_REQUIRED instead of ssl.CERT_NONE"
      - pattern: "check_hostname\\\\s*=\\\\s*False"
        flags: "i"
        message: "SSL hostname checking disabled — allows certificate spoofing"
        remediation: "Set check_hostname=True (the default)"

  - id: "phi-cache-key"
    name: "No PHI as Cache/Dictionary Key"
    description: "Detect PHI identifiers used as cache or dictionary keys"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(key|cache|redis|memcache)[^;\\n]{0,50}\\\\b(ssn|social[\\\\._]security|dob|date[\\\\._]of[\\\\._]birth|diagnosis)\\\\b"
        flags: "i"
        message: "PHI identifier used as cache/dictionary key — violates data minimization"
        remediation: "Use an opaque identifier (SHA-256 hash or UUID) as the cache key"

  - id: "connection-string-credentials"
    name: "No Hardcoded Credentials in Connection Strings"
    description: "Detect database connection strings with embedded credentials"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(postgres|postgresql|mysql|mongodb|mongodb\\\\+srv|redis|amqp)://[^/\\\\s:]+:[^/@\\\\s]+@"
        flags: "i"
        message: "Database connection string with embedded credentials — use environment variables or a secrets manager"
        remediation: "Store connection strings in environment variables (e.g., DATABASE_URL) or a secrets manager. Never hardcode credentials in source code."

  - id: "sensitive-logging"
    name: "No Sensitive Credentials in Logs"
    description: "Detect logging of sensitive credential data"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(log|logger)\\\\.\\\\w+\\\\([^)]{0,100}\\\\b(header|authorization|bearer|cookie|session[_\\\\-]?token)\\\\b"
        flags: "i"
        message: "Sensitive credential data in log statement"
        remediation: "Never log raw authentication headers, cookies, or session tokens"

  - id: "phi-file-export"
    name: "No PHI in File Write/Export"
    description: "Detect PHI data in file write or export operations"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(write|csv|export|dump|open)[^;]{0,50}(ssn|social[\\\\._]security|date[\\\\._]of[\\\\._]birth|diagnosis)"
        flags: "i"
        message: "PHI data in file write/export operation"
        remediation: "Do not export raw PHI to files; use tokenized or de-identified values"

  # WS5: Six New Compliance Framework Policies (2026-03-25)

  - id: "nydfs-mfa-enforcement"
    name: "NYDFS 500.12 MFA Enforcement"
    description: "Detect authentication code missing MFA verification"
    severity: error
    languages: ["python", "javascript", "typescript"]
    rules:
      - pattern: "(?i)(authenticate|login|sign.?in|check.?password|verify.?password|compare.?password)\\\\s*\\\\([^)]*password[^)]*\\\\)"
        flags: "i"
        message: "NYDFS 500.12: Authentication handler verifies password - ensure MFA/TOTP verification follows"
        remediation: "Add multi-factor authentication after password verification per NYDFS Part 500.12"

  - id: "nydfs-encryption-at-rest"
    name: "NYDFS 500.15 Encryption of Nonpublic Information"
    description: "Detect unencrypted storage of nonpublic information"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(?i)(plaintext|plain_text|unencrypted|no.?encrypt)\\\\s*[=:]\\\\s*True"
        flags: "i"
        message: "NYDFS 500.15: Storage marked as plaintext/unencrypted"
        remediation: "Enable encryption at rest for all nonpublic information per NYDFS Part 500.15"

  - id: "cmmc-security-flaw-comments"
    name: "CMMC SI.L2-3.14.1 Security Flaw Remediation"
    description: "Detect TODO/FIXME with security keywords indicating unresolved flaws"
    severity: warning
    languages: ["*"]
    rules:
      - pattern: "(?i)\\\\b(TODO|FIXME|HACK|XXX)\\\\b[:\\\\s].*\\\\b(security|vuln|exploit|injection|xss|csrf|auth|permission|privilege|bypass|sanitiz|encry|decrypt|credential|secret|token|password|overflow|dos|ddos)\\\\b"
        flags: "i"
        message: "CMMC SI.L2-3.14.1: Security-related TODO/FIXME indicates unresolved flaw"
        remediation: "Remediate security flaws in a timely manner per CMMC SI.L2-3.14.1"

  - id: "cmmc-cui-handling"
    name: "CMMC MP.L2-3.8.1 CUI Media Protection"
    description: "Detect CUI data handling without classification markers"
    severity: warning
    languages: ["*"]
    rules:
      - pattern: "(?i)(cui|controlled.?unclassified|fouo|for.?official.?use.?only)\\\\s*[=:]\\\\s*['\"][^'\"]+['\"]"
        flags: "i"
        message: "CMMC MP.L2-3.8.1: CUI data handling detected - ensure proper classification marking"
        remediation: "Apply CUI marking banners and handle per NIST SP 800-171 media protection requirements"

  - id: "nist-ai-rmf-bias-testing"
    name: "NIST AI RMF MAP 2.3 Bias Testing"
    description: "Detect ML training code without bias/fairness testing"
    severity: warning
    languages: ["python"]
    rules:
      - pattern: "(?i)(model\\\\.fit|model\\\\.train|\\\\.fit\\\\(|\\\\.train\\\\(|trainer\\\\.train)\\\\s*\\\\("
        flags: "i"
        message: "NIST AI RMF MAP 2.3: ML model training detected - verify bias testing is performed"
        remediation: "Use bias testing libraries (fairlearn, aequitas, AIF360) before deployment"

  - id: "nist-ai-rmf-human-oversight"
    name: "NIST AI RMF GOVERN 1.3 Human Oversight"
    description: "Detect automated decision functions without human approval"
    severity: warning
    languages: ["python", "javascript", "typescript"]
    rules:
      - pattern: "(?i)(auto.?approve|auto.?decision|auto.?reject|automated.?decision|auto.?deny)\\\\s*[=(]"
        flags: "i"
        message: "NIST AI RMF GOVERN 1.3: Automated decision function detected - ensure human oversight"
        remediation: "Implement human-in-the-loop review for consequential automated decisions"

  - id: "ffiec-separation-of-duties"
    name: "FFIEC D&A Separation of Duties"
    description: "Detect deployment scripts that also modify production data"
    severity: error
    languages: ["*"]
    rules:
      - pattern: "(?i)(deploy|deployment|push.?to.?prod|release)\\\\s*[=(].*\\\\b(INSERT|UPDATE|DELETE|DROP|ALTER|TRUNCATE|migrate|seed)\\\\b"
        flags: "i"
        message: "FFIEC D&A: Deployment code contains data modification - violates separation of duties"
        remediation: "Separate deployment and data modification into distinct scripts"
      - pattern: "git\\\\s+push\\\\s+.*\\\\b(main|master|prod|production|release)\\\\b"
        message: "FFIEC D&A: Direct push to protected branch - use pull request workflow"
        remediation: "Use pull requests with required reviewers instead of direct pushes"

  - id: "ffiec-code-review-gates"
    name: "FFIEC D&A Independent Code Review"
    description: "Detect force push or review bypass patterns"
    severity: warning
    languages: ["*"]
    rules:
      - pattern: "(?i)--force\\\\s+push|push\\\\s+--force|push\\\\s+-f\\\\b"
        message: "FFIEC D&A: Force push detected - may bypass code review controls"
        remediation: "Avoid force pushes; use pull request workflow to maintain audit trail"

  - id: "hitrust-access-control-logging"
    name: "HITRUST 01.b User Registration"
    description: "Detect user provisioning without audit logging"
    severity: warning
    languages: ["python", "javascript", "typescript"]
    rules:
      - pattern: "(?i)(create.?user|register.?user|add.?user|provision.?user|signup|sign.?up)\\\\s*[=(]"
        flags: "i"
        message: "HITRUST 01.b: User registration detected - ensure audit logging is implemented"
        remediation: "Log all user registration events to an audit trail per HITRUST CSF 01.b"

  - id: "hitrust-session-timeout"
    name: "HITRUST 01.t Session Time-out"
    description: "Detect session configuration without timeout settings"
    severity: warning
    languages: ["python", "javascript", "typescript"]
    rules:
      - pattern: "(?i)(session|cookie)[_\\\\-.]?(max.?age|expir|timeout|lifetime|ttl)\\\\s*[=:]\\\\s*(0|None|null|undefined|false)"
        flags: "i"
        message: "HITRUST 01.t: Session configured with no timeout or expiration disabled"
        remediation: "Set appropriate session timeout values per HITRUST CSF 01.t (15-30 minutes recommended)"
"""
