Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
netresearch avatar

Security Audit

  • 424 installs
  • 32 repo stars
  • Updated August 3, 2026
  • netresearch/security-audit-skill

security-audit is an agent skill that runs structured pre-release security reviews across auth, dependencies, secrets, OWASP risks, cloud IaC, and AI agent configs for developers who need exploitable issues caught before

About

security-audit is an agent skill (version 2.10.3) from Netresearch that guides pre-release security assessments across PHP/TYPO3, Python, JavaScript, Go, Rust, cloud IaC, APIs, frontends, and AI agent configuration files. It bundles 80+ automated checkpoints in checkpoints.yaml, a security-audit-dispatcher.sh that detects 17 technology ecosystems, and reference guides covering OWASP Top 10, OWASP LLM Top 10 2025, CWE Top 25 2025, and CVSS v4.0 scoring patterns. Shell scripts audit local projects or GitHub repositories, while reference files address XXE, deserialization, SSRF, JWT flaws, supply-chain risks, and SKILL.md or mcp.json agent hardening. Developers reach for security-audit before shipping when they need checklist-driven reviews with semgrep, trivy, and gitleaks verification steps instead of ad-hoc grep passes.

  • OWASP-oriented review checklist
  • Secrets and dependency scanning guidance
  • AuthZ/authN misconfiguration checks
  • Pre-release hardening recommendations
  • Risk-prioritized remediation output

Security Audit by the numbers

  • 424 all-time installs (skills.sh)
  • +21 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #541 of 2,203 Security skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/netresearch/security-audit-skill --skill security-audit

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs424
repo stars32
Last updatedAugust 3, 2026
Repositorynetresearch/security-audit-skill

How do you run a pre-release OWASP security audit?

Run structured pre-release security reviews across auth, dependencies, secrets, and OWASP risks to catch exploitable issues before production deployment or customer exposure.

Who is it for?

Developers and security reviewers auditing PHP, TYPO3, polyglot web stacks, cloud IaC, or AI agent repos before production or customer exposure.

Skip if: Teams needing only penetration-test exploitation or runtime incident response rather than pre-release code and configuration review.

When should I use this skill?

Trigger security-audit when preparing a release, reviewing pull requests for OWASP/CWE risks, or auditing SKILL.md, AGENTS.md, or mcp.json agent configurations.

What you get

Security checklist results, CVSS-scored findings, scanner output from semgrep/trivy/gitleaks, and framework-specific remediation references.

  • security checklist report
  • CVSS-scored findings
  • scanner command output

By the numbers

  • Bundles 80+ automated security checkpoints in checkpoints.yaml
  • Auto-detects 17 technology ecosystems via security-audit-dispatcher.sh
  • Published as version 2.10.3 with OWASP LLM Top 10 2025 coverage

Files

checkpoints.yamlYAMLGitHub ↗
# Checkpoints for security-audit skill
# CHECKPOINT TYPE SEMANTICS:
#   `regex`     — passes when pattern IS found. Use for compliance checks
#                 ("composer audit must be in CI", "PHPStan should be present").
#   `regex_not` — passes when pattern is ABSENT. Use for anti-pattern checks
#                 ("$wpdb without prepare", "v-html with user input"). The
#                 vast majority of SA-* checkpoints fall into this category.
#   `not_contains` — passes when pattern is absent from a single file (no glob).
# Inverted semantics caused widespread false positives on clean codebases
# (filed as netresearch/security-audit-skill#60). When adding new checkpoints,
# choose the type that makes a CLEAN project PASS by default.
# Focuses on security best practices for PHP/TYPO3 extensions

version: 2
skill_id: security-audit

