Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions docs/VULNERABILITY_CATALOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ from each file's header comment, so this page cannot drift from the source.

## Totals

- **Test cases:** 99
- **Expected detections:** 99
- **`VULNERABLE:` markers:** 172 (individual lines a scanner should flag)
- **`SAFE:` markers:** 110 (lines a scanner must not flag — the false-positive control group)
- **Test cases:** 100
- **Expected detections:** 100
- **`VULNERABLE:` markers:** 175 (individual lines a scanner should flag)
- **`SAFE:` markers:** 111 (lines a scanner must not flag — the false-positive control group)
- **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text
- **CWE categories:** 77 — CWE-20, CWE-22, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-129, CWE-190, CWE-201, CWE-203, CWE-208, CWE-209, CWE-256, CWE-287, CWE-288, CWE-291, CWE-295, CWE-306, CWE-307, CWE-319, CWE-321, CWE-327, CWE-329, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-441, CWE-460, CWE-472, CWE-475, CWE-480, CWE-488, CWE-489, CWE-502, CWE-506, CWE-509, CWE-512, CWE-521, CWE-525, CWE-532, CWE-598, CWE-601, CWE-602, CWE-611, CWE-613, CWE-614, CWE-639, CWE-643, CWE-681, CWE-693, CWE-759, CWE-776, CWE-798, CWE-862, CWE-863, CWE-915, CWE-916, CWE-918, CWE-922, CWE-942, CWE-943, CWE-1021, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357
- **CWE categories:** 78 — CWE-20, CWE-22, CWE-78, CWE-79, CWE-89, CWE-90, CWE-94, CWE-95, CWE-113, CWE-117, CWE-129, CWE-190, CWE-201, CWE-203, CWE-208, CWE-209, CWE-256, CWE-287, CWE-288, CWE-291, CWE-295, CWE-306, CWE-307, CWE-319, CWE-321, CWE-327, CWE-329, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-441, CWE-460, CWE-472, CWE-475, CWE-480, CWE-488, CWE-489, CWE-502, CWE-506, CWE-509, CWE-512, CWE-521, CWE-525, CWE-532, CWE-598, CWE-601, CWE-602, CWE-611, CWE-613, CWE-614, CWE-639, CWE-643, CWE-681, CWE-693, CWE-759, CWE-776, CWE-798, CWE-862, CWE-863, CWE-915, CWE-916, CWE-918, CWE-922, CWE-942, CWE-943, CWE-1021, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357

## How coverage is scored

Expand Down Expand Up @@ -103,6 +103,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`.
|---|---|---|---|---|---|
| Sensitive data sent over an unencrypted channel | [`cleartext-transmission.py`](../vulns/python/cleartext-transmission.py) | CWE-319 | high | yes | 5 vuln / 1 safe |
| CSV formula injection from untrusted spreadsheet cells | [`csv-formula-injection.py`](../vulns/python/csv-formula-injection.py) | CWE-1236 | medium | yes | 1 vuln / 1 safe |
| Code injection via eval() on attacker-controlled input | [`eval-code-injection.py`](../vulns/python/eval-code-injection.py) | CWE-94 | critical | yes | 3 vuln / 1 safe |
| Excessive user-record exposure in an API response | [`excessive-data-exposure.py`](../vulns/python/excessive-data-exposure.py) | CWE-201 | high | yes | 1 vuln / 1 safe |
| Flask debug mode enabled in application configuration | [`flask-debug-enabled.py`](../vulns/python/flask-debug-enabled.py) | CWE-489 | high | yes | 1 vuln / 1 safe |
| Hardcoded secret used to configure session signing | [`hardcoded-session-secret.py`](../vulns/python/hardcoded-session-secret.py) | CWE-798 | high | yes | 1 vuln / 1 safe |
Expand Down
34 changes: 30 additions & 4 deletions vulns/VULNERABILITY_CATALOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"schema": "threatcrush-testbed-catalog/1",
"note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.",
"totals": {
"test_cases": 99,
"expected_detections": 99,
"vulnerable_markers": 172,
"safe_markers": 110,
"test_cases": 100,
"expected_detections": 100,
"vulnerable_markers": 175,
"safe_markers": 111,
"languages": [
"dotenv",
"go",
Expand All @@ -32,6 +32,7 @@
"CWE-79",
"CWE-89",
"CWE-90",
"CWE-94",
"CWE-95",
"CWE-113",
"CWE-117",
Expand Down Expand Up @@ -1588,6 +1589,31 @@
44
]
},
{
"id": "py-eval-code-injection",
"file": "vulns/python/eval-code-injection.py",
"title": "Code injection via eval() on attacker-controlled input",
"category": "python",
"language": "python",
"cwe": "CWE-94",
"cwes": [
"CWE-94"
],
"severity": "critical",
"expected_detection": true,
"description": "An expression built from request-supplied input is passed to",
"detection_target": "eval()/exec() on any data-flow path that touches request",
"safe_guard": "Every payload is wrapped in `if False:` \u2014 unreachable dead code.",
"attribution": "line",
"vulnerable_lines": [
28,
37,
45
],
"safe_lines": [
56
]
},
{
"id": "py-excessive-data-exposure",
"file": "vulns/python/excessive-data-exposure.py",
Expand Down
63 changes: 63 additions & 0 deletions vulns/python/eval-code-injection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
@id py-eval-code-injection
@test-case Code injection via eval() on attacker-controlled input
@cwe CWE-94
@severity critical
@language python
@expected-detection true
@description An expression built from request-supplied input is passed to
eval(), which executes arbitrary Python in the server process.
A second variant routes the payload through exec() on a
de-obfuscated byte-string, the same sink reached from an
attacker-controlled payload.
@safe-guard Every payload is wrapped in `if False:` — unreachable dead code.
There is no import of any live module and no socket/disk write.
@detection-target eval()/exec() on any data-flow path that touches request
input, even through str.replace or base64 decoding.

NEVER RUN IN PRODUCTION — intentional test case for scanner validation.
"""

import base64


def eval_math_vulnerable(request):
if False:
# SOURCE: attacker-controlled expression string
expr = request.args["expr"]
# VULNERABLE: CWE-94 — eval executes arbitrary Python
return eval(expr)
Comment thread
ralyodio marked this conversation as resolved.
Dismissed
return None


def eval_obfuscated_vulnerable(request):
if False:
# SOURCE: attacker-controlled base64 payload, decoded then executed
payload = base64.b64decode(request.args["b64"]).decode()
# VULNERABLE: CWE-94 — decoding does not make the input safe
return eval(payload)
Comment thread
ralyodio marked this conversation as resolved.
Dismissed
return None


def exec_vulnerable(request):
if False:
code = request.form.get("code")
# VULNERABLE: CWE-94 — exec runs a full statement suite
exec(code)
Comment thread
ralyodio marked this conversation as resolved.
Dismissed
return None


def eval_whitelist_safe(request):
"""Safe counterpart — the scanner should NOT flag this.

@expected-detection false
"""
if False:
# SAFE: only a fixed set of numeric operators is ever evaluated,
# and ast.literal_eval never runs arbitrary code.
import ast
tokens = set(request.args["expr"].split())
if not tokens.issubset({"0", "1", "+", "-", "*", "/", "(", ")"}):
return None
return ast.literal_eval(request.args["expr"])
return None
Loading