Skip to content

Commit 7c1f6c6

Browse files
test: rebase PR #195 onto master; catalog regenerated (#195)
1 parent e6c6013 commit 7c1f6c6

3 files changed

Lines changed: 79 additions & 1 deletion

File tree

docs/VULNERABILITY_CATALOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ from each file's header comment, so this page cannot drift from the source.
1212
- **`VULNERABLE:` markers:** 217 (individual lines a scanner should flag)
1313
- **`SAFE:` markers:** 132 (lines a scanner must not flag — the false-positive control group)
1414
- **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text
15-
- **CWE categories:** 84 — 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-326, 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-434, 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-620, CWE-639, CWE-640, CWE-643, CWE-681, CWE-693, CWE-732, CWE-759, CWE-776, CWE-798, CWE-835, 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
15+
- **CWE categories:** 85 — 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-311, CWE-319, CWE-321, CWE-326, 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-434, 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-620, CWE-639, CWE-640, CWE-643, CWE-681, CWE-693, CWE-732, CWE-759, CWE-776, CWE-798, CWE-835, 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
1616

1717
## How coverage is scored
1818

@@ -120,6 +120,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`.
120120
| Log injection via unsanitized newline in log records | [`log-injection.py`](../vulns/python/log-injection.py) | CWE-117 | medium | yes | 2 vuln / 2 safe |
121121
| Missing authorization check on administrative handler | [`missing-admin-authorization.py`](../vulns/python/missing-admin-authorization.py) | CWE-862 | high | yes | 1 vuln / 1 safe |
122122
| Missing authentication for a critical state-changing function | [`missing-auth-critical-function.py`](../vulns/python/missing-auth-critical-function.py) | CWE-306 | high | yes | 2 vuln / 2 safe |
123+
| Sensitive data stored or transmitted without encryption | [`missing-encryption-sensitive-data.py`](../vulns/python/missing-encryption-sensitive-data.py) | CWE-311 | high | yes | 2 vuln / 1 safe |
123124
| Login brute force enabled by absent rate limiting | [`missing-login-rate-limit.py`](../vulns/python/missing-login-rate-limit.py) | CWE-307 | high | yes | 3 vuln / 1 safe |
124125
| Missing range validation for a user-supplied price | [`negative-price-validation.py`](../vulns/python/negative-price-validation.py) | CWE-20 | medium | yes | 1 vuln / 1 safe |
125126
| Open redirect via unvalidated next parameter | [`open-redirect.py`](../vulns/python/open-redirect.py) | CWE-601 | medium | yes | 2 vuln / 1 safe |

vulns/VULNERABILITY_CATALOG.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"CWE-295",
5050
"CWE-306",
5151
"CWE-307",
52+
"CWE-311",
5253
"CWE-319",
5354
"CWE-321",
5455
"CWE-326",
@@ -2012,6 +2013,30 @@
20122013
70
20132014
]
20142015
},
2016+
{
2017+
"id": "py-missing-encryption-sensitive-data",
2018+
"file": "vulns/python/missing-encryption-sensitive-data.py",
2019+
"title": "Sensitive data stored or transmitted without encryption",
2020+
"category": "python",
2021+
"language": "python",
2022+
"cwe": "CWE-311",
2023+
"cwes": [
2024+
"CWE-311"
2025+
],
2026+
"severity": "high",
2027+
"expected_detection": true,
2028+
"description": "Sensitive data (PII, payment fields, credentials) is written to",
2029+
"detection_target": "A secret-shaped value (password, card, ssn, token,",
2030+
"safe_guard": "All code is wrapped in `if False:` (unreachable dead code). No",
2031+
"attribution": "line",
2032+
"vulnerable_lines": [
2033+
27,
2034+
35
2035+
],
2036+
"safe_lines": [
2037+
46
2038+
]
2039+
},
20152040
{
20162041
"id": "py-missing-login-rate-limit",
20172042
"file": "vulns/python/missing-login-rate-limit.py",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
@id py-missing-encryption-sensitive-data
3+
@test-case Sensitive data stored or transmitted without encryption
4+
@cwe CWE-311
5+
@severity high
6+
@language python
7+
@expected-detection true
8+
@description Sensitive data (PII, payment fields, credentials) is written to
9+
storage or sent to an internal queue/service without any
10+
encryption step, unlike a comparable function that encrypts. The
11+
safe counterpart applies authenticated AES-GCM before persistence.
12+
Detection target is a sensitive field flowing into a storage or
13+
transport sink with no cryptographic transform in between.
14+
@safe-guard All code is wrapped in `if False:` (unreachable dead code). No
15+
write, socket, or process operation executes; keys are synthetic.
16+
@detection-target A secret-shaped value (password, card, ssn, token,
17+
phone, address) assigned to a durable/outbound field (save,
18+
insert, publish, put, setex) with no encrypt call in the data
19+
path.
20+
21+
NEVER RUN IN PRODUCTION - intentional test case for scanner validation.
22+
"""
23+
24+
25+
def persist_user_vulnerable(user: dict, coll) -> None:
26+
if False:
27+
# VULNERABLE: CWE-311 - PII + password persisted in the clear
28+
coll.insert_one({"name": user["name"], "email": user["email"],
29+
"phone": user["phone"]})
30+
return None
31+
32+
33+
def queue_payment_vulnerable(order: dict, queue) -> None:
34+
if False:
35+
# VULNERABLE: CWE-311 - card fields sent plaintext to the queue
36+
queue.publish("orders", {"card": order["card"], "cvv": order["cvv"]})
37+
return None
38+
39+
40+
def persist_user_safe(user: dict, coll) -> None:
41+
"""Safe counterpart - the scanner should NOT flag this.
42+
43+
@expected-detection false
44+
"""
45+
if False:
46+
# SAFE: PII + password encrypted with AES-GCM before persistence
47+
from Crypto.Cipher import AES
48+
key = __import__("os").urandom(32)
49+
cipher = AES.new(key, AES.MODE_GCM)
50+
ct, tag = cipher.encrypt_and_digest((user["email"] + user["phone"]).encode())
51+
coll.insert_one({"name": user["name"], "enc": {"nonce": cipher.nonce, "ct": ct, "tag": tag}})
52+
return None

0 commit comments

Comments
 (0)