mechanical:
  # SECURITY.md existence is covered by SA-SP-01 (warning severity, with
  # org_provides fallback). The previous SA-01 duplicated that check at info
  # severity and was removed.

  # === SECRETS NOT IN VCS ===
  - id: SA-02
    type: contains
    target: .gitignore
    pattern: ".env"
    severity: error
    desc: ".env files must be in .gitignore to prevent credential leaks"

  - id: SA-03
    type: file_not_exists
    target: .env
    severity: error
    desc: ".env file must not be committed to repository"

  - id: SA-04
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "password = "
    severity: warning
    desc: "PHP files should not contain hardcoded password assignments"

  - id: SA-05
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "api_key = "
    severity: warning
    desc: "PHP files should not contain hardcoded API key assignments"

  - id: SA-06
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "secret = "
    severity: warning
    desc: "PHP files should not contain hardcoded secret assignments"

  # === COMPOSER AUDIT IN CI ===
  # CI must run composer audit. Accept either the literal `composer audit`
  # invocation OR a `uses:` reference to the netresearch security reusable
  # workflow (which runs composer audit + SBOM + gitleaks centrally).
  - id: SA-07
    type: regex
    target: .github/workflows/*.yml
    pattern: 'composer[[:space:]]+audit|uses:[[:space:]]+"?netresearch/(typo3-ci-workflows|[.]github)/[.]github/workflows/security[.]yml'
    severity: error
    desc: "CI must run composer audit (directly or via netresearch security reusable workflow)"

  # === XXE PREVENTION ===
  # Use command type to avoid false positives from glob fallback to config files
  - id: SA-08
    type: command
    target: "! grep -rqF 'LIBXML_NOENT' --include='*.php' Classes/ 2>/dev/null"
    severity: error
    desc: "PHP files must not use LIBXML_NOENT flag that enables XXE"

  - id: SA-08b
    type: command
    target: "! grep -rqF 'LIBXML_DTDLOAD' --include='*.php' Classes/ 2>/dev/null"
    severity: error
    desc: "PHP files must not use LIBXML_DTDLOAD flag that enables XXE"

  - id: SA-09
    type: command
    target: "! grep -rqF 'libxml_disable_entity_loader(false)' --include='*.php' Classes/ 2>/dev/null"
    severity: error
    desc: "Must not explicitly enable XML entity loading (XXE vulnerability)"

  # === SQL INJECTION PREVENTION ===
  - id: SA-10
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "$_GET["
    severity: warning
    desc: "Direct use of $_GET should be avoided (use framework request handling)"

  - id: SA-11
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "$_POST["
    severity: warning
    desc: "Direct use of $_POST should be avoided (use framework request handling)"

  - id: SA-12
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "$_REQUEST["
    severity: warning
    desc: "Direct use of $_REQUEST should be avoided (use framework request handling)"

  # === XSS PREVENTION ===
  # Use command type to avoid false positives from glob fallback to config files
  - id: SA-13
    type: command
    target: "! grep -rqF 'echo $' --include='*.php' Classes/ 2>/dev/null"
    severity: warning
    desc: "Direct echo of variables may be XSS vulnerable - use htmlspecialchars()"

  # === DEPENDABOT FOR SECURITY ===
  - id: SA-14
    type: file_exists
    target: .github/dependabot.yml
    severity: warning
    desc: "Dependabot should be enabled for security updates"

  - id: SA-15
    type: contains
    target: .github/dependabot.yml
    pattern: 'package-ecosystem: "composer"'
    severity: warning
    desc: "Dependabot should monitor composer for security vulnerabilities"

  # === DESERIALIZATION PREVENTION ===
  - id: SA-21
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "unserialize($_"
    severity: error
    desc: "Never unserialize user input - use json_decode instead"

  - id: SA-22
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "unserialize($"
    severity: warning
    desc: "unserialize() should use allowed_classes parameter or be replaced with json_decode"

  # === INSECURE PASSWORD HASHING ===
  - id: SA-23
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "md5($pass"
    severity: error
    desc: "md5 must not be used for password hashing - use password_hash()"

  - id: SA-24
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "sha1($pass"
    severity: error
    desc: "sha1 must not be used for password hashing - use password_hash()"

  # === COMMAND INJECTION ===
  - id: SA-25
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "exec($_"
    severity: error
    desc: "Running commands with user input is a command injection vulnerability"

  - id: SA-26
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "system($_"
    severity: error
    desc: "system() with user input is a command injection vulnerability"

  - id: SA-27
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "shell_exec($_"
    severity: error
    desc: "shell_exec() with user input is a command injection vulnerability"

  - id: SA-28
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "passthru($_"
    severity: error
    desc: "passthru() with user input is a command injection vulnerability"

  # === INSECURE RANDOMNESS ===
  - id: SA-29
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "rand()"
    severity: warning
    desc: "rand() should not be used for security purposes - use random_int()"

  - id: SA-30
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "mt_rand()"
    severity: warning
    desc: "mt_rand() should not be used for security purposes - use random_int()"

  # === INFORMATION DISCLOSURE ===
  - id: SA-31
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "phpinfo()"
    severity: warning
    desc: "phpinfo() should not be in production code - information disclosure risk"

  # === FILE UPLOAD SAFETY ===
  - id: SA-32
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "move_uploaded_file($_"
    severity: warning
    desc: "Direct move_uploaded_file with superglobal needs security review - use framework file handling"

  # === COOKIE SECURITY ===
  - id: SA-33
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "$_COOKIE["
    severity: warning
    desc: "Direct use of $_COOKIE should be avoided (use framework request handling)"

  # === OPEN REDIRECT ===
  - id: SA-34
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "header('Location: ' . $_"
    severity: error
    desc: "Open redirect vulnerability - never use user input directly in Location header"

  - id: SA-35
    type: not_contains
    target: "Classes/**/*.php"
    pattern: 'header("Location: " . $_'
    severity: error
    desc: "Open redirect vulnerability - never use user input directly in Location header"

  # === SECURITY HEADERS ===
  - id: SA-36
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "X-XSS-Protection: 1"
    severity: warning
    desc: "X-XSS-Protection is deprecated - use Content-Security-Policy instead"

  # === CODE INJECTION (CWE-94) ===
  - id: SA-37
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "eval($_"
    severity: error
    desc: "Code injection via eval() with user input (CWE-94)"

  - id: SA-38
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "assert($_"
    severity: error
    desc: "Code injection via assert() with user input (CWE-94)"

  - id: SA-39
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "preg_replace\\s*\\(.*?/e['\"]"
    severity: error
    desc: "Deprecated /e modifier in preg_replace enables code execution (CWE-94)"

  # === IDOR (CWE-639) ===
  - id: SA-40
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "->find\\(\\$_(GET|POST|REQUEST)\\["
    severity: warning
    desc: "Direct use of user-supplied ID in database lookup without authorization check (CWE-639 IDOR)"

  # === SECRET SCANNING ===
  - id: SA-SEC-01
    type: not_contains
    target: "**/*.php"
    pattern: "AKIA"
    severity: error
    desc: "Possible AWS access key found in source code"

  - id: SA-SEC-02
    type: not_contains
    target: "**/*.php"
    pattern: "sk-ant-"
    severity: error
    desc: "Possible Anthropic API key found in source code"

  - id: SA-SEC-03
    type: not_contains
    target: "**/*.php"
    pattern: "sk-proj-"
    severity: error
    desc: "Possible OpenAI API key found in source code"

  - id: SA-SEC-04
    type: file_exists
    target: .gitignore
    severity: error
    desc: ".gitignore must exist to prevent accidental secret commits"

  # === SUPPLY CHAIN ===
  # composer.lock should be COMMITTED for APPLICATIONS (project root,
  # deployable installs) but GITIGNORED for LIBRARIES / TYPO3 EXTENSIONS
  # (the lock would freeze transitive deps that the consuming application
  # needs to resolve fresh — locally generated lock files are fine).
  # Gate on composer.json `type` AND check git-tracked status (not just
  # filesystem presence — devs often have a locally-generated lock):
  #  - typo3-cms-extension / library / metapackage → must NOT be tracked
  #  - everything else (project, …) → must BE tracked
  - id: SA-SC-01
    type: command
    pattern: 'if jq -re ".type" composer.json 2>/dev/null | grep -qE "^(typo3-cms-extension|library|metapackage|composer-plugin)$"; then [ -z "$(git ls-files composer.lock 2>/dev/null)" ]; else [ -n "$(git ls-files composer.lock 2>/dev/null)" ]; fi'
    severity: warning
    desc: "composer.lock should be git-tracked for applications, but git-ignored for libraries / TYPO3 extensions (would freeze transitive deps for consumers). Gated by composer.json type + git ls-files."

  # Use single-quoted YAML so the runner (which captures inner-quote content
  # verbatim via regex without YAML unescape) sees a usable bash string. The
  # jq filter is wrapped in bash double-quotes with `\"` for jq string
  # literals — the runner regex preserves backslashes, and bash unescapes
  # them on `<<<` invocation. Empty input (no composer.json) → jq exits
  # non-zero → `!` makes the checkpoint pass (skip).
  - id: SA-SC-02
    type: command
    target: '! jq -e "([.require // {}, .[\"require-dev\"] // {}] | add | to_entries[] | select(.value == \"*\" and (.key | startswith(\"netresearch/\") | not)))" composer.json >/dev/null 2>&1'
    severity: error
    desc: "Wildcard (*) version constraints are insecure for external packages. Internal netresearch/* packages may use '*' (intentional intra-org versioning)."

  # === TYPE JUGGLING (CWE-843) ===
  - id: SA-41
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "==\\s*\\$_(GET|POST|REQUEST|COOKIE)"
    severity: error
    desc: "Loose comparison (==) with superglobal enables type juggling attacks (CWE-843)"

  - id: SA-42
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "in_array\\s*\\(\\s*\\$_(GET|POST|REQUEST|COOKIE)[^,)]*,[^,)]*(?:,\\s*(?!true)[^)]*)?\\)"
    severity: warning
    desc: "in_array() with superglobal without strict flag enables type juggling (CWE-843)"

  # === PHAR DESERIALIZATION (CWE-502) ===
  - id: SA-43
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "phar://"
    severity: error
    desc: "phar:// stream wrapper triggers deserialization and can lead to RCE (CWE-502)"

  # === SSTI (CWE-1336) ===
  - id: SA-44
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "createTemplate\\s*\\(.*\\$"
    severity: error
    desc: "Dynamic template creation with variables enables server-side template injection (CWE-1336)"

  # === EMAIL HEADER INJECTION (CWE-93) ===
  - id: SA-45
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "\\bmail\\s*\\([^)]*\\$_(GET|POST|REQUEST)"
    severity: error
    desc: "mail() with user input enables email header injection via CRLF (CWE-93)"

  # === LDAP INJECTION (CWE-90) ===
  - id: SA-46
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "ldap_(search|bind)\\s*\\([^)]*\\$_(GET|POST|REQUEST)"
    severity: error
    desc: "LDAP operations with user input without ldap_escape() enables LDAP injection (CWE-90)"

  # === INSECURE TOKEN GENERATION (CWE-330) ===
  - id: SA-47
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "(md5|sha1)\\s*\\(\\s*(time|microtime|uniqid|rand|mt_rand)\\s*\\("
    severity: error
    desc: "Predictable token generation using md5/sha1 of time/rand (CWE-330) - use random_bytes()"

  # === LOG INJECTION / CRLF (CWE-117) ===
  - id: SA-48
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "error_log\\s*\\([^)]*\\$_(GET|POST|REQUEST|COOKIE)"
    severity: warning
    desc: "Logging user input without sanitization enables log injection/forgery (CWE-117)"

  # === SESSION FIXATION (CWE-384) ===
  - id: SA-49
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "session_id\\s*\\(\\s*\\$_(GET|POST|REQUEST|COOKIE)"
    severity: error
    desc: "Setting session ID from user input enables session fixation attacks (CWE-384)"

  # === HOST HEADER POISONING (CWE-644) ===
  - id: SA-50
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "\\$_SERVER\\[['\"]HTTP_HOST['\"]\\].*(/reset|/confirm|/verify|/activate)"
    severity: warning
    desc: "HTTP_HOST used in security-critical URL construction enables host header poisoning (CWE-644)"

  # === MASS ASSIGNMENT (CWE-915) ===
  - id: SA-51
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "\\$guarded\\s*=\\s*\\[\\s*\\]"
    severity: error
    desc: "Empty $guarded array allows mass assignment of all model fields (CWE-915)"

  - id: SA-52
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "->allowAllProperties()"
    severity: error
    desc: "allowAllProperties() disables TYPO3 Extbase mass assignment protection (CWE-915)"

  # === SAST TOOLING ===
  - id: SA-SAST-01
    type: regex
    target: .github/workflows/*.yml
    pattern: 'phpstan|uses:[[:space:]]+"?netresearch/typo3-ci-workflows/[.]github/workflows/ci[.]yml'
    severity: warning
    desc: "PHPStan should be configured in CI (directly or via netresearch typo3-ci-workflows reusable workflow which runs PHPStan)"

  # === DEPENDENCY SCANNING ===
  - id: SA-DEP-01
    type: file_exists
    target: .github/dependabot.yml
    severity: warning
    desc: "Dependabot or Renovate should be configured for dependency updates"

  - id: SA-DEP-02
    type: regex
    target: .github/workflows/*.yml
    pattern: 'composer[[:space:]]+audit|trivy|snyk|uses:[[:space:]]+"?netresearch/(typo3-ci-workflows|[.]github)/[.]github/workflows/security[.]yml'
    severity: warning
    desc: "CI should include dependency vulnerability scanning (composer audit/trivy/snyk or via netresearch security reusable workflow)"

  # === GITLEAKS IN CI ===
  - id: SA-DEP-03
    type: regex
    target: .github/workflows/*.yml
    pattern: 'gitleaks|uses:[[:space:]]+"?netresearch/(typo3-ci-workflows|[.]github)/[.]github/workflows/security[.]yml'
    severity: info
    desc: "CI should include gitleaks for secret scanning (directly or via netresearch security reusable workflow)"

  # === NPM DEPENDENCY MONITORING ===
  - id: SA-DEP-04
    type: file_exists_conditional
    condition_file: package.json
    severity: warning
    desc: "npm dependencies monitored when package.json exists"
    check: |
      If package.json exists, verify that:
      1. .github/dependabot.yml is configured to monitor the "npm" package-ecosystem.
      2. CI runs `npm audit` and is configured to fail the build on vulnerabilities (e.g., using `--audit-level=high`).
      3. CI runs `npm audit signatures` to verify package integrity.
    tags: [dependencies, npm, supply-chain]

  # === GITHUB ACTIONS INJECTION ===
  - id: SA-GHA-01
    type: regex_not
    target: .github/workflows/*.yml
    pattern: 'run:.*\$\{\{\s*inputs\.'
    severity: error
    desc: "Workflow run: blocks must not interpolate ${{ inputs.* }} directly (code injection). Use env: block instead. Note: only catches single-line run: — SA-GHA-03 LLM review covers multi-line blocks"

  - id: SA-GHA-02
    type: regex_not
    target: .github/workflows/*.yml
    pattern: 'run:.*\$\{\{\s*github\.event\.'
    severity: error
    desc: "Workflow run: blocks must not interpolate ${{ github.event.* }} directly (code injection). Use env: block instead. Note: only catches single-line run: — SA-GHA-03 LLM review covers multi-line blocks"

  # === PATH TRAVERSAL PREVENTION (CWE-22) ===
  - id: SA-53
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "(file_get_contents|fopen|include|require)\\s*\\(.*\\$_(GET|POST|REQUEST)"
    severity: error
    desc: "File operations with user input without path validation enables path traversal (CWE-22)"

  - id: SA-54
    type: not_contains
    target: "Classes/**/*.php"
    pattern: "../"
    severity: warning
    desc: "Hardcoded relative path traversal patterns should be avoided in PHP source"

  # === SEMGREP / OPENGREP IN CI ===
  - id: SA-SAST-02
    type: regex
    target: .github/workflows/*.yml
    pattern: 'semgrep|opengrep|uses:[[:space:]]+"?netresearch/(typo3-ci-workflows|[.]github)/[.]github/workflows/security[.]yml'
    severity: info
    desc: "CI should include semgrep or opengrep for SAST scanning (directly or via netresearch security reusable workflow which runs Opengrep)"

  # === SECURITY POLICY ===
  - id: SA-SP-01
    type: file_exists
    target: "{SECURITY.md,.github/SECURITY.md,docs/SECURITY.md}"
    org_provides: SECURITY.md
    severity: warning
    desc: "SECURITY.md must exist with vulnerability reporting instructions. Satisfied org-wide via {owner}/.github/SECURITY.md when present."

  - id: SA-SP-02
    type: contains
    target: "{SECURITY.md,.github/SECURITY.md,docs/SECURITY.md}"
    pattern: "Reporting"
    severity: warning
    desc: "SECURITY.md should contain reporting instructions"

  # === CSP COMPLIANCE ===
  - id: SA-CSP-01
    type: regex_not
    target: "Resources/Private/**/*.html"
    pattern: '<script(?![^>]*\bsrc\s*=)[^>]*>'
    severity: error
    desc: "Inline <script> tags violate Content Security Policy. Move JavaScript to external files loaded via f:be.pageRenderer includeJsFiles or AssetCollector API"

  - id: SA-CSP-02
    type: regex_not
    target: "Resources/Private/**/*.html"
    pattern: '\son\w+\s*='
    severity: error
    desc: "Inline event handlers (on*= attributes) violate CSP. Use addEventListener() in external JavaScript files instead"

  # === Imported from evandervecht/security-audit-skill fork (2026-04-19) ===
  # Per-language, per-framework, cloud, mobile, and IaC checkpoints.
  # Authored by E van der Vecht (MIT + CC-BY-SA-4.0 dual-licensed).
  # Consumed by scripts/security-audit-dispatcher.sh and scripts/scanners/*.sh.

  # === SECURITY DOCUMENTATION ===
  # === SECRETS NOT IN VCS ===
  # === COMPOSER AUDIT IN CI ===
  # === XXE PREVENTION ===
  # Use command type to avoid false positives from glob fallback to config files
  # === SQL INJECTION PREVENTION ===
  # === XSS PREVENTION ===
  # Use command type to avoid false positives from glob fallback to config files
  # === DEPENDABOT FOR SECURITY ===
  # === DESERIALIZATION PREVENTION ===
  # === INSECURE PASSWORD HASHING ===
  # === COMMAND INJECTION ===
  # === INSECURE RANDOMNESS ===
  # === INFORMATION DISCLOSURE ===
  # === FILE UPLOAD SAFETY ===
  # === COOKIE SECURITY ===
  # === OPEN REDIRECT ===
  # === SECURITY HEADERS ===
  # === CODE INJECTION (CWE-94) ===
  # === IDOR (CWE-639) ===
  # === SECRET SCANNING ===
  # === SUPPLY CHAIN ===
  # === TYPE JUGGLING (CWE-843) ===
  # === PHAR DESERIALIZATION (CWE-502) ===
  # === SSTI (CWE-1336) ===
  # === EMAIL HEADER INJECTION (CWE-93) ===
  # === LDAP INJECTION (CWE-90) ===
  # === INSECURE TOKEN GENERATION (CWE-330) ===
  # === LOG INJECTION / CRLF (CWE-117) ===
  # === SESSION FIXATION (CWE-384) ===
  # === HOST HEADER POISONING (CWE-644) ===
  # === MASS ASSIGNMENT (CWE-915) ===
  # === SAST TOOLING ===
  # === DEPENDENCY SCANNING ===
  # === GITLEAKS IN CI ===
  # === PATH TRAVERSAL PREVENTION (CWE-22) ===
  # === SEMGREP IN CI ===
  # === SECURITY POLICY ===
  # === INFRASTRUCTURE-AS-CODE SECURITY ===
  - id: SA-IAC-01
    type: command
    target: "for f in Dockerfile*; do [ -f \"$f\" ] || continue; grep -qE '^\\s*USER\\s' \"$f\" || exit 1; ! grep -qE '^\\s*USER\\s+root\\b' \"$f\" || exit 1; done"
    severity: warning
    desc: "Dockerfile must declare a non-root USER directive (missing USER means container runs as root)"

  - id: SA-IAC-02
    type: command
    target: "! grep -rqE '(COPY|ADD).*\\.env' Dockerfile* 2>/dev/null"
    severity: error
    desc: "Dockerfile must not copy .env files into image layers (secrets leak)"

  - id: SA-IAC-03
    type: command
    target: "! grep -rqE 'ARG.*(PASSWORD|SECRET|TOKEN|API_KEY)' Dockerfile* 2>/dev/null"
    severity: error
    desc: "Dockerfile ARG must not contain secrets (visible in image history)"

  - id: SA-IAC-04
    type: command
    target: "! grep -rqE '^FROM\\s+\\w+\\s*$' Dockerfile* 2>/dev/null"
    severity: warning
    desc: "Dockerfile base images should be pinned to specific tags or digests, not latest"

  - id: SA-IAC-05
    type: command
    target: "! grep -rqE 'privileged:\\s*true' docker-compose*.yml 2>/dev/null"
    severity: error
    desc: "Docker Compose must not use privileged mode (container escape risk)"

  - id: SA-IAC-06
    type: command
    target: "! grep -rqE '/var/run/docker\\.sock' docker-compose*.yml 2>/dev/null"
    severity: error
    desc: "Docker Compose must not mount Docker socket (container escape risk)"

  - id: SA-IAC-07
    type: command
    target: "! grep -rqE 'runAsUser:\\s*0' k8s/ kubernetes/ deploy/ manifests/ charts/ 2>/dev/null"
    severity: error
    desc: "Kubernetes pods must not run as root (runAsUser: 0)"

  - id: SA-IAC-08
    type: command
    target: "! grep -rqE 'hostNetwork:\\s*true' k8s/ kubernetes/ deploy/ manifests/ charts/ 2>/dev/null"
    severity: error
    desc: "Kubernetes pods should not use host networking"

  - id: SA-IAC-09
    type: command
    target: "! grep -rqE 'cidr_blocks.*0\\.0\\.0\\.0/0' --include='*.tf' . 2>/dev/null"
    severity: warning
    desc: "Terraform security groups should not allow unrestricted ingress (0.0.0.0/0)"

  - id: SA-IAC-10
    type: command
    target: "! grep -rqE 'acl.*public' --include='*.tf' . 2>/dev/null"
    severity: warning
    desc: "Terraform S3 buckets should not use public ACLs"

  # === FRONTEND/CLIENT-SIDE SECURITY ===
  # Look for risky innerHTML assignments. Recognised SAFE forms (will not
  # trip the check, all per-line):
  #  - assignment from a single-/double-quoted string literal
  #    (no interpolation possible)
  #  - same-line escaping helper call: escapeHtml(...), DOMPurify.sanitize(...),
  #    sanitize(...)
  #  - explicit safety marker: `// eslint-disable-line no-unsanitized/property`
  #    or `// noqa: SA-FE-01`
  # Anything else (template literals starting with bare backtick, variables,
  # function calls) trips the check. Add the eslint-disable / noqa marker if
  # the value is provably safe (e.g. statically built HTML), or refactor to
  # textContent / createElement.
  - id: SA-FE-01
    type: regex_not
    target: "**/*.js"
    pattern: '\.innerHTML[[:space:]]*=(?!([[:space:]]*["''][^"'']*["''][[:space:]]*;|.*(escapeHtml|DOMPurify|sanitize|eslint-disable-line[[:space:]]+no-unsanitized|noqa:[[:space:]]+SA-FE-01)))'
    severity: warning
    desc: "Direct innerHTML assignment without an escaping/sanitising helper may enable DOM-based XSS. Recognised safe forms: string-literal assignment, same-line escapeHtml()/DOMPurify.sanitize(), or `// eslint-disable-line no-unsanitized/property`. Otherwise refactor to textContent/createElement."

  - id: SA-FE-02
    type: not_contains
    target: "**/*.js"
    pattern: "document.write("
    severity: warning
    desc: "document.write() may enable DOM-based XSS - use DOM manipulation methods"

  - id: SA-FE-03
    type: command
    target: "! grep -rqE 'eval\\s*\\(' --include='*.js' --include='*.ts' . 2>/dev/null"
    severity: warning
    desc: "eval() in JavaScript enables code injection - use safer alternatives"

  - id: SA-FE-04
    type: command
    target: "! grep -rqE 'localStorage\\.(set|get)Item.*(token|password|secret|key|credential|session)' --include='*.js' --include='*.ts' . 2>/dev/null"
    severity: error
    desc: "Sensitive data (tokens, passwords, secrets) must not be stored in localStorage"

  - id: SA-FE-05
    type: command
    target: "! grep -rqE 'Access-Control-Allow-Origin.*\\*' --include='*.php' --include='*.js' --include='*.conf' --include='*.yaml' --include='*.yml' . 2>/dev/null"
    severity: warning
    desc: "CORS wildcard (*) origin should be avoided - use specific allowed origins"

  - id: SA-FE-06
    type: command
    target: "! grep -rqE 'new Function\\s*\\(' --include='*.js' --include='*.ts' . 2>/dev/null"
    severity: warning
    desc: "new Function() enables dynamic code execution - use safer alternatives"

  # === AI/LLM AGENT SECURITY ===
  - id: SA-AI-01
    type: command
    target: "! grep -rqE '(api_key|apiKey|API_KEY|secret|password|token)\\s*[:=]\\s*[\"'\\''](sk-|AKIA|ghp_|ghs_)' SKILL.md AGENTS.md CLAUDE.md .claude/ 2>/dev/null"
    severity: error
    desc: "AI agent config files must not contain hardcoded API keys or secrets"

  - id: SA-AI-02
    type: command
    target: "! grep -rqE 'dangerouslyDisableSandbox|--no-verify|--force' SKILL.md AGENTS.md CLAUDE.md .claude/ 2>/dev/null"
    severity: error
    desc: "AI agent configs must not disable safety mechanisms (sandbox, hooks, verification)"

  - id: SA-AI-03
    type: command
    target: "! grep -rqE 'Bash\\(\\*\\)|allowed-tools:.*Bash\\b[^(]' SKILL.md skills/*/SKILL.md 2>/dev/null"
    severity: warning
    desc: "AI skills should not grant unrestricted Bash access - scope to specific commands"

  - id: SA-AI-04
    type: command
    target: "! grep -rqE '\"version\"\\s*:\\s*\"latest\"' .claude/mcp*.json mcp.json 2>/dev/null"
    severity: warning
    desc: "MCP server versions should be pinned, not 'latest' (supply chain risk)"

  # === JAVASCRIPT/TYPESCRIPT SECURITY ===
  - id: SA-JS-01
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "eval\\("
    severity: error
    desc: "eval() usage detected - potential code injection"

  - id: SA-JS-02
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "\\.innerHTML\\s*="
    severity: error
    desc: "innerHTML assignment detected - potential DOM XSS"

  - id: SA-JS-03
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "document\\.write\\("
    severity: error
    desc: "document.write() usage detected - potential DOM XSS"

  - id: SA-JS-04
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "addEventListener\\(.message"
    severity: warning
    desc: "postMessage handler detected - verify origin validation"

  - id: SA-JS-05
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "Math\\.random\\(\\)"
    severity: warning
    desc: "Math.random() is not cryptographically secure - use crypto.getRandomValues()"

  - id: SA-JS-06
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "__proto__"
    severity: error
    desc: "__proto__ access detected - potential prototype pollution"

  - id: SA-JS-07
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "new\\s+Function\\("
    severity: error
    desc: "Function constructor detected - equivalent to eval()"

  - id: SA-JS-08
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "setTimeout\\(\\s*['\"`]"
    severity: error
    desc: "setTimeout with string argument - implicit eval()"

  - id: SA-JS-09
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "\\.outerHTML\\s*="
    severity: error
    desc: "outerHTML assignment detected - potential DOM XSS"

  - id: SA-JS-10
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "\\bdebugger\\b"
    severity: warning
    desc: "debugger statement detected - must not ship to production"

  - id: SA-JS-11
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "require\\(.serialize-javascript"
    severity: warning
    desc: "serialize-javascript outputs executable JS - ensure output is never eval'd"

  - id: SA-JS-12
    type: regex_not
    target: "**/*.{ts,tsx}"
    pattern: ":\\s*any\\b"
    severity: warning
    desc: "TypeScript 'any' type disables type checking - use 'unknown' for untrusted input"

  - id: SA-JS-13
    type: regex_not
    target: "**/*.{ts,tsx}"
    pattern: "as\\s+unknown\\s+as"
    severity: error
    desc: "Double type assertion bypasses TypeScript safety - use runtime validation"

  - id: SA-JS-14
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "import\\([^)]*\\$\\{"
    severity: error
    desc: "Dynamic import with template variable - potential module injection"

  - id: SA-JS-15
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "setInterval\\(\\s*['\"`]"
    severity: error
    desc: "setInterval with string argument - implicit eval()"

  - id: SA-JS-17
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx,mjs,cjs}"
    pattern: "postMessage\\([^,]+,\\s*['\"]\\*['\"]"
    severity: error
    desc: "postMessage with wildcard origin - data exposed to any frame"

  # === NODE.JS SERVER-SIDE SECURITY (Phase 3) ===
  - id: SA-NODE-01
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "child_process.*exec\\("
    severity: error
    desc: "child_process.exec() with potential command injection — use execFile or spawn instead"

  - id: SA-NODE-02
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "fs\\.(readFile|writeFile|readdir|unlink).*req\\.(query|params|body)"
    severity: error
    desc: "fs operation with user input — validate and restrict paths with path.resolve + startsWith"

  - id: SA-NODE-03
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "require\\s*\\(\\s*['\"]vm2?['\"]\\s*\\)"
    severity: error
    desc: "vm/vm2 module is not a security boundary — use OS-level isolation for untrusted code"

  - id: SA-NODE-04
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "Buffer\\.(allocUnsafe|allocUnsafeSlow)\\s*\\("
    severity: warning
    desc: "Buffer.allocUnsafe returns uninitialized memory — use Buffer.alloc unless fully overwritten"

  - id: SA-NODE-05
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "require\\s*\\(\\s*[^'\"\\s].*[+`]"
    severity: error
    desc: "Dynamic require() with variable path — use an allowlist of permitted modules"

  - id: SA-NODE-06
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "(hashSync|compareSync|pbkdf2Sync|scryptSync)\\s*\\("
    severity: warning
    desc: "Synchronous crypto in request handler blocks event loop — use async variant"

  - id: SA-NODE-07
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "res\\.(setHeader|writeHead)\\s*\\([^)]*req\\.(query|params|body|headers)"
    severity: error
    desc: "User input in HTTP response header — risk of CRLF injection"

  - id: SA-NODE-08
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "Math\\.random\\s*\\("
    severity: warning
    desc: "Math.random() is not cryptographically secure — use crypto.randomUUID() or crypto.randomBytes()"

  - id: SA-NODE-09
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "http\\.createServer\\s*\\("
    severity: warning
    desc: "http.createServer — verify headersTimeout, requestTimeout, and body size limits are set"

  - id: SA-NODE-10
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "Object\\.assign\\s*\\([^,]+,\\s*req\\.(body|query|params)"
    severity: error
    desc: "Object.assign with user input — risk of prototype pollution"

  - id: SA-NODE-11
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "\\beval\\s*\\("
    severity: error
    desc: "eval() executes arbitrary code — use safe alternatives"

  - id: SA-NODE-12
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "createHash\\s*\\(\\s*['\"]md5['\"]"
    severity: warning
    desc: "MD5 is cryptographically broken — use SHA-256 or stronger"

  - id: SA-NODE-13
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "createHash\\s*\\(\\s*['\"]sha1['\"]"
    severity: warning
    desc: "SHA-1 is cryptographically weak — use SHA-256 or stronger"

  - id: SA-NODE-14
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "new\\s+Function\\s*\\("
    severity: error
    desc: "new Function() is equivalent to eval — use safe alternatives"

  - id: SA-NODE-15
    type: regex_not
    target: "**/*.{js,ts,mjs,cjs}"
    pattern: "fetch\\s*\\(\\s*req\\.(query|params|body)"
    severity: error
    desc: "fetch with user-supplied URL — risk of SSRF, validate and restrict URLs"

  # === PYTHON SECURITY CHECKS (Phase 4) ===
  - id: SA-PY-01
    type: regex_not
    target: "**/*.py"
    pattern: "pickle\\.(loads|load)\\("
    severity: error
    desc: "Insecure deserialization via pickle"

  - id: SA-PY-02
    type: regex_not
    target: "**/*.py"
    pattern: "eval\\("
    severity: error
    desc: "Code injection via eval()"

  - id: SA-PY-03
    type: regex_not
    target: "**/*.py"
    pattern: "exec\\("
    severity: error
    desc: "Code injection via exec()"

  - id: SA-PY-04
    type: regex_not
    target: "**/*.py"
    pattern: "subprocess\\.\\w+\\(.*shell\\s*=\\s*True"
    severity: error
    desc: "Command injection via subprocess with shell=True"

  - id: SA-PY-05
    type: regex_not
    target: "**/*.py"
    pattern: "os\\.system\\("
    severity: error
    desc: "Command injection via os.system()"

  - id: SA-PY-06
    type: regex_not
    target: "**/*.py"
    pattern: "yaml\\.load\\("
    severity: error
    desc: "Unsafe YAML loading — use yaml.safe_load() instead"

  - id: SA-PY-07
    type: regex_not
    target: "**/*.py"
    pattern: "execute\\(f\""
    severity: error
    desc: "SQL injection via f-string in query"

  - id: SA-PY-08
    type: regex_not
    target: "**/*.py"
    pattern: "execute\\(.*\\.format\\("
    severity: error
    desc: "SQL injection via .format() in query"

  - id: SA-PY-09
    type: regex_not
    target: "**/*.py"
    pattern: "hashlib\\.md5\\("
    severity: warning
    desc: "Weak hash algorithm MD5 — use SHA-256+ or argon2 for passwords"

  - id: SA-PY-10
    type: regex_not
    target: "**/*.py"
    pattern: "hashlib\\.sha1\\("
    severity: warning
    desc: "Weak hash algorithm SHA1 — use SHA-256+ for integrity checks"

  - id: SA-PY-11
    type: regex_not
    target: "**/*.py"
    pattern: "tempfile\\.mktemp\\("
    severity: error
    desc: "Deprecated tempfile.mktemp() has race condition — use mkstemp()"

  - id: SA-PY-12
    type: regex_not
    target: "**/*.py"
    pattern: "__import__\\("
    severity: warning
    desc: "Dynamic import via __import__() — validate module names against a whitelist"

  - id: SA-PY-13
    type: regex_not
    target: "**/*.py"
    pattern: "xml\\.etree\\.ElementTree"
    severity: warning
    desc: "Standard library XML parser — use defusedxml to prevent XXE attacks"

  - id: SA-PY-14
    type: regex_not
    target: "**/*.py"
    pattern: "Template\\s*\\(.*\\w+.*\\)"
    severity: warning
    desc: "Jinja2/Mako Template with variable input — risk of SSTI"

  - id: SA-PY-15
    type: regex_not
    target: "**/*.py"
    pattern: "os\\.popen\\("
    severity: error
    desc: "Command injection via os.popen()"

  - id: SA-PY-16
    type: regex_not
    target: "**/*.py"
    pattern: "compile\\(.*,.*,"
    severity: warning
    desc: "compile() with dynamic input — risk of code injection"

  - id: SA-PY-17
    type: regex_not
    target: "**/*.py"
    pattern: "shelve\\.open\\("
    severity: warning
    desc: "shelve uses pickle internally — insecure deserialization risk"

  - id: SA-PY-18
    type: regex_not
    target: "**/*.py"
    pattern: "marshal\\.loads\\("
    severity: warning
    desc: "Insecure deserialization via marshal"

  # === RUBY SECURITY CHECKS (Phase 4) ===
  - id: SA-RB-01
    type: regex_not
    target: "**/*.rb"
    pattern: "\\beval\\s*\\("
    severity: error
    desc: "eval() usage — potential code injection"

  - id: SA-RB-02
    type: regex_not
    target: "**/*.rb"
    pattern: "\\.send\\s*\\("
    severity: warning
    desc: "send() with dynamic method — potential method injection"

  - id: SA-RB-03
    type: regex_not
    target: "**/*.rb"
    pattern: "\\bsystem\\s*\\("
    severity: warning
    desc: "system() call — verify no user input in command string"

  - id: SA-RB-04
    type: regex_not
    target: "**/*.rb"
    pattern: "Marshal\\.load\\s*\\("
    severity: error
    desc: "Marshal.load — insecure deserialization of untrusted data"

  - id: SA-RB-05
    type: regex_not
    target: "**/*.rb"
    pattern: "YAML\\.load\\s*\\("
    severity: error
    desc: "YAML.load without safe_load — insecure deserialization risk"

  - id: SA-RB-06
    type: regex_not
    target: "**/*.rb"
    pattern: "ERB\\.new\\s*\\("
    severity: warning
    desc: "ERB.new — audit for template injection with user input"

  - id: SA-RB-07
    type: regex_not
    target: "**/*.rb"
    pattern: "find_by_sql\\s*\\("
    severity: error
    desc: "find_by_sql — risk of SQL injection with string interpolation"

  - id: SA-RB-08
    type: regex_not
    target: "**/*.rb"
    pattern: "\\.html_safe\\b"
    severity: warning
    desc: "html_safe bypasses Rails XSS escaping — audit for user input"

  - id: SA-RB-09
    type: regex_not
    target: "**/*.rb"
    pattern: "\\braw\\s*\\("
    severity: warning
    desc: "raw() bypasses Rails XSS escaping — audit for user input"

  - id: SA-RB-10
    type: regex_not
    target: "**/*.rb"
    pattern: "\\bKernel\\.open\\s*\\("
    severity: error
    desc: "Kernel.open — pipe injection and SSRF risk with user input"

  - id: SA-RB-11
    type: regex_not
    target: "**/*.rb"
    pattern: "\\.permit!\\b"
    severity: error
    desc: "permit! allows all params — mass assignment vulnerability"

  - id: SA-RB-12
    type: regex_not
    target: "**/*.rb"
    pattern: "Digest::MD5"
    severity: warning
    desc: "MD5 is cryptographically broken — use SHA-256 or bcrypt"

  - id: SA-RB-13
    type: regex_not
    target: "**/*.rb"
    pattern: "Digest::SHA1"
    severity: warning
    desc: "SHA-1 is cryptographically weak — use SHA-256 or stronger"

  - id: SA-RB-14
    type: regex_not
    target: "**/*.rb"
    pattern: "\\bexec\\s*\\("
    severity: warning
    desc: "exec() call — verify no user input in command string"

  - id: SA-RB-15
    type: regex_not
    target: "**/*.rb"
    pattern: "\\bopen\\s*\\(\\s*[\"']\\|"
    severity: error
    desc: "open() with pipe prefix — direct command execution"

  # === JAVA SECURITY CHECKS (Phase 2) ===
  - id: SA-JAVA-01
    type: regex_not
    target: "**/*.java"
    pattern: "new\\s+ObjectInputStream\\s*\\("
    severity: error
    desc: "ObjectInputStream deserialization — risk of RCE via gadget chains"

  - id: SA-JAVA-02
    type: regex_not
    target: "**/*.java"
    pattern: "new\\s+XMLDecoder\\s*\\("
    severity: error
    desc: "XMLDecoder deserialization — enables arbitrary code execution"

  - id: SA-JAVA-03
    type: regex_not
    target: "**/*.java"
    pattern: "InitialContext\\s*\\(\\s*\\)[\\s\\S]{0,100}\\.lookup\\s*\\("
    severity: error
    desc: "JNDI lookup — risk of remote class loading (Log4Shell pattern)"

  - id: SA-JAVA-04
    type: regex_not
    target: "**/*.java"
    pattern: "Class\\.forName\\s*\\("
    severity: warning
    desc: "Reflection via Class.forName — risk of arbitrary class instantiation"

  - id: SA-JAVA-05
    type: regex_not
    target: "**/*.java"
    pattern: "(createStatement|executeQuery|executeUpdate)\\s*\\([^)]*\\+"
    severity: error
    desc: "JDBC string concatenation — SQL injection risk, use PreparedStatement"

  - id: SA-JAVA-06
    type: regex_not
    target: "**/*.java"
    pattern: "DocumentBuilderFactory\\.newInstance\\s*\\("
    severity: warning
    desc: "XML parsing without explicit XXE protection — disable external entities"

  - id: SA-JAVA-07
    type: regex_not
    target: "**/*.java"
    pattern: "Runtime\\.getRuntime\\s*\\(\\s*\\)\\.exec\\s*\\("
    severity: error
    desc: "Runtime.exec — command injection risk, use ProcessBuilder with array args"

  - id: SA-JAVA-08
    type: regex_not
    target: "**/*.java"
    pattern: "getInstance\\s*\\(\\s*\"(MD5|SHA-1)\"\\s*\\)"
    severity: warning
    desc: "Weak hash algorithm (MD5/SHA-1) — use SHA-256 or stronger"

  - id: SA-JAVA-09
    type: regex_not
    target: "**/*.java"
    pattern: "new\\s+Random\\s*\\("
    severity: warning
    desc: "java.util.Random is predictable — use SecureRandom for security operations"

  - id: SA-JAVA-10
    type: regex_not
    target: "**/*.java"
    pattern: "Cipher\\.getInstance\\s*\\(\\s*\"(DES|.*ECB)"
    severity: error
    desc: "Weak cipher (DES/ECB) — use AES-GCM for authenticated encryption"

  - id: SA-JAVA-11
    type: regex_not
    target: "**/*.java"
    pattern: "(openConnection|openStream)\\s*\\(\\s*\\)"
    severity: warning
    desc: "URL.openConnection/openStream — SSRF risk, validate and restrict URLs"

  - id: SA-JAVA-12
    type: regex_not
    target: "**/*.java"
    pattern: "new\\s+File\\s*\\(\\s*[^)]*\\+\\s*(request|req|param|input|args)"
    severity: warning
    desc: "File path from user input — path traversal risk, validate canonical path"

  # === C# SECURITY CHECKS (Phase 2) ===
  - id: SA-CS-01
    type: regex_not
    target: "**/*.cs"
    pattern: "new\\s+BinaryFormatter\\s*\\("
    severity: error
    desc: "BinaryFormatter deserialization — RCE risk, use System.Text.Json"

  - id: SA-CS-02
    type: regex_not
    target: "**/*.cs"
    pattern: "new\\s+NetDataContractSerializer\\s*\\("
    severity: error
    desc: "NetDataContractSerializer — insecure deserialization with type embedding"

  - id: SA-CS-03
    type: regex_not
    target: "**/*.cs"
    pattern: "FromSqlRaw\\s*\\(\\s*\\$"
    severity: error
    desc: "FromSqlRaw with interpolation — SQL injection, use FromSqlInterpolated"

  - id: SA-CS-04
    type: regex_not
    target: "**/*.cs"
    pattern: "new\\s+XmlDocument\\s*\\("
    severity: warning
    desc: "XmlDocument — set XmlResolver=null and disable DTD processing"

  - id: SA-CS-05
    type: regex_not
    target: "**/*.cs"
    pattern: "Process\\.Start\\s*\\("
    severity: warning
    desc: "Process.Start — command injection risk, set UseShellExecute=false"

  - id: SA-CS-06
    type: regex_not
    target: "**/*.cs"
    pattern: "MD5\\.Create\\s*\\("
    severity: warning
    desc: "MD5 is cryptographically broken — use SHA256 or stronger"

  - id: SA-CS-07
    type: regex_not
    target: "**/*.cs"
    pattern: "SHA1\\.Create\\s*\\("
    severity: warning
    desc: "SHA-1 is cryptographically weak — use SHA256 or stronger"

  - id: SA-CS-08
    type: regex_not
    target: "**/*.cs"
    pattern: "new\\s+Random\\s*\\("
    severity: warning
    desc: "System.Random is predictable — use RandomNumberGenerator for security"

  - id: SA-CS-09
    type: regex_not
    target: "**/*.cs"
    pattern: "DESCryptoServiceProvider"
    severity: error
    desc: "DES is broken (56-bit key) — use AES-GCM"

  - id: SA-CS-10
    type: regex_not
    target: "**/*.cs"
    pattern: "AllowAnyOrigin\\s*\\("
    severity: error
    desc: "CORS AllowAnyOrigin — use explicit origin allowlist"

  - id: SA-CS-11
    type: regex_not
    target: "**/*.cs"
    pattern: "DirectorySearcher\\s*\\(\\s*\\$"
    severity: error
    desc: "LDAP injection via DirectorySearcher with interpolation"

  - id: SA-CS-12
    type: regex_not
    target: "**/*.cs"
    pattern: "UseShellExecute\\s*=\\s*true"
    severity: warning
    desc: "UseShellExecute=true passes args through shell — set to false"

  # === GO SECURITY CHECKS ===
  - id: SA-GO-01
    type: regex_not
    target: "**/*.go"
    pattern: "unsafe\\.(Pointer|Sizeof|Slice|String|Offsetof|Alignof)"
    severity: warning
    desc: "unsafe package usage — bypasses Go memory safety, audit required"

  - id: SA-GO-02
    type: regex_not
    target: "**/*.go"
    pattern: "\"text/template\""
    severity: error
    desc: "text/template does not escape HTML — use html/template for web output"

  - id: SA-GO-03
    type: regex_not
    target: "**/*.go"
    pattern: "(Sprintf|\"\\s*\\+).*(SELECT|INSERT|UPDATE|DELETE|select|insert|update|delete)"
    severity: error
    desc: "SQL string concatenation — use parameterized queries"

  - id: SA-GO-04
    type: regex_not
    target: "**/*.go"
    pattern: "exec\\.Command\\s*\\(\\s*\"(sh|bash|cmd|powershell)\""
    severity: error
    desc: "Shell invocation via exec.Command — risk of command injection"

  - id: SA-GO-05
    type: regex_not
    target: "**/*.go"
    pattern: "filepath\\.Join\\s*\\(.*\\b(r\\.|req\\.|request\\.|URL)"
    severity: warning
    desc: "filepath.Join with user input — validate resolved path stays within base"

  - id: SA-GO-06
    type: regex_not
    target: "**/*.go"
    pattern: "InsecureSkipVerify\\s*:\\s*true"
    severity: error
    desc: "TLS certificate verification disabled — enables MITM attacks"

  - id: SA-GO-07
    type: regex_not
    target: "**/*.go"
    pattern: "\"math/rand\""
    severity: warning
    desc: "math/rand is not cryptographically secure — use crypto/rand for secrets"

  - id: SA-GO-08
    type: regex_not
    target: "**/*.go"
    pattern: "http\\.(Get|Post|Head)\\s*\\(.*\\b(r\\.|req\\.|request\\.|URL)"
    severity: error
    desc: "HTTP request with user-controlled URL — SSRF risk"

  - id: SA-GO-09
    type: regex_not
    target: "**/*.go"
    pattern: "log\\.(Print|Fatal|Panic)(f|ln)?\\s*\\("
    severity: warning
    desc: "Unstructured logging — use log/slog for security event logging"

  - id: SA-GO-10
    type: regex_not
    target: "**/*.go"
    pattern: "Header\\(\\)\\.Set\\s*\\(.*\\b(r\\.|req\\.)"
    severity: warning
    desc: "HTTP header set with request data — risk of header injection"

  - id: SA-GO-11
    type: regex_not
    target: "**/*.go"
    pattern: "VersionTLS1[01]\\b"
    severity: error
    desc: "TLS 1.0/1.1 is insecure — use TLS 1.2 or higher"

  - id: SA-GO-12
    type: regex_not
    target: "**/*.go"
    pattern: "(password|secret|apiKey|token)\\s*[:=]\\s*\"[^\"]{8,}\""
    severity: error
    desc: "Potential hardcoded credential — use environment variables or secret manager"

  # === RUST SECURITY CHECKS ===
  - id: SA-RS-01
    type: regex_not
    target: "**/*.rs"
    pattern: "unsafe\\s*\\{|unsafe\\s+fn\\s|unsafe\\s+impl\\s"
    severity: warning
    desc: "unsafe block/fn/impl — bypasses Rust safety guarantees, audit required"

  - id: SA-RS-02
    type: regex_not
    target: "**/*.rs"
    pattern: "extern\\s+\"C\"\\s*\\{|#\\[no_mangle\\]"
    severity: warning
    desc: "FFI boundary — audit for null pointers, lifetime issues, and error handling"

  - id: SA-RS-03
    type: regex_not
    target: "**/*.rs"
    pattern: "panic!\\s*\\(|todo!\\s*\\(|unimplemented!\\s*\\("
    severity: warning
    desc: "panic!/todo!/unimplemented! in code — can cause DoS via unwinding"

  - id: SA-RS-04
    type: regex_not
    target: "**/*.rs"
    pattern: "\\.unwrap\\(\\)|\\.expect\\(\\s*\""
    severity: warning
    desc: ".unwrap()/.expect() can panic — use ? or match in production paths"

  - id: SA-RS-05
    type: regex_not
    target: "**/*.rs"
    pattern: "as\\s+\\*const\\s|as\\s+\\*mut\\s"
    severity: warning
    desc: "Raw pointer cast — potential use-after-free or null deref in unsafe code"

  - id: SA-RS-06
    type: regex_not
    target: "**/*.rs"
    pattern: "sql_query\\s*\\(\\s*format!|query.*&format!"
    severity: error
    desc: "SQL query with format! string — use parameterized queries"

  - id: SA-RS-07
    type: regex_not
    target: "**/*.rs"
    pattern: "Command::new\\s*\\(\\s*\"(sh|bash|cmd|powershell)\""
    severity: error
    desc: "Shell invocation via Command::new — risk of command injection"

  - id: SA-RS-08
    type: regex_not
    target: "**/*.rs"
    pattern: "\\.join\\s*\\(.*\\b(req|input|param|query|user)"
    severity: warning
    desc: "Path join with user input — validate resolved path stays within base"

  - id: SA-RS-09
    type: regex_not
    target: "**/*.rs"
    pattern: "serde_json::from_(str|slice|reader)\\s*\\("
    severity: warning
    desc: "Deserialization of potentially untrusted data — enforce size limits"

  - id: SA-RS-10
    type: regex_not
    target: "**/*.rs"
    pattern: "==\\s*(token|secret|hmac|hash|key|password|mac|signature)"
    severity: error
    desc: "Non-constant-time comparison of secret — use constant_time_eq"

  - id: SA-RS-11
    type: regex_not
    target: "**/*.rs"
    pattern: "mem::forget\\s*\\(|ManuallyDrop::new\\s*\\("
    severity: warning
    desc: "mem::forget/ManuallyDrop prevents cleanup — sensitive data may persist"

  - id: SA-RS-12
    type: regex_not
    target: "**/*.rs"
    pattern: "(password|secret|api_key|token)\\s*[:=]\\s*\"[^\"]{8,}\""
    severity: error
    desc: "Potential hardcoded credential — use environment variables or secret manager"

  # === VUE.JS SECURITY CHECKS ===
  - id: SA-VUE-01
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "v-html\\s*="
    severity: warning
    desc: "v-html directive — potential XSS if used with user input"

  - id: SA-VUE-02
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "Vue\\.compile\\s*\\("
    severity: error
    desc: "Vue.compile() with dynamic input — potential template injection"

  - id: SA-VUE-03
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: ":(href|src)\\s*=\\s*\"[^\"]*[a-zA-Z]"
    severity: warning
    desc: "v-bind:href/src with variable — validate URL protocol to prevent javascript: XSS"

  - id: SA-VUE-04
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "beforeEnter\\s*:|beforeEach\\s*\\("
    severity: warning
    desc: "Client-side route guard — ensure server-side authorization exists"

  - id: SA-VUE-05
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "(computed|watch|methods)\\s*:\\s*\\{[^}]*eval\\s*\\("
    severity: error
    desc: "eval() in Vue reactivity hook — potential code injection"

  - id: SA-VUE-06
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "(defineStore|new\\s+Vuex\\.Store)\\s*\\([^)]*\\{[\\s\\S]*?(token|secret|password|apiKey|api_key|ssn|creditCard)"
    severity: error
    desc: "Sensitive data in Vuex/Pinia store — exposed via DevTools"

  - id: SA-VUE-07
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "(asyncData|serverPrefetch|fetch)\\s*\\([^)]*\\)\\s*\\{[\\s\\S]*?(secret|internal|private|apiKey|connectionString)"
    severity: error
    desc: "SSR hydration may leak server-only data to client HTML"

  - id: SA-VUE-08
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "Vue\\.mixin\\s*\\(|app\\.mixin\\s*\\("
    severity: warning
    desc: "Global mixin — applies to every component, audit for side effects"

  # === ANGULAR SECURITY CHECKS ===
  - id: SA-ANG-01
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "bypassSecurityTrust(Html|Script|Url|ResourceUrl)\\s*\\("
    severity: error
    desc: "bypassSecurityTrust* disables Angular sanitization — audit for user input"

  - id: SA-ANG-02
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "compiler\\.compileModuleAndAllComponentsAsync|Component\\(\\s*\\{\\s*template\\s*:"
    severity: error
    desc: "Dynamic template compilation — potential template injection"

  - id: SA-ANG-03
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "@Pipe[\\s\\S]*?bypassSecurityTrust"
    severity: error
    desc: "Pipe with bypassSecurityTrust — reusable sanitization bypass"

  - id: SA-ANG-04
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "\\[innerHTML\\]\\s*="
    severity: warning
    desc: "innerHTML binding — verify input is sanitized before binding"

  - id: SA-ANG-05
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "canActivate|CanActivate|canLoad|CanLoad"
    severity: warning
    desc: "Client-side route guard — ensure server-side authorization exists"

  - id: SA-ANG-06
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "HttpInterceptor[\\s\\S]*?intercept\\s*\\("
    severity: warning
    desc: "HTTP interceptor — verify tokens are only sent to trusted origins"

  - id: SA-ANG-07
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "eval\\s*\\([^)]*\\)|new\\s+Function\\s*\\("
    severity: error
    desc: "eval/new Function in Angular code — potential code injection"

  - id: SA-ANG-08
    type: regex_not
    target: "**/*.{ts,html}"
    pattern: "ngZone\\.run\\s*\\([\\s\\S]*?(password|token|secret|creditCard|ssn|apiKey)"
    severity: warning
    desc: "Sensitive data in Zone.js context — may persist in memory"

  # === REACT SECURITY CHECKS ===
  - id: SA-REACT-01
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "dangerouslySetInnerHTML"
    severity: warning
    desc: "dangerouslySetInnerHTML usage — potential XSS"

  - id: SA-REACT-02
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "\\{\\s*\\.\\.\\.(?:user|props|data|input|params|query)"
    severity: warning
    desc: "Spreading user-controlled object as JSX props — may inject dangerouslySetInnerHTML"

  - id: SA-REACT-03
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "href\\s*=\\s*\\{(?!['\"](https?:|mailto:|/)[^}])"
    severity: warning
    desc: "Dynamic href from variable — potential javascript: protocol XSS"

  - id: SA-REACT-04
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "'use client'[\\s\\S]*?\\b(password|secret|token|ssn|creditCard|hash)\\b"
    severity: warning
    desc: "Client component may receive sensitive data as props — data visible in browser"

  - id: SA-REACT-05
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "\\beval\\s*\\(|new\\s+Function\\s*\\("
    severity: error
    desc: "eval() or Function constructor — code injection risk"

  - id: SA-REACT-06
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "useState\\s*\\(\\s*\\{[^}]*(token|secret|password|refreshToken|cvv|ssn|creditCard)"
    severity: warning
    desc: "Sensitive data in React state — visible in DevTools"

  - id: SA-REACT-07
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "useEffect\\s*\\(\\s*\\(\\)\\s*=>\\s*\\{[^}]*fetch\\s*\\([^)]*\\)\\.then"
    severity: warning
    desc: "useEffect fetch without visible auth — verify credentials are included"

  - id: SA-REACT-08
    type: regex_not
    target: "**/*.{jsx,tsx}"
    pattern: "key\\s*=\\s*\\{[^}]*(index|idx|i)\\s*\\}"
    severity: info
    desc: "Array index as React key — may cause state leaks between list items"

  # === NEXT.JS SECURITY CHECKS ===
  - id: SA-NEXT-01
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx}"
    pattern: "'use server'[\\s\\S]*?export\\s+async\\s+function\\s+\\w+"
    severity: warning
    desc: "Server Action — verify auth/authorization check inside function body"

  - id: SA-NEXT-02
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "export\\s+async\\s+function\\s+(GET|POST|PUT|DELETE|PATCH)\\s*\\("
    severity: warning
    desc: "Next.js API route handler — verify authentication is enforced"

  - id: SA-NEXT-03
    type: regex_not
    target: "**/*.env*"
    pattern: "NEXT_PUBLIC_[A-Z_]*(SECRET|KEY|PASSWORD|TOKEN|CREDENTIAL|PRIVATE|DATABASE)"
    severity: error
    desc: "NEXT_PUBLIC_ env var with secret-like name — exposed to client bundle"

  - id: SA-NEXT-04
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx}"
    pattern: "(getServerSideProps|getStaticProps)[\\s\\S]*?return\\s*\\{\\s*props:"
    severity: warning
    desc: "getServerSideProps/getStaticProps return — verify no sensitive fields in props"

  - id: SA-NEXT-05
    type: regex_not
    target: "**/next.config.{js,mjs,ts}"
    pattern: "hostname:\\s*['\"]?\\*{1,2}['\"]?"
    severity: error
    desc: "Wildcard hostname in next/image config — SSRF risk via image optimization"

  - id: SA-NEXT-06
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx}"
    pattern: "Response\\.redirect\\s*\\([^)]*searchParams|redirect\\s*\\(\\s*(?:req|request)"
    severity: warning
    desc: "Redirect with user-controlled destination — potential open redirect"

  - id: SA-NEXT-07
    type: regex_not
    target: "**/*.{js,ts,jsx,tsx}"
    pattern: "JSON\\.stringify\\s*\\([^)]*(config|secret|user|session|token|key|credential)"
    severity: warning
    desc: "JSON.stringify of potentially sensitive object — may leak in RSC payload"

  - id: SA-NEXT-08
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "export\\s+async\\s+function\\s+POST\\s*\\([^)]*\\)\\s*\\{[^}]*(?:cookie|session|auth)"
    severity: warning
    desc: "POST handler with cookie/session auth — verify CSRF protection"

  # === NUXT SECURITY CHECKS ===
  - id: SA-NUXT-01
    type: regex_not
    target: "server/**/*.{js,ts}"
    pattern: "defineEventHandler\\s*\\(\\s*async\\s*\\(\\s*event\\s*\\)"
    severity: warning
    desc: "Nitro server handler — verify authentication middleware is applied"

  - id: SA-NUXT-02
    type: regex_not
    target: "**/*.{vue,js,ts}"
    pattern: "useFetch\\s*\\(\\s*['\"][^'\"]*admin|useAsyncData\\s*\\(\\s*['\"][^'\"]*secret"
    severity: warning
    desc: "useFetch/useAsyncData fetching sensitive endpoint — data exposed in hydration payload"

  - id: SA-NUXT-03
    type: regex_not
    target: "**/nuxt.config.{js,ts}"
    pattern: "runtimeConfig[\\s\\S]*?public\\s*:\\s*\\{[^}]*(secret|password|token|key|credential|private|database)"
    severity: error
    desc: "Secret in runtimeConfig.public — exposed to client"

  - id: SA-NUXT-04
    type: regex_not
    target: "**/*.vue"
    pattern: "v-html\\s*="
    severity: warning
    desc: "v-html directive — potential XSS, especially dangerous in SSR context"

  - id: SA-NUXT-05
    type: regex_not
    target: "server/**/*.{js,ts}"
    pattern: "exec\\s*\\(|execSync\\s*\\(|\\$queryRawUnsafe\\s*\\("
    severity: error
    desc: "Shell exec or raw SQL in Nitro handler — injection risk"

  - id: SA-NUXT-06
    type: regex_not
    target: "plugins/**/*.{js,ts}"
    pattern: "defineNuxtPlugin\\s*\\(\\s*(?:async\\s*)?\\(\\s*nuxtApp\\s*\\)\\s*=>"
    severity: info
    desc: "Nuxt plugin without enforce/dependsOn — verify execution order for security plugins"

  # === SPRING SECURITY CHECKS ===
  - id: SA-SPRING-01
    type: regex_not
    target: "**/*.java"
    pattern: "requestMatchers\\s*\\(\\s*\"\\/(api|admin)\\/\\*\\*\"\\s*\\)\\s*\\.\\s*permitAll\\s*\\(\\s*\\)"
    severity: error
    desc: "Spring Security permitAll overreach — verify scope is intentionally broad"

  - id: SA-SPRING-02
    type: regex_not
    target: "**/*.java"
    pattern: "parseExpression\\s*\\(\\s*[a-zA-Z_]\\w*\\s*\\)"
    severity: error
    desc: "SpEL expression parsed from untrusted input — injection risk"

  - id: SA-SPRING-03
    type: regex_not
    target: "**/*.java"
    pattern: "include\\s*:\\s*[\"']?\\*[\"']?|exposure\\.include\\s*=\\s*\\*"
    severity: error
    desc: "Spring Boot actuator wildcard exposure — secrets and heap dumps accessible"

  - id: SA-SPRING-04
    type: regex_not
    target: "**/*.java"
    pattern: "csrf\\s*\\(\\s*(?:csrf|c)\\s*->\\s*(?:csrf|c)\\.disable\\s*\\(\\s*\\)\\s*\\)|\\.csrf\\(\\)\\.disable\\(\\)"
    severity: warning
    desc: "CSRF protection disabled — verify endpoint is stateless (JWT/Bearer)"

  - id: SA-SPRING-05
    type: regex_not
    target: "**/*.java"
    pattern: "@PreAuthorize\\s*\\("
    severity: warning
    desc: "@PreAuthorize found — verify @EnableMethodSecurity is declared on a @Configuration class"

  - id: SA-SPRING-06
    type: regex_not
    target: "**/*.java"
    pattern: "return\\s+(?:request|param|input|query|\\w+)\\s*;"
    severity: warning
    desc: "Controller return value may be user-controlled — Thymeleaf SSTI risk"

  - id: SA-SPRING-07
    type: regex_not
    target: "**/*.java"
    pattern: "@ModelAttribute\\s+(?!.*Dto|.*Request|.*Form|.*Command)\\w+\\s+\\w+"
    severity: warning
    desc: "@ModelAttribute binds to entity directly — mass assignment risk"

  - id: SA-SPRING-08
    type: regex_not
    target: "**/*.java"
    pattern: "enableDefaultTyping\\s*\\(|activateDefaultTyping\\s*\\("
    severity: error
    desc: "Jackson default typing enabled — deserialization gadget chain risk"

  # === .NET SECURITY CHECKS ===
  - id: SA-DOTNET-01
    type: regex_not
    target: "**/*.cs"
    pattern: "UseAuthentication\\s*\\(\\s*\\)[\\s\\S]{0,200}UseRouting\\s*\\(\\s*\\)|MapControllers\\s*\\(\\s*\\)[\\s\\S]{0,200}UseAuthentication\\s*\\(\\s*\\)|UseAuthorization\\s*\\(\\s*\\)[\\s\\S]{0,200}UseAuthentication\\s*\\(\\s*\\)"
    severity: error
    desc: "ASP.NET Core middleware ordering wrong — auth must come before routing/endpoints"

  - id: SA-DOTNET-02
    type: regex_not
    target: "**/*.cs"
    pattern: "FromSqlRaw\\s*\\(\\s*\\$\"|FromSqlRaw\\s*\\(\\s*\"[^\"]*\"\\s*\\+|ExecuteSqlRaw\\s*\\(\\s*\\$\"|ExecuteSqlRaw\\s*\\(\\s*\"[^\"]*\"\\s*\\+"
    severity: error
    desc: "Entity Framework raw SQL with string interpolation/concatenation — SQL injection"

  - id: SA-DOTNET-03
    type: regex_not
    target: "**/*.cs"
    pattern: "\\[AllowAnonymous\\]\\s*(?:\\r?\\n\\s*)*(?:public\\s+class|\\[(?:ApiController|Route)\\])"
    severity: error
    desc: "[AllowAnonymous] on controller class — all actions are publicly accessible"

  - id: SA-DOTNET-04
    type: regex_not
    target: "**/*.cs"
    pattern: "Html\\.Raw\\s*\\((?!.*Sanitiz)|@\\(\\s*\\(MarkupString\\)\\s*\\w+"
    severity: error
    desc: "Razor Html.Raw or MarkupString with unsanitized input — XSS risk"

  - id: SA-DOTNET-05
    type: regex_not
    target: "**/*.cs"
    pattern: "AllowAnyOrigin\\s*\\(\\s*\\)|SetIsOriginAllowed\\s*\\(\\s*_?\\s*=>\\s*true\\s*\\)"
    severity: error
    desc: "CORS policy allows any origin — credential theft via cross-origin requests"

  - id: SA-DOTNET-06
    type: regex_not
    target: "**/*.cs"
    pattern: "IgnoreAntiforgeryTokenAttribute\\s*\\(\\s*\\)|IgnoreAntiforgeryToken\\]"
    severity: warning
    desc: "Anti-forgery token validation disabled — CSRF risk"

  - id: SA-DOTNET-07
    type: regex_not
    target: "**/*.cs"
    pattern: "DisableAutomaticKeyGeneration\\s*\\(\\s*\\)"
    severity: warning
    desc: "Data Protection automatic key generation disabled — keys will expire without rotation"

  - id: SA-DOTNET-08
    type: regex_not
    target: "**/*.cs"
    pattern: "class\\s+\\w+Hub\\s*:\\s*Hub\\b"
    severity: warning
    desc: "SignalR hub found — verify [Authorize] attribute is applied"

  # === BLAZOR SECURITY CHECKS ===
  - id: SA-BLAZOR-01
    type: regex_not
    target: "**/*.{razor,cs}"
    pattern: "Http\\.\\w+Async\\s*\\(\\s*\"[^\"]*(?:admin|secret|internal|private|manage)"
    severity: error
    desc: "Blazor WASM calling sensitive API — verify server-side [Authorize] enforcement"

  - id: SA-BLAZOR-02
    type: regex_not
    target: "**/*.{razor,cs}"
    pattern: "(?:private|protected|public)\\s+string\\s+(?:creditCard|cvv|ssn|password|secret|token|apiKey)\\s*="
    severity: warning
    desc: "Sensitive data stored in Blazor component state — exposure via circuit or prerender"

  - id: SA-BLAZOR-03
    type: regex_not
    target: "**/*.{razor,cs}"
    pattern: "InvokeVoidAsync\\s*\\(\\s*\"eval\"|InvokeAsync\\s*\\(\\s*\"eval\""
    severity: error
    desc: "JS interop calling eval — injection risk from untrusted input"

  - id: SA-BLAZOR-04
    type: regex_not
    target: "**/*.{razor,cs}"
    pattern: "\\[Authorize\\][\\s\\S]{0,200}prerender\\s*:\\s*true"
    severity: warning
    desc: "[Authorize] with prerender enabled — auth state may not be available during prerender"

  - id: SA-BLAZOR-05
    type: regex_not
    target: "**/*.{razor,cs}"
    pattern: "OnInitializedAsync[\\s\\S]{0,300}(?:Sensitive|Secret|Private|Confidential|GetCredentials|GetTokens)"
    severity: warning
    desc: "Sensitive data loaded in OnInitializedAsync — may leak via prerendering"

  # === DJANGO SECURITY ===
  - id: SA-DJANGO-01
    type: regex_not
    target: "**/*.py"
    pattern: "\\.raw\\s*\\(\\s*f[\"']|\\.raw\\s*\\(\\s*[\"'].*%s.*[\"']\\s*%|\\.extra\\s*\\(|cursor\\.execute\\s*\\(\\s*f[\"']|cursor\\.execute\\s*\\(\\s*[\"'].*%s.*[\"']\\s*%"
    severity: error
    desc: "Django ORM injection via raw(), extra(), or cursor.execute() with string interpolation"

  - id: SA-DJANGO-02
    type: regex_not
    target: "**/*.py"
    pattern: "@csrf_exempt|csrf_exempt\\s*\\(|decorators\\.csrf\\s+import\\s+csrf_exempt"
    severity: error
    desc: "CSRF protection disabled via @csrf_exempt decorator"

  - id: SA-DJANGO-03
    type: regex_not
    target: "**/*.py"
    pattern: "DEBUG\\s*=\\s*True"
    severity: error
    desc: "Django DEBUG=True — exposes tracebacks, SQL queries, and settings in production"

  - id: SA-DJANGO-04
    type: regex_not
    target: "**/*.py"
    pattern: "mark_safe\\s*\\(|\\.safestring\\s+import|safestring\\.mark_safe"
    severity: error
    desc: "XSS risk via mark_safe() — bypasses Django auto-escaping"

  - id: SA-DJANGO-05
    type: regex_not
    target: "**/*.py"
    pattern: "SECRET_KEY\\s*=\\s*[\"'][^\"']{8,}[\"']"
    severity: error
    desc: "Django SECRET_KEY hardcoded in source — enables session/token forgery if leaked"

  - id: SA-DJANGO-06
    type: regex_not
    target: "**/*.py"
    pattern: "PickleSerializer|SESSION_SERIALIZER.*[Pp]ickle"
    severity: error
    desc: "Pickle session serializer — enables RCE if SECRET_KEY is compromised"

  - id: SA-DJANGO-07
    type: regex_not
    target: "**/*.py"
    pattern: "path\\s*\\(\\s*[\"']admin/[\"']|url\\s*\\(\\s*r?\\s*[\"'].*admin/"
    severity: warning
    desc: "Django admin on default /admin/ URL — consider obscuring path and adding IP restrictions"

  - id: SA-DJANGO-08
    type: regex_not
    target: "**/*.py"
    pattern: "FileField\\s*\\(\\s*upload_to\\s*=\\s*[\"'][^\"']*[\"'](?:\\s*\\)|\\s*,\\s*\\))|request\\.FILES\\["
    severity: warning
    desc: "File upload without visible validation — verify size, type, and filename sanitization"

  # === FLASK SECURITY ===
  - id: SA-FLASK-01
    type: regex_not
    target: "**/*.py"
    pattern: "render_template_string\\s*\\("
    severity: error
    desc: "Flask render_template_string() — potential SSTI if user input reaches template"

  - id: SA-FLASK-02
    type: regex_not
    target: "**/*.py"
    pattern: "request\\.args\\s*\\[|request\\.args\\.get\\s*\\(|request\\.form\\s*\\[|request\\.form\\.get\\s*\\(|request\\.values"
    severity: warning
    desc: "Flask request parameter access — verify input is validated before use"

  - id: SA-FLASK-03
    type: regex_not
    target: "**/*.py"
    pattern: "send_file\\s*\\(\\s*f[\"']|send_file\\s*\\(\\s*.*request\\.|send_file\\s*\\(\\s*os\\.path\\.join"
    severity: error
    desc: "Flask send_file() with dynamic path — potential path traversal"

  - id: SA-FLASK-04
    type: regex_not
    target: "**/*.py"
    pattern: "app\\.run\\s*\\(.*debug\\s*=\\s*True|\\.config\\s*\\[\\s*[\"']DEBUG[\"']\\s*\\]\\s*=\\s*True|FLASK_DEBUG\\s*=\\s*1"
    severity: error
    desc: "Flask debug=True — Werkzeug debugger enables arbitrary code execution"

  - id: SA-FLASK-05
    type: regex_not
    target: "**/*.py"
    pattern: "secret_key\\s*=\\s*[\"'][^\"']{1,30}[\"']|app\\.config\\s*\\[\\s*[\"']SECRET_KEY[\"']\\s*\\]\\s*=\\s*[\"']"
    severity: error
    desc: "Flask SECRET_KEY hardcoded or weak — enables session cookie forgery"

  - id: SA-FLASK-06
    type: regex_not
    target: "**/*.py"
    pattern: "db\\.session\\.execute\\s*\\(\\s*f[\"']|db\\.session\\.execute\\s*\\(\\s*[\"'].*%s.*[\"']\\s*%|db\\.engine\\.execute\\s*\\(\\s*f[\"']|\\.execute\\s*\\(\\s*f[\"']SELECT|\\.execute\\s*\\(\\s*f[\"']INSERT|\\.execute\\s*\\(\\s*f[\"']UPDATE|\\.execute\\s*\\(\\s*f[\"']DELETE"
    severity: error
    desc: "SQLAlchemy raw query with string interpolation — SQL injection risk"

  # === FASTAPI SECURITY ===
  - id: SA-FASTAPI-01
    type: regex_not
    target: "**/*.py"
    pattern: "@app\\.(get|post|put|patch|delete)\\("
    severity: warning
    desc: "FastAPI endpoint without Depends() — verify authentication is not missing"

  - id: SA-FASTAPI-02
    type: regex_not
    target: "**/*.py"
    pattern: "def\\s+\\w+\\s*\\([^)]*:\\s*dict\\s*[,\\)]|:\\s*Any\\s*[,\\)=]|extra\\s*=\\s*[\"']allow[\"']"
    severity: warning
    desc: "Pydantic validation bypass via dict/Any type or extra='allow'"

  - id: SA-FASTAPI-03
    type: regex_not
    target: "**/*.py"
    pattern: "allow_origins\\s*=\\s*\\[\\s*[\"']\\*[\"']\\s*\\]|CORSMiddleware.*allow_origins.*\\*"
    severity: error
    desc: "FastAPI CORS wildcard origin — allows any domain to make cross-origin requests"

  - id: SA-FASTAPI-04
    type: regex_not
    target: "**/*.py"
    pattern: "response\\.headers\\s*\\[.*\\]\\s*=\\s*f[\"']|response\\.headers\\s*\\[.*\\]\\s*=.*request\\.|.headers\\s*\\[\\s*[\"']Set-Cookie[\"']\\s*\\]\\s*="
    severity: warning
    desc: "Response header set from user input — potential header injection"

  - id: SA-FASTAPI-05
    type: regex_not
    target: "**/*.py"
    pattern: "UploadFile.*filename|file\\.filename|shutil\\.copyfileobj\\s*\\(\\s*file"
    severity: warning
    desc: "FastAPI file upload — verify size limit, type validation, and filename sanitization"

  - id: SA-FASTAPI-06
    type: regex_not
    target: "**/*.py"
    pattern: "algorithms\\s*=\\s*\\[.*none.*\\]|jwt\\.decode\\s*\\(\\s*token\\s*,\\s*[^,]+\\s*\\)\\s*$|ACCESS_TOKEN_EXPIRE.*(?:525600|86400|43200)"
    severity: error
    desc: "OAuth2/JWT implementation issue — algorithm confusion, missing validation, or excessive expiry"

  # === GIN (GO) SECURITY CHECKS ===
  - id: SA-GIN-01
    type: regex_not
    target: "**/*.go"
    pattern: "\\.Use\\(auth[A-Za-z]*\\("
    severity: error
    desc: "Auth middleware may be registered after routes — verify ordering"

  - id: SA-GIN-02
    type: regex_not
    target: "**/*.go"
    pattern: "c\\.(Bind|ShouldBind|ShouldBindJSON|BindJSON|ShouldBindQuery)\\s*\\("
    severity: warning
    desc: "Gin binding function — verify struct does not contain sensitive fields (mass assignment)"

  - id: SA-GIN-03
    type: regex_not
    target: "**/*.go"
    pattern: "template\\.HTML\\s*\\(|c\\.Data\\s*\\([^)]*\"text/html|c\\.Writer\\.WriteString\\s*\\("
    severity: error
    desc: "Raw HTML output bypassing template auto-escaping — potential XSS"

  - id: SA-GIN-04
    type: regex_not
    target: "**/*.go"
    pattern: "AllowAllOrigins\\s*:\\s*true|AllowOrigins\\s*:\\s*\\[\\s*\"\\*\"\\s*\\]|AllowOriginFunc\\s*:.*return\\s+true"
    severity: error
    desc: "CORS misconfiguration — wildcard or permissive origin policy"

  - id: SA-GIN-05
    type: regex_not
    target: "**/*.go"
    pattern: "c\\.(File|FileAttachment)\\s*\\([^)]*c\\.(Param|Query|PostForm)\\s*\\("
    severity: error
    desc: "User-controlled path in c.File/c.FileAttachment — path traversal risk"

  - id: SA-GIN-06
    type: regex_not
    target: "**/*.go"
    pattern: "gin\\.New\\s*\\(\\s*\\)"
    severity: warning
    desc: "gin.New() without default middleware — verify Recovery() is registered first"

  # === RAILS SECURITY CHECKS ===
  - id: SA-RAILS-01
    type: regex_not
    target: "**/*.rb"
    pattern: "\\.permit!|params\\[:[a-z_]+\\]\\.permit\\([^)]*(?:role|admin|superuser|permission)"
    severity: error
    desc: "Mass assignment — permit! or permitting sensitive fields"

  - id: SA-RAILS-02
    type: regex_not
    target: "**/*.rb"
    pattern: "\\.html_safe|raw\\s*\\(|<%=="
    severity: error
    desc: "html_safe/raw/<%== bypasses Rails auto-escaping — XSS risk"

  - id: SA-RAILS-03
    type: regex_not
    target: "**/*.rb"
    pattern: "find_by_sql\\s*\\(.*#\\{|\\.where\\s*\\(.*#\\{|\\.order\\s*\\(\\s*params"
    severity: error
    desc: "String interpolation in SQL query — SQL injection risk"

  - id: SA-RAILS-04
    type: regex_not
    target: "**/*.rb"
    pattern: "skip_before_action\\s*:verify_authenticity_token|protect_from_forgery\\s+with:\\s*:null_session"
    severity: error
    desc: "CSRF protection disabled or misconfigured"

  - id: SA-RAILS-05
    type: regex_not
    target: "**/*.rb"
    pattern: "send_file\\s*.*params\\[|send_data\\s*.*filename:\\s*params\\["
    severity: error
    desc: "User-controlled path in send_file/send_data — path traversal risk"

  - id: SA-RAILS-06
    type: regex_not
    target: "**/*.rb"
    pattern: "render\\s+inline:\\s*.*params\\[|render\\s+inline:\\s*.*#\\{"
    severity: error
    desc: "User input in render inline: — server-side template injection"

  - id: SA-RAILS-07
    type: regex_not
    target: "**/*.rb"
    pattern: "has_one_attached\\s+:\\w+"
    severity: warning
    desc: "Active Storage attachment — verify content_type and size validation"

  - id: SA-RAILS-08
    type: regex_not
    target: "**/*.rb"
    pattern: "class\\s+\\w+Channel\\s*<\\s*ApplicationCable::Channel"
    severity: warning
    desc: "Action Cable channel — verify authentication in Connection and authorization in subscribed"

  # === EXPRESS SECURITY CHECKS ===
  - id: SA-EXPRESS-01
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "app\\.(get|post|put|delete|use)\\s*\\([^)]*\\)[\\s\\S]*?app\\.use\\s*\\(\\s*helmet\\s*\\("
    severity: error
    desc: "Routes defined before helmet middleware — missing security headers"

  - id: SA-EXPRESS-02
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "execSync\\s*\\(.*req\\.(params|query|body)|exec\\s*\\(.*req\\.(params|query|body)"
    severity: error
    desc: "User input in shell command — command injection risk"

  - id: SA-EXPRESS-03
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "res\\.sendFile\\s*\\(\\s*(?:req\\.(params|query|body)|path\\.join\\s*\\([^)]*req\\.(params|query|body))"
    severity: error
    desc: "User-controlled path in res.sendFile — path traversal risk"

  - id: SA-EXPRESS-04
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "session\\s*\\(\\s*\\{[^}]*secret\\s*:\\s*['\"][^'\"]{0,20}['\"]|cookie\\s*:\\s*\\{[^}]*httpOnly\\s*:\\s*false|cookie\\s*:\\s*\\{[^}]*secure\\s*:\\s*false"
    severity: error
    desc: "Insecure session configuration — weak secret, missing httpOnly, or missing secure flag"

  - id: SA-EXPRESS-05
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "app\\.(post|put)\\s*\\(\\s*['\"\\/][^'\"]*(?:login|auth|token|password|register)[^'\"]*['\"]"
    severity: warning
    desc: "Auth endpoint — verify rate limiting is applied"

  - id: SA-EXPRESS-06
    type: regex_not
    target: "**/*.{js,ts}"
    pattern: "findByIdAndUpdate\\s*\\([^,]+,\\s*req\\.body\\s*\\)|\\.create\\s*\\(\\s*req\\.body\\s*\\)"
    severity: warning
    desc: "Passing req.body directly to database operation — mass assignment risk"

  # === NESTJS SECURITY CHECKS ===
  - id: SA-NEST-01
    type: regex_not
    target: "**/*.ts"
    pattern: "@UseGuards\\s*\\(\\s*RolesGuard\\s*,\\s*AuthGuard\\s*\\)"
    severity: error
    desc: "RolesGuard before AuthGuard — authorization checked before authentication"

  - id: SA-NEST-02
    type: regex_not
    target: "**/*.ts"
    pattern: "new\\s+ValidationPipe\\s*\\(\\s*\\{[^}]*whitelist\\s*:\\s*false"
    severity: error
    desc: "ValidationPipe with whitelist:false — extra properties not stripped (mass assignment)"

  - id: SA-NEST-03
    type: regex_not
    target: "**/*.ts"
    pattern: "@Column\\s*\\(\\s*\\)\\s*\\n\\s*password\\s*:|@Column\\s*\\(\\s*\\)\\s*\\n\\s*(?:secret|token|hash|internal)"
    severity: warning
    desc: "Sensitive entity column without @Exclude — may be exposed in API responses"

  - id: SA-NEST-04
    type: regex_not
    target: "**/*.ts"
    pattern: "@Param\\s*\\(\\s*['\"][^'\"]+['\"]\\s*\\)\\s+\\w+\\s*:\\s*string"
    severity: warning
    desc: "Route parameter without ParseIntPipe/ParseUUIDPipe — type confusion risk"

  - id: SA-NEST-05
    type: regex_not
    target: "**/*.ts"
    pattern: "@Public\\s*\\(\\s*\\)\\s*\\n\\s*@(Delete|Put|Patch)\\s*\\(|@Public\\s*\\(\\s*\\)\\s*\\n\\s*@Controller"
    severity: error
    desc: "@Public on state-changing endpoint or entire controller — auth bypass"

  - id: SA-NEST-06
    type: regex_not
    target: "**/*.ts"
    pattern: "@WebSocketGateway\\s*\\("
    severity: warning
    desc: "WebSocket gateway — verify handleConnection authentication and message-level guards"

  # === AWS SECURITY CHECKS ===
  - id: SA-AWS-01
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "\"Action\"\\s*:\\s*\"\\*\"|\"Action\"\\s*:\\s*\\[\\s*\"\\*\"\\s*\\]"
    severity: error
    desc: "IAM policy with wildcard Action — grants unrestricted permissions"

  - id: SA-AWS-02
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "\"Effect\"\\s*:\\s*\"Allow\"[^}]*\"Action\"\\s*:\\s*\"sts:AssumeRole\"(?![^}]*\"Condition\")"
    severity: warning
    desc: "AssumeRole without conditions — missing MFA, IP, or external ID restriction"

  - id: SA-AWS-03
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "\"Principal\"\\s*:\\s*\\{\\s*\"AWS\"\\s*:\\s*\"\\*\"\\s*\\}|\"Principal\"\\s*:\\s*\"\\*\""
    severity: error
    desc: "Overly permissive trust policy — any principal can assume role"

  - id: SA-AWS-04
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "\"Action\"\\s*:\\s*\"iam:PassRole\"[^}]*\"Resource\"\\s*:\\s*\"\\*\""
    severity: error
    desc: "iam:PassRole with wildcard resource — privilege escalation risk"

  - id: SA-AWS-05
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "acl\\s*=\\s*\"public-read\"|acl\\s*=\\s*\"public-read-write\""
    severity: error
    desc: "S3 bucket with public ACL — data exposure risk"

  - id: SA-AWS-06
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "block_public_acls\\s*=\\s*false|block_public_policy\\s*=\\s*false|restrict_public_buckets\\s*=\\s*false"
    severity: error
    desc: "S3 public access block disabled — bucket may become publicly accessible"

  - id: SA-AWS-07
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "environment\\s*\\{[^}]*variables\\s*=\\s*\\{[^}]*(PASSWORD|SECRET|API_KEY|TOKEN|PRIVATE_KEY)\\s*=\\s*\"[^\"]+\""
    severity: error
    desc: "Lambda environment variable contains hardcoded secret"

  - id: SA-AWS-08
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "policy_arn\\s*=\\s*\"arn:aws:iam::aws:policy/AdministratorAccess\"|policy_arn\\s*=\\s*\"arn:aws:iam::aws:policy/PowerUserAccess\""
    severity: error
    desc: "Lambda or role with AdministratorAccess/PowerUserAccess — overly permissive"

  - id: SA-AWS-09
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "cidr_blocks\\s*=\\s*\\[\\s*\"0\\.0\\.0\\.0/0\"\\s*\\]|CidrIp:\\s*[\"']?0\\.0\\.0\\.0/0"
    severity: error
    desc: "Security group ingress open to 0.0.0.0/0 — unrestricted internet access"

  - id: SA-AWS-10
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "enable_key_rotation\\s*=\\s*false"
    severity: warning
    desc: "KMS key rotation disabled — keys should be rotated automatically"

  - id: SA-AWS-11
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "is_multi_region_trail\\s*=\\s*false|enable_log_file_validation\\s*=\\s*false"
    severity: error
    desc: "CloudTrail not multi-region or missing log validation"

  - id: SA-AWS-12
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "password\\s*=\\s*\"[^\"]+\"|master_password\\s*=\\s*\"[^\"]+\""
    severity: error
    desc: "Hardcoded password in Terraform/CloudFormation — use Secrets Manager"

  # === GCP SECURITY CHECKS ===
  - id: SA-GCP-01
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "role\\s*=\\s*\"roles/(owner|editor)\"|\"roles/(owner|editor)\""
    severity: error
    desc: "GCP primitive role (Owner/Editor) — use granular predefined roles"

  - id: SA-GCP-02
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "resource\\s+\"google_service_account_key\"|google_service_account_key\\s*\\{"
    severity: error
    desc: "Service account key file — use Workload Identity Federation instead"

  - id: SA-GCP-03
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "\"allUsers\"|\"allAuthenticatedUsers\"|member\\s*=\\s*\"allUsers\"|member\\s*=\\s*\"allAuthenticatedUsers\""
    severity: error
    desc: "allUsers/allAuthenticatedUsers binding — public access to GCP resource"

  - id: SA-GCP-04
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "google_storage_bucket_iam[^}]*(allUsers|allAuthenticatedUsers)|predefinedAcl:\\s*public"
    severity: error
    desc: "Public Cloud Storage bucket — data exposure risk"

  - id: SA-GCP-05
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "uniform_bucket_level_access\\s*=\\s*false"
    severity: warning
    desc: "Uniform bucket-level access disabled — inconsistent ACLs possible"

  - id: SA-GCP-06
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "environment_variables\\s*=\\s*\\{[^}]*(PASSWORD|SECRET|API_KEY|TOKEN|PRIVATE_KEY)\\s*=\\s*\"[^\"]+\""
    severity: error
    desc: "Cloud Functions environment variable contains hardcoded secret"

  - id: SA-GCP-07
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "cloudfunctions\\.invoker[^}]*allUsers|allUsers[^}]*cloudfunctions\\.invoker"
    severity: error
    desc: "Cloud Function invocable by allUsers — unauthenticated access"

  - id: SA-GCP-08
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "source_ranges\\s*=\\s*\\[\\s*\"0\\.0\\.0\\.0/0\"\\s*\\]|sourceRanges:[^}]*0\\.0\\.0\\.0/0"
    severity: error
    desc: "VPC firewall rule open to 0.0.0.0/0 — unrestricted internet ingress"

  - id: SA-GCP-09
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "google_kms_crypto_key_iam[^}]*(allUsers|allAuthenticatedUsers)"
    severity: error
    desc: "KMS key accessible by allUsers — encryption key exposure"

  - id: SA-GCP-10
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "exempted_members\\s*=\\s*\\["
    severity: warning
    desc: "Audit log exemptions configured — all access should be logged"

  # === AZURE SECURITY CHECKS ===
  - id: SA-AZURE-01
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "role_definition_name\\s*=\\s*\"(Owner|Contributor)\"|8e3af657-a8ff-443c-a75c-2fe8c4bcb635|b24988ac-6180-42a0-ab88-20f7382dd24c"
    severity: error
    desc: "Owner/Contributor role assignment — use least-privilege roles"

  - id: SA-AZURE-02
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "role_definition_name\\s*=\\s*\"Storage Blob Data Owner\"(?![^}]*condition\\s*=)"
    severity: warning
    desc: "Storage Blob Data Owner without conditions — add ABAC conditions"

  - id: SA-AZURE-03
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "allow_nested_items_to_be_public\\s*=\\s*true|allow_blob_public_access\\s*=\\s*true|allowBlobPublicAccess['\"]?\\s*[:=]\\s*['\"]?true|container_access_type\\s*=\\s*\"(blob|container)\""
    severity: error
    desc: "Public blob access enabled — anonymous access to storage data"

  - id: SA-AZURE-04
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "authLevel[\"\\s]*[:=]\\s*[\"']?anonymous|\"authLevel\"\\s*:\\s*\"anonymous\""
    severity: error
    desc: "Azure Function with anonymous auth level — no authentication required"

  - id: SA-AZURE-05
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "app_settings\\s*=\\s*\\{[^}]*(PASSWORD|SECRET|KEY|TOKEN|CONNECTION)\\s*=\\s*\"(?!@Microsoft\\.KeyVault)[^\"]+\""
    severity: error
    desc: "Hardcoded secret in Azure Function app settings — use Key Vault references"

  - id: SA-AZURE-06
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "source_address_prefix\\s*=\\s*\"\\*\"|sourceAddressPrefix['\"]?\\s*[:=]\\s*['\"]\\*['\"]|\"sourceAddressPrefix\"\\s*:\\s*\"\\*\""
    severity: error
    desc: "NSG inbound rule open to * — unrestricted internet access"

  - id: SA-AZURE-07
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "purge_protection_enabled\\s*=\\s*false|enablePurgeProtection:\\s*false|\"enablePurgeProtection\"\\s*:\\s*false"
    severity: error
    desc: "Key Vault missing purge protection — keys can be permanently deleted"

  - id: SA-AZURE-08
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "enable_rbac_authorization\\s*=\\s*false|access_policy\\s*\\{"
    severity: warning
    desc: "Key Vault using access policies instead of RBAC — harder to audit"

  - id: SA-AZURE-09
    type: regex
    target: "**/*.{tf,bicep}"
    pattern: "azurerm_monitor_diagnostic_setting"
    severity: warning
    desc: "Diagnostic setting present — verify all critical log categories are enabled"

  - id: SA-AZURE-10
    type: regex_not
    target: "**/*.{tf,bicep}"
    pattern: "public_network_access_enabled\\s*=\\s*true|start_ip_address\\s*=\\s*\"0\\.0\\.0\\.0\""
    severity: error
    desc: "Azure SQL public network access or permissive firewall rule"

  # === WORDPRESS SECURITY ===
  - id: SA-WP-01
    type: regex_not
    target: "**/*.php"
    pattern: "\\$wpdb\\s*->\\s*(query|get_results|get_row|get_var|get_col)\\s*\\(\\s*[\"']"
    severity: error
    desc: "$wpdb query without $wpdb->prepare() — SQL injection risk"

  - id: SA-WP-02
    type: regex_not
    target: "**/*.php"
    pattern: "unserialize\\s*\\(\\s*\\$_(GET|POST|REQUEST|COOKIE|SERVER)|unserialize\\s*\\(\\s*\\$"
    severity: error
    desc: "unserialize() with user-controlled input — object injection risk"

  - id: SA-WP-03
    type: regex_not
    target: "**/*.php"
    pattern: "echo\\s+\\$(?!.*esc_html|.*esc_attr|.*esc_url|.*wp_kses|.*absint|.*intval)"
    severity: error
    desc: "Unescaped output — use esc_html(), esc_attr(), esc_url(), or wp_kses()"

  - id: SA-WP-04
    type: regex_not
    target: "**/*.php"
    pattern: "register_rest_route\\s*\\([^)]*(?!permission_callback)[^)]*\\)|permission_callback.*__return_true"
    severity: error
    desc: "REST API route without permission_callback or with __return_true — unauthenticated access"

  - id: SA-WP-05
    type: regex_not
    target: "**/*.php"
    pattern: "update_option\\s*\\(|update_post_meta\\s*\\(|delete_option\\s*\\(|delete_post_meta\\s*\\("
    severity: warning
    desc: "Option/meta modification — verify current_user_can() and nonce checks are present"

  - id: SA-WP-06
    type: regex_not
    target: "**/*.php"
    pattern: "\\$_POST\\[.*\\]\\s*(?!.*wp_verify_nonce|.*check_ajax_referer|.*wp_nonce)"
    severity: error
    desc: "POST data processed without nonce verification — CSRF risk"

  - id: SA-WP-07
    type: regex_not
    target: "**/*.php"
    pattern: "move_uploaded_file\\s*\\(|\\$_FILES\\s*\\[.*\\]\\s*\\[.tmp_name.\\]"
    severity: error
    desc: "Direct file upload handling — use wp_handle_upload() with MIME validation"

  - id: SA-WP-08
    type: regex_not
    target: "**/*.php"
    pattern: "WP_DEBUG.*true|WP_DEBUG_DISPLAY.*true|DISALLOW_FILE_EDIT.*false"
    severity: error
    desc: "wp-config.php misconfiguration — debug enabled or file editing allowed in production"

  - id: SA-WP-09
    type: regex_not
    target: "**/*.php"
    pattern: "^<\\?php\\s*\\n(?!.*defined\\s*\\(\\s*['\"]ABSPATH['\"])"
    severity: warning
    desc: "PHP file missing defined('ABSPATH') check — direct file access possible"

  - id: SA-WP-10
    type: regex_not
    target: "**/*.php"
    pattern: "\\$table_prefix\\s*=\\s*['\"]wp_['\"]"
    severity: warning
    desc: "Default WordPress table prefix wp_ — makes targeted SQL injection easier"

  # === DRUPAL SECURITY ===
  - id: SA-DRUPAL-01
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "db_query\\s*\\(\\s*[\"'].*\\$|->query\\s*\\(\\s*[\"'].*\\$|sprintf\\s*\\(\\s*[\"']SELECT"
    severity: error
    desc: "Drupal database query with string interpolation — SQL injection risk"

  - id: SA-DRUPAL-02
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "#markup.*\\$|#markup.*\\.\\s*\\$|#markup.*getRequest|#markup.*->get\\s*\\("
    severity: error
    desc: "Render array #markup with user input — XSS risk, use #plain_text or Html::escape()"

  - id: SA-DRUPAL-03
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "['\"]#markup['\"]\\s*=>\\s*.*\\$(?!.*Html::escape|.*Xss::filter|.*check_plain|.*t\\()"
    severity: error
    desc: "Unescaped variable in #markup — XSS risk"

  - id: SA-DRUPAL-04
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "->delete\\s*\\(\\s*\\)|->save\\s*\\(\\s*\\)"
    severity: warning
    desc: "Entity state change — verify Form API CSRF protection or _csrf_token route requirement"

  - id: SA-DRUPAL-05
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "entityQuery\\s*\\([^)]*\\)(?!.*accessCheck)|->load\\s*\\(\\s*\\$"
    severity: error
    desc: "Entity query or load without access check — bypasses node/field access control"

  - id: SA-DRUPAL-06
    type: regex_not
    target: "**/*.{php,module,install}"
    pattern: "hash_salt.*=\\s*['\"]['\"]|error_level.*verbose|update_free_access.*TRUE"
    severity: error
    desc: "Drupal settings.php misconfiguration — empty hash_salt, verbose errors, or update access"

  # === JOOMLA SECURITY ===
  - id: SA-JOOMLA-01
    type: regex_not
    target: "**/*.php"
    pattern: "->where\\s*\\(.*[\"'].*\\.\\s*\\$|setQuery\\s*\\(\\s*[\"'].*\\$|->where\\s*\\(\\s*[\"'].*\\$"
    severity: error
    desc: "Joomla database query with string concatenation — SQL injection risk"

  - id: SA-JOOMLA-02
    type: regex_not
    target: "**/*.php"
    pattern: "->get\\s*\\([^,)]+\\s*,\\s*[^,)]*\\s*,\\s*['\"]RAW['\"]|\\$_GET\\s*\\[|\\$_POST\\s*\\[|\\$_REQUEST\\s*\\["
    severity: error
    desc: "JInput RAW filter or direct superglobal access — unvalidated input"

  - id: SA-JOOMLA-03
    type: regex_not
    target: "**/*.php"
    pattern: "extends\\s+BaseController[^{]*\\{[^}]*function\\s+(delete|save|publish)"
    severity: warning
    desc: "Controller state-changing method — verify authorise() and checkToken() are present"

  - id: SA-JOOMLA-04
    type: regex_not
    target: "**/*.php"
    pattern: "\\$error_reporting\\s*=\\s*['\"]maximum['\"]|\\$debug\\s*=\\s*1|\\$secret\\s*=\\s*['\"]joomla['\"]"
    severity: error
    desc: "Joomla configuration.php misconfiguration — debug enabled or weak secret"

  # === ANDROID SDK SECURITY ===
  - id: SA-ANDROID-01
    type: regex_not
    target: "**/AndroidManifest.xml"
    pattern: "android:exported\\s*=\\s*\"true\""
    severity: warning
    desc: "Exported component — verify intent-filter restrictions and permission guards"

  - id: SA-ANDROID-02
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "rawQuery\\s*\\(\\s*\"[^\"]*\\+\\s*\\w+|rawQuery\\s*\\(\\s*\"[^\"]*\\$\\{?"
    severity: error
    desc: "SQL injection in ContentProvider — use parameterized selectionArgs instead of concatenation"

  - id: SA-ANDROID-03
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "addJavascriptInterface\\s*\\("
    severity: error
    desc: "WebView JavaScript interface — verify API level >= 17 and restrict to trusted origins"

  - id: SA-ANDROID-04
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "getSharedPreferences\\s*\\([^)]*\\)[\\s\\S]{0,80}(password|token|secret|key|credential)|MODE_WORLD_READABLE"
    severity: error
    desc: "Sensitive data in SharedPreferences — use EncryptedSharedPreferences"

  - id: SA-ANDROID-05
    type: regex_not
    target: "**/AndroidManifest.xml"
    pattern: "usesCleartextTraffic\\s*=\\s*\"true\"|cleartextTrafficPermitted\\s*=\\s*\"true\""
    severity: error
    desc: "Cleartext traffic allowed — enforce HTTPS via NetworkSecurityConfig"

  - id: SA-ANDROID-06
    type: regex_not
    target: "**/AndroidManifest.xml"
    pattern: "android:debuggable\\s*=\\s*\"true\""
    severity: error
    desc: "Debug mode enabled in manifest — must be false for release builds"

  - id: SA-ANDROID-07
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "registerReceiver\\s*\\(\\s*\\w+\\s*,\\s*\\w+\\s*\\)\\s*$"
    severity: warning
    desc: "Broadcast receiver registered without permission — add permission parameter"

  - id: SA-ANDROID-08
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "new\\s+Random\\s*\\(|java\\.util\\.Random|kotlin\\.random\\.Random"
    severity: warning
    desc: "Insecure random number generator — use java.security.SecureRandom for tokens"

  - id: SA-ANDROID-09
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "SecretKeySpec\\s*\\(\\s*\"[^\"]+\"\\.toByteArray|private\\s+(static\\s+)?final\\s+byte\\[\\]\\s+\\w*(KEY|key|SECRET|secret)"
    severity: error
    desc: "Hardcoded encryption key — use Android Keystore for key management"

  - id: SA-ANDROID-10
    type: regex_not
    target: "**/*.{kt,java}"
    pattern: "Log\\.(d|v|i)\\s*\\(\\s*\"[^\"]*\"\\s*,\\s*[^)]*?(password|token|secret|key|credential|session)"
    severity: warning
    desc: "Sensitive data in log output — strip debug logs in release builds"

  # === IOS SDK SECURITY ===
  - id: SA-IOS-01
    type: regex_not
    target: "**/*.swift"
    pattern: "kSecAttrAccessibleAlways[^T]|kSecAttrAccessibleAlways\\b(?!ThisDeviceOnly)"
    severity: error
    desc: "Insecure Keychain accessibility — use kSecAttrAccessibleWhenUnlockedThisDeviceOnly"

  - id: SA-IOS-02
    type: regex_not
    target: "**/Info.plist"
    pattern: "NSAllowsArbitraryLoads[\\s\\S]{0,30}<true"
    severity: error
    desc: "App Transport Security disabled — enforce HTTPS connections"

  - id: SA-IOS-03
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "UIWebView"
    severity: error
    desc: "Deprecated UIWebView usage — migrate to WKWebView"

  - id: SA-IOS-04
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "UIPasteboard\\.general\\.(string|setString|setItems|setValue)[\\s\\S]{0,60}(token|password|secret|key|credential|session)"
    severity: warning
    desc: "Sensitive data on general pasteboard — use UIPasteboard.withUniqueName()"

  - id: SA-IOS-05
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "UserDefaults\\.(standard\\.)?set\\s*\\([^,]+,\\s*forKey:\\s*\"(token|password|secret|key|credential|session|auth)|NSUserDefaults.*set(Object|Value).*forKey.*@\"(token|password|secret)"
    severity: error
    desc: "Sensitive data in UserDefaults/NSUserDefaults — use Keychain instead"

  - id: SA-IOS-06
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "application\\s*\\(\\s*_\\s+app.*open\\s+url:\\s*URL|openURL:\\s*\\(NSURL\\s*\\*\\)"
    severity: warning
    desc: "URL scheme handler — verify source app validation and parameter sanitization"

  - id: SA-IOS-07
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "arc4random\\s*\\(|arc4random_uniform\\s*\\([\\s\\S]{0,80}(token|key|secret|session|nonce)"
    severity: error
    desc: "Insecure random for security tokens — use SecRandomCopyBytes"

  - id: SA-IOS-08
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "CC_MD5\\s*\\(|CC_SHA1\\s*\\(|CC_MD5_DIGEST_LENGTH"
    severity: warning
    desc: "Weak hash algorithm (MD5/SHA-1) — use SHA-256 via CryptoKit"

  - id: SA-IOS-09
    type: regex_not
    target: "**/*.pbxproj"
    pattern: "GCC_GENERATE_POSITION_DEPENDENT_CODE\\s*=\\s*YES|CLANG_ENABLE_OBJC_ARC\\s*=\\s*NO"
    severity: error
    desc: "Missing binary protections (PIE/ARC) — enable in Xcode build settings"

  - id: SA-IOS-10
    type: regex_not
    target: "**/*.{swift,m}"
    pattern: "NSLog\\s*\\(\\s*@?\"[^\"]*%([@dfs])[^\"]*\"\\s*,\\s*[^)]*?(password|token|secret|key|credential|session)"
    severity: warning
    desc: "Sensitive data in NSLog — use os_log with .private annotation"

