CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m50s
CI / Detect Changes (pull_request) Skipped
CI / Deploy Agent (pull_request) Skipped
CI / Deploy Dashboard (pull_request) Skipped
CI / Deploy Docs (pull_request) Skipped
CI / Deploy MCP (pull_request) Skipped
Covers the pattern-expressible slice of the needs_tooling bucket that no off-the-shelf ruleset digs out, keeping detection deterministic (LLM only FP-filters downstream, never detects): - cra-ai-1 Secure-by-Default: flask/django debug, TLS verify=False, CORS '*' - cra-ai-7 Strong auth: password/secret hashed with md5/sha1 (metavar-gated) - cra-ai-10 Session mgmt: Secure/HttpOnly = false cookies (py + express) - cra-ai-14 Data at rest: ECB/DES/3DES + node createCipher Rules ship in the binary (include_str!) and stage to a temp file at scan time, added as a second --config alongside --config=auto (no deploy/volume change). Wiring: control-map gains controls_for_finding (match by CWE and/or rule id); custom controls bind by rule id with cwe:[] so a broad CWE can't over-attribute and let the judge FP-drop a genuine finding. rule_id_matches tolerates semgrep's path prefix on local check_ids. Triage now maps by rule id too (a custom finding carries no LUT CWE). LUT: cra-ai-1,7,10,14 needs_tooling->covered (covered 9->13). Validated: all 9 rules fire on positive fixtures, 0 on clean. ControlCheckSpec gains Serialize/Deserialize (unrelated-safe; already used by the index cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
4.8 KiB
YAML
118 lines
4.8 KiB
YAML
# Custom semgrep rules for CRA controls that no off-the-shelf ruleset digs out.
|
|
# Each rule id is `cra-ai-<n>-<slug>` and is keyed back to its control via the
|
|
# `control-map` LUT (by rule-id suffix, so semgrep's path prefix on check_id does
|
|
# not matter). Detection here is deterministic; the grounded LLM judge downstream
|
|
# only confirms/refutes — it never detects. Keep patterns tight: a false positive
|
|
# that the judge refutes marks the whole finding a false positive.
|
|
rules:
|
|
# --- cra-ai-1: Secure-by-Default-Konfiguration -------------------------------
|
|
- id: cra-ai-1-flask-debug-enabled
|
|
languages: [python]
|
|
severity: WARNING
|
|
message: Flask app started with debug=True — ships an interactive debugger / code execution in production (secure-by-default violation).
|
|
metadata:
|
|
cwe: ["CWE-489: Active Debug Code"]
|
|
control: cra-ai-1
|
|
patterns:
|
|
- pattern: '$APP.run(..., debug=True, ...)'
|
|
|
|
- id: cra-ai-1-django-debug-true
|
|
languages: [python]
|
|
severity: WARNING
|
|
message: Django DEBUG = True — leaks stack traces / settings in production (secure-by-default violation).
|
|
metadata:
|
|
cwe: ["CWE-489: Active Debug Code"]
|
|
control: cra-ai-1
|
|
patterns:
|
|
- pattern: 'DEBUG = True'
|
|
|
|
- id: cra-ai-1-tls-verify-disabled
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: TLS certificate verification disabled (verify=False) — defeats transport security by default.
|
|
metadata:
|
|
cwe: ["CWE-295: Improper Certificate Validation"]
|
|
control: cra-ai-1
|
|
patterns:
|
|
- pattern: 'requests.$M(..., verify=False, ...)'
|
|
|
|
- id: cra-ai-1-cors-wildcard
|
|
languages: [javascript, typescript]
|
|
severity: WARNING
|
|
message: CORS Access-Control-Allow-Origin set to "*" — opens the API to any origin by default.
|
|
metadata:
|
|
cwe: ["CWE-942: Permissive Cross-domain Policy with Untrusted Domains"]
|
|
control: cra-ai-1
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: '$RES.header("Access-Control-Allow-Origin", "*")'
|
|
- pattern: '$RES.setHeader("Access-Control-Allow-Origin", "*")'
|
|
|
|
# --- cra-ai-7: Starke Authentifizierung (weak password hashing) --------------
|
|
- id: cra-ai-7-weak-password-hash
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: Password/secret hashed with a fast, broken digest (md5/sha1) — use a password KDF (bcrypt/scrypt/argon2).
|
|
metadata:
|
|
cwe: ["CWE-916: Use of Password Hash With Insufficient Computational Effort"]
|
|
control: cra-ai-7
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: 'hashlib.md5($PW)'
|
|
- pattern: 'hashlib.sha1($PW)'
|
|
- metavariable-regex:
|
|
metavariable: $PW
|
|
regex: '(?i).*(pass|pwd|secret|cred|token).*'
|
|
|
|
# --- cra-ai-10: Sitzungsmanagement (insecure session cookies) ----------------
|
|
- id: cra-ai-10-session-cookie-insecure
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: Session cookie hardened flag explicitly disabled (Secure/HttpOnly = False) — session token exposed to theft.
|
|
metadata:
|
|
cwe: ["CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute"]
|
|
control: cra-ai-10
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: 'SESSION_COOKIE_SECURE = False'
|
|
- pattern: 'SESSION_COOKIE_HTTPONLY = False'
|
|
|
|
- id: cra-ai-10-express-cookie-insecure
|
|
languages: [javascript, typescript]
|
|
severity: ERROR
|
|
message: Express cookie set with secure/httpOnly = false — session token exposed to interception / XSS theft.
|
|
metadata:
|
|
cwe: ["CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute"]
|
|
control: cra-ai-10
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: '$RES.cookie($NAME, $VAL, {..., secure: false, ...})'
|
|
- pattern: '$RES.cookie($NAME, $VAL, {..., httpOnly: false, ...})'
|
|
|
|
# --- cra-ai-14: Speicher-Schutz / Data at Rest (weak cipher) -----------------
|
|
- id: cra-ai-14-python-weak-cipher
|
|
languages: [python]
|
|
severity: ERROR
|
|
message: Data-at-rest encrypted with a broken cipher/mode (ECB, DES, 3DES) — provides no real confidentiality.
|
|
metadata:
|
|
cwe: ["CWE-327: Use of a Broken or Risky Cryptographic Algorithm"]
|
|
control: cra-ai-14
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: 'AES.new($K, AES.MODE_ECB, ...)'
|
|
- pattern: 'DES.new(...)'
|
|
- pattern: 'DES3.new(...)'
|
|
|
|
- id: cra-ai-14-node-weak-cipher
|
|
languages: [javascript, typescript]
|
|
severity: ERROR
|
|
message: Data-at-rest encrypted with a broken cipher (DES / deprecated createCipher) — provides no real confidentiality.
|
|
metadata:
|
|
cwe: ["CWE-327: Use of a Broken or Risky Cryptographic Algorithm"]
|
|
control: cra-ai-14
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: 'crypto.createCipheriv("des-ecb", ...)'
|
|
- pattern: 'crypto.createCipheriv("des", ...)'
|
|
- pattern: 'crypto.createCipher(...)'
|