llm_reviews:
  # === HARDCODED CREDENTIALS REVIEW ===
  - id: SA-16
    domain: security
    prompt: |
      Search for hardcoded credentials in the codebase:
      1. Look for patterns like: password, secret, api_key, token, credentials
      2. Check configuration files for plaintext secrets
      3. Look for Base64-encoded strings that might be credentials
      4. Check for AWS keys, database connection strings with passwords
      5. Verify environment variables are used instead of hardcoded values

      Report any findings with file paths and line numbers.
    severity: error
    desc: "Verify no hardcoded credentials exist in codebase"

  # === SQL INJECTION REVIEW ===
  - id: SA-17
    domain: security
    prompt: |
      Audit for SQL injection vulnerabilities:
      1. Check if database queries use prepared statements/parameterized queries
      2. Look for string concatenation in SQL queries
      3. Verify TYPO3 QueryBuilder is used correctly with parameters
      4. Check for raw SQL with user input
      5. Look for patterns like: "SELECT * FROM table WHERE id = " . $id

      For TYPO3, verify:
      - QueryBuilder createNamedParameter() is used for user input
      - No direct SQL string building with request data
    severity: error
    desc: "Verify prepared statements are used to prevent SQL injection"

  # === XXE PREVENTION REVIEW ===
  - id: SA-18
    domain: security
    prompt: |
      Audit XML parsing for XXE vulnerabilities:
      1. Check all XML parsing code (DOMDocument, SimpleXML, XMLReader)
      2. Verify LIBXML_NOENT and LIBXML_DTDLOAD are NOT used
      3. Look for safe flags: LIBXML_NONET, LIBXML_NOBLANKS
      4. Check if libxml_disable_entity_loader() is called (deprecated in PHP 8)
      5. For PHP 8+, verify no external entity loading configuration

      Safe pattern example:
      $doc = new DOMDocument();
      $doc->loadXML($xml, LIBXML_NONET | LIBXML_NOBLANKS);
    severity: error
    desc: "Verify XML parsing is protected against XXE attacks"

  # === XSS PREVENTION REVIEW ===
  - id: SA-19
    domain: security
    prompt: |
      Audit for Cross-Site Scripting (XSS) vulnerabilities:
      1. Check output encoding in PHP files and templates
      2. Verify htmlspecialchars() or equivalent is used for HTML output
      3. Check Fluid templates for proper escaping (f:format.htmlspecialchars)
      4. Look for echo/print of unescaped user input
      5. Check JavaScript contexts for proper JSON encoding

      For TYPO3/Fluid:
      - By default Fluid escapes output, but check for f:format.raw usage
      - Verify ContentObjectRenderer output is properly escaped
    severity: error
    desc: "Verify output encoding prevents XSS attacks"

  # === AUTHENTICATION/AUTHORIZATION REVIEW ===
  - id: SA-20
    domain: security
    prompt: |
      Review authentication and authorization mechanisms:
      1. Check if backend modules require proper authentication
      2. Verify frontend plugins validate user permissions
      3. Look for access control checks before sensitive operations
      4. Check for proper CSRF token validation
      5. Verify session handling is secure

      For TYPO3:
      - Check for proper $GLOBALS['BE_USER'] access checks
      - Verify Extbase actions use @TYPO3\CMS\Extbase\Annotation\IgnoreValidation carefully
    severity: warning
    desc: "Verify proper authentication and authorization controls"

  # === DESERIALIZATION REVIEW ===
  - id: SA-LLM-21
    domain: security
    prompt: |
      Audit for insecure deserialization:
      1. Search for unserialize() calls - check if allowed_classes parameter is used
      2. Look for phar:// usage in file operations (triggers deserialization)
      3. Check if user-controlled data reaches unserialize()
      4. Verify JSON is used instead of serialize/unserialize for data exchange
      5. Check for __wakeup() and __destruct() methods that could be gadget chains

      Safe pattern: unserialize($data, ['allowed_classes' => false])
      Best pattern: json_decode($data) instead
    severity: error
    desc: "Verify no insecure deserialization exists"

  # === FILE UPLOAD REVIEW ===
  - id: SA-LLM-22
    domain: security
    prompt: |
      Audit file upload handling:
      1. Check if MIME type is validated server-side (not just extension)
      2. Verify uploaded files are renamed to random filenames
      3. Check if uploads are stored outside the web root
      4. Look for prevention of script execution in upload directories
      5. Verify file size limits are enforced
      6. Check for image reprocessing to strip metadata

      For TYPO3: verify FAL (File Abstraction Layer) is used
    severity: warning
    desc: "Verify file uploads are handled securely"

  # === CRYPTOGRAPHY REVIEW ===
  - id: SA-LLM-23
    domain: security
    prompt: |
      Audit cryptographic implementations:
      1. Check for weak algorithms (MD5, SHA1 for integrity, DES, RC4, ECB mode)
      2. Verify authenticated encryption is used (sodium_crypto_secretbox or AES-GCM)
      3. Look for hardcoded encryption keys or IVs
      4. Check for proper random generation (random_bytes, not rand/mt_rand)
      5. Verify key derivation uses HKDF or similar (not plain hash)
      6. Check for sodium_memzero() usage to clear sensitive data from memory

      Recommended: Use sodium_crypto_secretbox for symmetric encryption
    severity: error
    desc: "Verify cryptographic practices are secure"

  # === SECURITY HEADERS REVIEW ===
  - id: SA-LLM-24
    domain: security
    prompt: |
      Audit HTTP security headers configuration:
      1. Check for HSTS (Strict-Transport-Security) with adequate max-age
      2. Verify Content-Security-Policy is configured
      3. Check X-Content-Type-Options: nosniff is set
      4. Verify X-Frame-Options or CSP frame-ancestors is set
      5. Check that X-XSS-Protection is set to 0 (deprecated, not 1; mode=block)
      6. Look for Referrer-Policy and Permissions-Policy headers
      7. Check middleware or TypoScript configuration for header settings

      Note: X-XSS-Protection should be 0, not 1. The feature is deprecated.
    severity: warning
    desc: "Verify security headers are properly configured"

  # === CSRF REVIEW (CWE-352) ===
  - id: SA-LLM-25
    domain: security
    prompt: |
      Audit CSRF protection coverage:
      1. Identify all state-changing endpoints (POST, PUT, DELETE, PATCH)
      2. Verify each has CSRF token validation
      3. Check that tokens are unique per session and per form
      4. Verify SameSite cookie attribute is set (Lax or Strict)
      5. Check for proper token regeneration after login

      For TYPO3:
      - Verify FormProtectionFactory is used in backend modules
      - Check Extbase plugins use form ViewHelpers (auto-include CSRF)
      - Look for AJAX endpoints missing CSRF validation
    severity: error
    desc: "Verify CSRF token coverage on all state-changing endpoints (CWE-352)"

  # === SSRF REVIEW (CWE-918) ===
  - id: SA-LLM-26
    domain: security
    prompt: |
      Audit for Server-Side Request Forgery (SSRF):
      1. Find all HTTP client usage (file_get_contents with URLs, curl, Guzzle, HttpClient)
      2. Check if any URL parameter comes from user input
      3. Verify URL allowlisting is applied (not just blocklisting)
      4. Check for DNS rebinding protection (resolve hostname before request)
      5. Verify internal network ranges are blocked (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16)
      6. Check for protocol restrictions (only allow http/https)

      Common vulnerable patterns:
      - file_get_contents($_GET['url'])
      - curl_init($userProvidedUrl)
      - $client->request('GET', $request->get('callback_url'))
    severity: error
    desc: "Verify SSRF protection in HTTP client calls (CWE-918)"

  # === CODE INJECTION REVIEW (CWE-94) ===
  - id: SA-LLM-27
    domain: security
    prompt: |
      Audit for dynamic code execution and code injection:
      1. Search for eval(), assert(), create_function() usage
      2. Check for dynamic include/require with variable paths
      3. Look for preg_replace with /e modifier (deprecated)
      4. Check call_user_func/call_user_func_array with user-controlled callable
      5. Verify no user input flows into code generation or template rendering
      6. Check for reflection-based instantiation with user-controlled class names

      Safe alternatives:
      - Use allowlists for dynamic class/function references
      - Use preg_replace_callback() instead of /e modifier
      - Use match/switch instead of eval for conditional logic
    severity: error
    desc: "Verify no dynamic code execution with user input (CWE-94)"

  # === IDOR REVIEW (CWE-639) ===
  - id: SA-LLM-28
    domain: security
    prompt: |
      Audit for Insecure Direct Object References (IDOR):
      1. Find all endpoints that accept resource IDs from user input
      2. Verify each performs ownership/authorization checks before access
      3. Check for patterns like find($id) without verifying the resource belongs to the user
      4. Look for sequential/predictable IDs that enable enumeration
      5. Verify API endpoints use scoped queries (e.g., findByUserAndId)

      Common vulnerable patterns:
      - $repo->find($_GET['id']) without ownership check
      - Direct database lookup by user-supplied ID
      - Download/export endpoints with unvalidated file/record IDs
    severity: error
    desc: "Verify authorization checks prevent IDOR bypasses (CWE-639)"

  # === RESOURCE EXHAUSTION REVIEW (CWE-770) ===
  - id: SA-LLM-29
    domain: security
    prompt: |
      Audit for resource exhaustion vulnerabilities:
      1. Check for unbounded loops or recursive calls with user-controlled depth
      2. Verify file upload size limits are enforced (upload_max_filesize, post_max_size)
      3. Check database queries have LIMIT clauses (especially findAll/findBy)
      4. Look for missing pagination on list endpoints
      5. Verify rate limiting exists on authentication and API endpoints
      6. Check for ReDoS (Regular Expression Denial of Service) patterns
      7. Verify memory_limit and max_execution_time are set appropriately

      Common vulnerable patterns:
      - $repo->findAll() without limit
      - file_get_contents('php://input') without size check
      - while loops with user-controlled termination condition
    severity: warning
    desc: "Verify resource limits prevent denial of service (CWE-770)"

  # === INFORMATION EXPOSURE REVIEW (CWE-200) ===
  - id: SA-LLM-30
    domain: security
    prompt: |
      Audit for sensitive information exposure:
      1. Check exception handling - verify stack traces are not shown to users
      2. Look for error messages that reveal internal structure (DB schema, file paths)
      3. Verify display_errors is Off in production configuration
      4. Check for debug endpoints or debug mode toggles left enabled
      5. Look for verbose logging that includes sensitive data (passwords, tokens)
      6. Verify API responses don't include internal IDs, timestamps, or metadata unnecessarily
      7. Check for information leakage in HTTP headers (Server, X-Powered-By)

      For TYPO3:
      - Check $GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'] is 0 in production
      - Verify devIPmask does not include wildcard or broad ranges
    severity: warning
    desc: "Verify no sensitive information exposure in errors and responses (CWE-200)"

  # === ACCESS CONTROL REVIEW (CWE-284) ===
  - id: SA-LLM-31
    domain: security
    prompt: |
      Audit access control completeness:
      1. Check that authentication middleware is applied consistently (not missing on routes)
      2. Verify authorization is enforced at controller level, not just in UI/templates
      3. Look for "security through obscurity" (hidden URLs without auth checks)
      4. Check that API endpoints have the same access controls as web endpoints
      5. Verify role/permission checks cannot be bypassed via parameter manipulation
      6. Check for default-allow vs default-deny access control patterns

      For TYPO3:
      - Verify backend module access is configured in ext_tables.php
      - Check that Extbase controllers verify BE_USER permissions
      - Verify frontend plugin access restrictions via TypoScript/Flexform
    severity: warning
    desc: "Verify access control is applied consistently at all layers (CWE-284)"

  # === TYPE JUGGLING (CWE-843) ===
  - id: SA-LLM-32
    domain: security
    prompt: |
      Audit for PHP type juggling vulnerabilities in authentication and authorization:
      1. Search for loose comparison (==) with user-supplied values, especially in auth code
      2. Check password/token comparisons - must use hash_equals() not == or ===
      3. Look for switch statements comparing user input (switch uses loose comparison)
      4. Verify JWT/HMAC signature verification uses timing-safe comparison
      5. Check for "0e" magic hash vulnerability in password comparisons
      6. Look for in_array() without strict flag (third parameter true)

      Vulnerable patterns:
      - if ($token == $_POST['token'])  // "0" matches "0e12345"
      - if ($role == 0)  // "admin" == 0 is true
      - switch ($_GET['action']) { case 0: ... }  // "anything" == 0
      - in_array($input, $whitelist)  // Without strict, "0" matches 0

      Safe patterns:
      - hash_equals($expected, $actual)
      - in_array($input, $whitelist, true)
      - === for all comparisons with user input
    severity: error
    desc: "Verify no loose comparison (==) with user input in auth/security code (CWE-843)"

  # === JWT IMPLEMENTATION FLAWS (CWE-347) ===
  - id: SA-LLM-33
    domain: security
    prompt: |
      Audit JWT implementation for common vulnerabilities:
      1. Check that JWT decode specifies allowed algorithms explicitly (algorithm confusion attack)
      2. Verify "none" algorithm is not accepted
      3. Check that RS256 tokens cannot be verified with HS256 using public key as secret
      4. Verify JWT expiration (exp claim) is checked and enforced
      5. Check that JWT secret/key is not hardcoded or too short
      6. Verify audience (aud) and issuer (iss) claims are validated
      7. Check for JWK/JWKS endpoint security (key injection via jku/x5u headers)

      Vulnerable patterns:
      - JWT::decode($token, $key) without algorithm allowlist
      - Accepting tokens with alg: "none"
      - Short/predictable JWT secrets (less than 256 bits)

      Safe patterns:
      - JWT::decode($token, new Key($publicKey, 'RS256'))
      - Explicit algorithm allowlist in JWT configuration
      - Key rotation with proper JWKS endpoint
    severity: error
    desc: "Verify JWT implementation prevents algorithm confusion and signature bypass (CWE-347)"

  # === HTTP HOST HEADER ATTACKS (CWE-644) ===
  - id: SA-LLM-34
    domain: security
    prompt: |
      Audit for HTTP Host header poisoning vulnerabilities:
      1. Check if $_SERVER['HTTP_HOST'] is used to construct URLs (password reset, email links)
      2. Verify base URL comes from configuration, not from Host header
      3. Look for cache poisoning via Host header in reverse proxy setups
      4. Check if web cache includes Host header in cache key
      5. Verify password reset links use configured base URL, not request host

      Vulnerable patterns:
      - $url = 'https://' . $_SERVER['HTTP_HOST'] . '/reset?token=' . $token
      - $baseUrl = $request->getSchemeAndHttpHost() in security-critical code

      Safe patterns:
      - $baseUrl = $config->get('app.url') or env('APP_URL')
      - Allowlist of valid Host header values in web server config
    severity: warning
    desc: "Verify HTTP Host header is not trusted for security-critical URL generation (CWE-644)"

  # === TIMING ATTACKS IN AUTH (CWE-208) ===
  - id: SA-LLM-35
    domain: security
    prompt: |
      Audit for timing side-channel vulnerabilities in authentication:
      1. Check that token/password comparisons use hash_equals() (constant-time)
      2. Verify HMAC verification uses hash_equals(), not === or strcmp()
      3. Look for early-return patterns in password verification (leaks valid usernames)
      4. Check that login failure response time is consistent regardless of whether user exists
      5. Verify API key comparison is timing-safe

      Vulnerable patterns:
      - if ($apiKey === $storedKey)  // Timing leak
      - if (strcmp($hmac, $expected) !== 0)  // Not constant-time
      - if (!$user) return error; if (!password_verify(...)) return error;  // Different timing for user exists vs wrong password

      Safe patterns:
      - hash_equals($stored, $provided)
      - password_verify($password, $hash) // Already constant-time internally
      - Consistent response time via sleep/delay for auth failures
    severity: warning
    desc: "Verify authentication comparisons are constant-time to prevent timing attacks (CWE-208)"

  # === SECOND-ORDER SQL INJECTION ===
  - id: SA-LLM-36
    domain: security
    prompt: |
      Audit for second-order SQL injection:
      1. Trace data stored from user input through the application
      2. Check if stored data is later used in SQL queries without parameterization
      3. Look for patterns where data is safely INSERT-ed but unsafely SELECT-ed later
      4. Check admin panels, reports, and batch processing that read stored user data
      5. Verify all queries use parameterized statements, even for "trusted" stored data

      Vulnerable flow:
      - Step 1: INSERT INTO users (name) VALUES (?)  -- safe insert with "admin'--"
      - Step 2: "SELECT * FROM posts WHERE author = '" . $user->name . "'"  -- unsafe read

      Key insight: No data from the database is "safe" - always use prepared statements.
    severity: error
    desc: "Verify stored data is not used unsafely in subsequent SQL queries (second-order SQLi)"

  # === ReDoS PATTERNS (CWE-1333) ===
  - id: SA-LLM-37
    domain: security
    prompt: |
      Audit for Regular Expression Denial of Service (ReDoS):
      1. Search for preg_match/preg_replace with user-controlled input
      2. Check for nested quantifiers: (a+)+, (a*)+, (a+)*, ([^"]*)*
      3. Look for alternation with overlapping matches: (a|a)+, (.*|.+)+
      4. Check if pcre.backtrack_limit is set to a reasonable value
      5. Verify regex patterns used on user input have bounded execution time
      6. Check for possessive quantifiers or atomic groups as mitigations

      Vulnerable patterns:
      - preg_match('/^(a+)+$/', $userInput)
      - preg_match('/^([a-zA-Z0-9]+)*@/', $email)
      - preg_match('/(.*)+/', $input)

      Safe patterns:
      - Use atomic groups: (?>a+) or possessive: a++
      - Set pcre.backtrack_limit in php.ini
      - Use filter_var() instead of regex for email/URL validation
      - Limit input length before applying regex
    severity: warning
    desc: "Verify regex patterns with user input are not vulnerable to catastrophic backtracking (CWE-1333)"

  # === PRIVILEGE ESCALATION (CWE-269) ===
  - id: SA-LLM-38
    domain: security
    prompt: |
      Audit for privilege escalation via parameter manipulation:
      1. Check if role/permission values can be set via user input (POST data, JSON body)
      2. Verify that role changes require admin authorization, not just authentication
      3. Look for hidden form fields containing role or permission data
      4. Check API endpoints that modify user attributes for proper authorization
      5. Verify that user profile updates cannot modify role or permission fields
      6. Check for vertical privilege escalation (user -> admin)
      7. Check for horizontal privilege escalation (user A -> user B's data)

      Vulnerable patterns:
      - User::create($request->all()) where request includes 'role' field
      - $user->role = $_POST['role'] without authorization check
      - PUT /api/users/me with {"role": "admin"} accepted

      Safe patterns:
      - Explicit allowlist of user-modifiable fields
      - Server-side role assignment only by authorized admins
      - Different endpoints for profile update vs admin user management
    severity: error
    desc: "Verify role/permission changes require proper authorization (CWE-269)"

  # === AUDIT LOGGING PRESENCE ===
  - id: SA-LLM-39
    domain: security
    prompt: |
      For each PHP service/class handling authentication, authorization,
      credential storage, rate limiting, or token validation:
      1. Verify LoggerInterface is injected (constructor DI)
      2. Verify security events are logged (failed auth, lockout, replay, CSRF)
      3. Verify log levels are appropriate (WARNING for failures, INFO for success)
      4. Verify usernames are NEVER logged in plaintext (must be hashed)
    severity: warning
    tags: [owasp-a09, logging, audit-trail]
    desc: "Security-sensitive services have audit logging"

  # === TOCTOU RACE CONDITIONS ===
  - id: SA-LLM-40
    domain: security
    prompt: |
      Check for Time-of-Check/Time-of-Use race conditions in:
      1. Rate limiters: Is check-then-increment atomic? (needs locking)
      2. Nonce/token validators: Is check-then-consume atomic?
      3. Last-resource guards: Is count-then-delete atomic?
      Look for non-atomic read-check-write sequences in security-critical code.
    severity: error
    tags: [toctou, race-condition, concurrency]
    desc: "No TOCTOU race conditions in security paths"

  # === IMAGE PROCESSING SECURITY ===
  - id: SA-IMG-01
    domain: security
    prompt: |
      Review image processing code for security:
      1. Verify realpath() validation on ALL input image file paths before processing
      2. Check that processed image output paths are validated against a whitelist directory
      3. Verify getimagesize()/exif_read_data() results are checked before use
      4. Check for path traversal in image URL/path parameters (../ sequences)
      5. Verify image dimension/filesize limits are enforced before processing
      6. Check that temporary files from image processing are cleaned up
    severity: error
    desc: "Image processing code must validate input paths with realpath(), enforce dimension/size limits, and clean up temporary files"

  # === LOCK HANDLING SECURITY ===
  - id: SA-LOCK-01
    domain: security
    prompt: |
      Review lock handling for resource exhaustion and deadlock prevention:
      1. Verify all lock acquisitions use try/finally to ensure lock release
      2. Check that LockCreateException is handled in a way that ensures no resource is left locked — catching and retrying or logging is acceptable; silently propagating without cleanup is not
      3. Verify lock timeout is configured (not infinite wait)
      4. Check for exhaustion logging when lock cannot be acquired after retries
      5. Verify no nested lock acquisitions that could cause deadlocks
      6. Check that lock keys are deterministic and don't allow user-controlled lock names
    severity: warning
    desc: "Lock handling must use try/finally for cleanup, catch LockCreateException, configure timeouts, and log exhaustion"

  # === ERROR MESSAGE SANITIZATION (CWE-209) ===
  - id: SA-55
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "throw\\s+new\\s+[\\w\\\\]*Exception\\([^)]*\\$\\w+->getMessage\\(\\)"
    severity: warning
    desc: "Exception re-thrown with raw getMessage() may leak sensitive data (API keys, paths) - sanitize first (CWE-209)"

  - id: SA-56
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "new\\s+JsonResponse\\([^)]*getMessage\\(\\)"
    severity: error
    desc: "Raw exception message in JsonResponse exposes internals to frontend (CWE-209)"

  - id: SA-57
    type: regex_not
    target: "Classes/**/*.php"
    pattern: "new\\s+HtmlResponse\\([^)]*getMessage\\(\\)"
    severity: error
    desc: "Raw exception message in HtmlResponse exposes internals to frontend (CWE-209)"

  # === EXCEPTION TYPE CONSISTENCY ===
  - id: SA-58
    type: command
    target: "! grep -rqP 'throw\\s+new\\s+\\\\?(RuntimeException|BadMethodCallException|\\\\Exception)\\s*\\(' --include='*Provider*.php' --include='*Client*.php' --include='*Connector*.php' --include='*Adapter*.php' Classes/ 2>/dev/null"
    severity: warning
    desc: "Provider/Client/Connector classes should use domain-specific exceptions, not generic RuntimeException or \\Exception"

  # === CONTEXT-AWARE ERROR SUPPRESSION ===
  - id: SA-SUPPRESS-01
    domain: security
    prompt: |
      Review @ error suppression usage for safety:
      1. ACCEPTABLE: @mkdir() for TOCTOU race conditions — must check return value or verify with is_dir() afterward
      2. ACCEPTABLE: @file_get_contents() when return value is checked against false
      3. ACCEPTABLE: @getimagesize() when return value is checked against false
      4. UNACCEPTABLE: @ without subsequent return value validation
      5. UNACCEPTABLE: @unlink() when deletion success is critical
      6. For each @ usage: verify the return value IS checked before the result is used or the function returns
      7. Flag any @ usage without clear TOCTOU justification or return check
    severity: warning
    desc: "Error suppression (@) is only acceptable for TOCTOU races (mkdir) or when return value is explicitly checked (file_get_contents, getimagesize)"

  # === ERROR MESSAGE SANITIZATION REVIEW (CWE-209) ===
  - id: SA-LLM-41
    domain: security
    prompt: |
      Audit error message handling for information leakage:
      1. Check all catch blocks in controllers/actions - verify $e->getMessage() is NOT passed to HTTP responses
      2. Look for exception messages that include HTTP request URLs (may contain API keys as query parameters)
      3. Verify exception re-throws sanitize the inner message before wrapping
      4. Check that server-side logging captures the full exception while client responses use generic messages
      5. Look for patterns like: ?key=, ?api_key=, ?token=, ?secret= in URL construction passed to HTTP clients

      Vulnerable patterns:
      - throw new Exception('Failed: ' . $e->getMessage())  where $e contains URL with API key
      - return new JsonResponse(['error' => $e->getMessage()], 500)
      - echo $e->getMessage() in any response context

      Safe patterns:
      - Sanitize URLs in exception messages: preg_replace('/([?&](key|api_key|token|secret)=)[^&\s]*/i', '$1[REDACTED]', $msg)
      - Log full exception server-side, return generic message to client
      - Use domain-specific exception types with controlled messages
    severity: error
    tags: [cwe-209, error-handling, information-disclosure]
    desc: "Verify error messages do not leak API keys, internal paths, or sensitive details (CWE-209)"

  # === EXCEPTION HIERARCHY CONSISTENCY REVIEW ===
  - id: SA-LLM-42
    domain: security
    prompt: |
      Audit exception usage consistency across provider/client abstraction layers:
      1. Identify all provider/client/connector/adapter classes in the codebase
      2. Verify they all use the same domain-specific exception hierarchy (not generic exceptions)
      3. Check that HTTP status codes map to consistent exception types across providers:
         - 401/402/403 → ProviderConfigurationException (or equivalent auth exception)
         - 429/503/timeout → ProviderConnectionException (or equivalent connectivity exception)
         - 4xx/5xx → ProviderResponseException (or equivalent response exception)
      4. Verify no provider throws RuntimeException, BadMethodCallException, LogicException, or bare \Exception
      5. Check that consumers can rely on catching a common base exception type

      Benefits of consistent exceptions:
      - Centralized error handling in consumers
      - Sanitization middleware can target specific exception types
      - Prevents sensitive details from bypassing error filters via unexpected types
    severity: warning
    tags: [exception-hierarchy, provider-abstraction, error-handling]
    desc: "Verify consistent exception hierarchy across provider abstraction layer"

  # === CRYPTO KEY TRIM CORRUPTION ===
  - id: SA-LLM-43
    domain: security
    prompt: |
      Audit for trim() called on variables that may contain binary key material:
      1. Search for trim(), ltrim(), rtrim() applied to variables holding encryption keys,
         HMAC keys, nonces, IVs, or raw binary secrets
      2. trim() strips bytes matching whitespace characters (0x09, 0x0A, 0x0D, 0x20, 0x00, 0x0B)
         which corrupts binary keys — a 256-bit key can lose entropy silently
      3. Check for trim() on values returned by random_bytes(), sodium_crypto_*keygen(),
         hex2bin(), base64_decode() when result is used as key material
      4. Verify key loading from files or environment does not trim binary content
      5. Safe alternative: if whitespace stripping is needed for base64/hex encoded keys,
         trim BEFORE decoding, never after

      Vulnerable patterns:
      - $key = trim(file_get_contents('secret.key'))  // binary key corrupted
      - $key = trim(sodium_crypto_secretbox_keygen())  // random bytes corrupted
      - $key = trim($env['ENCRYPTION_KEY'])  // if env holds raw binary

      Safe patterns:
      - $key = file_get_contents('secret.key')  // no trim on binary
      - $encoded = trim(file_get_contents('secret.key.b64')); $key = base64_decode($encoded)
    severity: error
    tags: [cryptography, key-management, data-corruption]
    desc: "trim() on binary key material silently corrupts keys by stripping bytes matching whitespace"

  # === ERROR MESSAGE SANITIZATION IN AJAX ENDPOINTS ===
  - id: SA-LLM-44
    domain: security
    prompt: |
      Audit API and AJAX endpoints for raw exception message exposure:
      1. Find all JSON-returning endpoints (JsonResponse, json_encode in controllers/actions)
      2. Check each catch block — $e->getMessage() must NOT appear in the response body
      3. Verify generic error strings are returned instead ('An error occurred', 'Request failed')
      4. Check that the full exception IS logged server-side for debugging
      5. Pay special attention to:
         - AJAX action methods in Extbase controllers
         - REST/API middleware error handlers
         - JsonView error formatters
      6. Exception messages from HTTP clients often contain full request URLs with API keys

      Vulnerable patterns:
      - return new JsonResponse(['error' => $e->getMessage()], 500)
      - echo json_encode(['message' => $exception->getMessage()])
      - $this->view->assign('error', $e->getMessage()) in AJAX context

      Safe patterns:
      - $this->logger->error('Operation failed', ['exception' => $e]);
        return new JsonResponse(['error' => 'An internal error occurred'], 500)
    severity: error
    tags: [cwe-209, ajax, api, information-disclosure]
    desc: "API/AJAX endpoints must not return raw exception messages — use generic error strings"

  # === SSRF HOST VALIDATION FOR AUTH-INJECTING HTTP CLIENTS ===
  - id: SA-LLM-45
    domain: security
    prompt: |
      Audit HTTP client wrappers that inject authentication credentials:
      1. Find all classes that create or configure HTTP clients (Guzzle, HttpClient, curl)
         and inject Authorization headers, Bearer tokens, API keys, or basic auth
      2. Verify the target host/URL is validated against an allowlist BEFORE credentials are sent
      3. Check that redirect following does not leak credentials to third-party hosts
      4. Flag any pattern where auth is injected based on configuration but the URL comes
         from user input or external data without host validation

      Vulnerable patterns:
      - $client->request('GET', $url, ['headers' => ['Authorization' => 'Bearer ' . $token]])
        where $url is not validated against allowed hosts
      - Guzzle middleware that adds auth headers to ALL requests regardless of destination
      - Base URI configured but request path allows host override (e.g., '//evil.com/path')

      Safe patterns:
      - Validate parse_url($url, PHP_URL_HOST) against allowlist before request
      - Use base_uri in Guzzle with relative paths only (reject absolute URLs)
      - Separate client instances per external service with fixed base URIs
    severity: error
    tags: [cwe-918, ssrf, credential-leakage, http-client]
    desc: "HTTP clients injecting auth credentials must validate target host against allowlist before sending"

  # === KEYED VS UNKEYED HASHING FOR TAMPER DETECTION ===
  - id: SA-LLM-46
    domain: security
    prompt: |
      Audit hash-based tamper detection for use of keyed vs unkeyed hashing:
      1. Find all uses of hash('sha256', ...), hash('sha512', ...), md5() for
         integrity verification, audit trails, or tamper detection
      2. Check if the hash is used to detect unauthorized modification of stored data
         (database records, configuration, audit logs)
      3. Unkeyed hashes (SHA-256) can be recomputed by anyone with database access —
         an attacker who compromises the DB can alter records AND recompute valid hashes
      4. Verify HMAC is used instead: hash_hmac('sha256', $data, $secret) where $secret
         is stored separately from the data being protected
      5. Check hash chains / audit trails — each entry should use HMAC, not plain hash

      Vulnerable patterns:
      - $hash = hash('sha256', $record['data'])  // anyone with DB access can recompute
      - $chain = hash('sha256', $previousHash . $newData)  // unkeyed chain

      Safe patterns:
      - $hash = hash_hmac('sha256', $record['data'], $hmacKey)
      - $chain = hash_hmac('sha256', $previousHash . $newData, $hmacKey)
      - HMAC key stored in environment/config, NOT in the database
    severity: error
    tags: [cryptography, hmac, tamper-detection, integrity]
    desc: "Tamper detection hashes must use HMAC (keyed), not plain SHA-256 — unkeyed hashes can be recomputed by anyone with DB access"

  # === COPY-ON-WRITE SODIUM_MEMZERO ===
  - id: SA-LLM-47
    domain: security
    prompt: |
      Audit sodium_memzero() usage for PHP copy-on-write (COW) pitfalls:
      1. In PHP, assigning a string variable creates a shared reference (COW).
         Modifying one copy (via sodium_memzero) only zeros THAT copy, not the original.
      2. Search for patterns where a secret is assigned to another variable, then
         sodium_memzero is called on one but not the other:
         - $key = $config->getKey(); sodium_memzero($key) — $config still holds secret
         - $a = $b; sodium_memzero($b) — $a still holds the secret in memory
         - $decrypted = sodium_crypto_secretbox_open(..., $key); sodium_memzero($key)
           — if $key was assigned from another variable, that source still holds it
      3. Check function parameters: passing a string by value creates a COW copy.
         sodium_memzero on the parameter does not zero the caller's variable.
      4. Verify that ALL references to the secret are zeroed, not just one alias.
      5. Check array/object access: $key = $array['key']; sodium_memzero($key) does NOT
         zero $array['key'].

      Vulnerable patterns:
      - $key = $this->key; sodium_memzero($key);  // $this->key still holds secret
      - function encrypt($key, $data) { ... sodium_memzero($key); }  // caller's $key intact
      - $keys = getKeys(); $enc = $keys['encryption']; sodium_memzero($enc);  // $keys unchanged

      Safe patterns:
      - sodium_memzero($this->key);  // zero the actual property
      - Pass by reference: function encrypt(string &$key, ...) { ... sodium_memzero($key); }
    severity: error
    tags: [cryptography, memory-safety, sodium, secret-cleanup]
    desc: "sodium_memzero() on a copy-on-write variable only zeros the copy — all references to the secret must be zeroed"

  # === READONLY/FINAL VALUE OBJECTS WITH SECRETS ===
  - id: SA-LLM-48
    domain: security
    prompt: |
      Audit readonly classes and final/readonly properties that store secrets:
      1. Find readonly classes (PHP 8.2+) or classes with readonly string properties
      2. Check if any hold sensitive values: tokens, API keys, passwords, encryption keys,
         secrets, credentials, connection strings
      3. Readonly properties cannot be modified after initialization, which means
         sodium_memzero() or any cleanup mechanism cannot zero them
      4. Secrets in readonly properties persist in memory for the object's entire lifetime
      5. Flag readonly class declarations where constructor parameters include
         token, key, secret, password, credential, apiKey naming patterns

      Vulnerable patterns:
      - readonly class ApiCredentials { public function __construct(public string $apiKey, public string $secret) {} }
      - class Config { public readonly string $encryptionKey; }
      - final class Token { public function __construct(private readonly string $bearerToken) {} }

      Safe patterns:
      - Use a mutable property with explicit cleanup in __destruct():
        sodium_memzero($this->accessToken); $this->accessToken = '';
        (Note: simply setting to null does NOT wipe the underlying string from memory)
      - Store secrets in SensitiveParameterValue (PHP 8.2+) for debug protection
      - Use a SecretBox wrapper that holds the value in a mutable property with a wipe() method
        that calls sodium_memzero() before nulling
    severity: error
    tags: [cryptography, memory-safety, readonly, secret-lifecycle]
    desc: "readonly/final value objects storing secrets cannot be zeroed — use mutable properties with explicit cleanup"

  # === REDIRECT CREDENTIAL LEAKAGE IN HTTP CLIENTS ===
  - id: SA-LLM-49
    domain: security
    prompt: |
      Audit HTTP clients for credential leakage via redirects:
      1. Find all Guzzle/HttpClient instances that send Authorization headers,
         Bearer tokens, or API keys
      2. By default, Guzzle follows redirects AND forwards Authorization headers
         to the redirect target — if the target is a different host, credentials leak
      3. Check for explicit redirect configuration:
         - 'allow_redirects' => false (disables redirects entirely)
         - 'allow_redirects' => ['strict' => true] (preserves method but still leaks auth)
         - Custom on_redirect callback that strips auth headers on host change
      4. Check PSR-18 HttpClient implementations for similar redirect behavior
      5. Verify that any HTTP client sending credentials has explicit redirect policy

      Vulnerable patterns:
      - $client = new Client(['headers' => ['Authorization' => 'Bearer ' . $token]])
        // default: follows redirects, sends auth to redirect target
      - $client->request('GET', $url, ['auth' => [$user, $pass]])
        // if $url redirects to external host, credentials are sent

      Safe patterns:
      - $client = new Client(['allow_redirects' => false, 'headers' => ['Authorization' => ...]])
      - Custom redirect middleware that strips Authorization on cross-origin redirect
      - 'allow_redirects' => ['on_redirect' => function() { /* strip auth */ }]
    severity: error
    tags: [cwe-522, http-client, credential-leakage, redirect]
    desc: "HTTP clients following redirects send Authorization headers to redirect targets — configure allow_redirects explicitly"

  # === SODIUM_MEMZERO IN FINALLY BLOCKS ===
  - id: SA-LLM-50
    domain: security
    prompt: |
      Audit sodium_memzero() placement in encryption/decryption operations:
      1. Find all encryption/decryption operations using sodium_crypto_secretbox,
         sodium_crypto_secretbox_open, sodium_crypto_aead_*, or similar
      2. Check that sodium_memzero() for key material is in a finally{} block,
         NOT placed after the try/catch block or only after success
      3. If an exception is thrown during encryption/decryption, keys left in memory
         without finally{} cleanup persist until garbage collection
      4. Verify the pattern: try { encrypt/decrypt } finally { sodium_memzero($key) }
      5. Check for early returns inside try blocks that skip sodium_memzero()

      Vulnerable patterns:
      - $result = sodium_crypto_secretbox($msg, $nonce, $key);
        sodium_memzero($key);  // skipped if exception thrown above
      - try { $result = encrypt($data, $key); } catch (...) { throw ...; }
        sodium_memzero($key);  // never reached if catch re-throws

      Safe patterns:
      - try { $result = sodium_crypto_secretbox($msg, $nonce, $key); }
        finally { sodium_memzero($key); sodium_memzero($nonce); }
      - Using a wrapper that handles cleanup in __destruct or finally internally
    severity: error
    tags: [cryptography, memory-safety, sodium, exception-handling]
    desc: "sodium_memzero() must be in finally{} blocks — exceptions during crypto operations leave keys in memory"

  # === DEPENDENCY VULNERABILITY MANAGEMENT ===
  - id: SA-DEP-05
    domain: supply-chain
    prompt: |
      Check the project's dependency vulnerability posture:
      1. Check Dependabot alerts for the repository (if accessible) or
         check for open Dependabot PRs indicating known vulnerabilities
      2. For npm projects: check if pnpm-lock.yaml/package-lock.json contains
         known-vulnerable transitive dependency versions. Cross-reference with
         the project's pnpm.overrides or npm.overrides — overrides should be
         a LAST RESORT when upstream hasn't patched
      3. For Go projects: check go.sum for github.com/docker/docker or other
         packages with known unfixable module path issues (v29.x not available
         on github.com/docker/docker Go module path)
      4. Verify the project has a strategy for each alert: fixed, dismissed
         with rationale, or tracked for upstream fix
      Report unaddressed vulnerabilities and recommend the appropriate fix
      strategy (upgrade > override > dismiss with rationale).
    severity: warning
    desc: "Verify all Dependabot alerts are addressed: prefer upgrades over overrides, dismiss unfixable with rationale"

  - id: SA-DEP-06
    domain: supply-chain
    prompt: |
      For npm/pnpm projects, verify transitive dependency health:
      1. Check if pnpm.overrides or npm.overrides exist in package.json
      2. For each override, verify it's still necessary — run pnpm update
         or npm update and check if the patched version resolves naturally
      3. Stale overrides that are no longer needed add maintenance burden
         and may mask version conflicts
      4. Check that direct dependencies are up to date — upgrading direct
         deps often pulls in patched transitive deps naturally
      Report unnecessary overrides and outdated direct dependencies.
    severity: warning
    desc: "Verify pnpm/npm overrides are still necessary and direct deps are current"

  # === GITHUB ACTIONS SECURITY PATTERNS ===
  - id: SA-GHA-03
    domain: ci-security
    prompt: |
      Review GitHub Actions workflows for security anti-patterns:
      1. Any ${{ inputs.* }} or ${{ github.event.* }} used directly in run:
         blocks is a code injection vector — must use env: block instead
      2. Check that pull_request_target workflows don't check out PR head
         code and execute it (combined with write permissions = RCE)
      3. Verify GITHUB_TOKEN permissions follow least-privilege principle
      4. Check for secrets passed to steps that don't need them
      5. Ensure third-party actions are SHA-pinned (not tag-only)
      Report specific injection vectors and their remediation.
    severity: error
    desc: "Review GitHub Actions for injection vectors, permission scope, and secret exposure"

Related skills

How it compares

Pick security-audit over generic code-review skills when you need OWASP/CWE checklist coverage, polyglot framework references, and bundled audit scripts rather than informal security comments.

FAQ

What does security-audit scan in a project?

security-audit scans auth flows, dependencies, secrets, OWASP Top 10 and API risks, cloud IaC, frontends, and AI agent configuration files. The dispatcher script auto-detects the stack from indicator files and runs matching scanners from 17 supported ecosystems.

How many checkpoints does security-audit include?

security-audit includes 80+ automated security checkpoints defined in checkpoints.yaml, plus extensive reference guides for OWASP, CWE Top 25 2025, CVSS v4.0, and framework-specific hardening patterns across PHP, Python, JavaScript, Go, Rust, and cloud platforms.

Which commands run a security-audit review?

security-audit runs ./scripts/security-audit-dispatcher.sh for auto-detected stacks, ./scripts/security-audit.sh for PHP-focused audits, or ./scripts/github-security-audit.sh owner/repo for GitHub repository reviews. The skill expects grep, jq, and gh CLI availability.

Securityauditappseccompliance

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.