From b0beb07ea6dc3f8f18b73ba56a950ac80619f8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eze=F0=9F=91=BD?= Date: Wed, 19 Aug 2026 04:47:51 -0300 Subject: [PATCH] test: rebase PR #196 onto master; catalog regenerated --- docs/VULNERABILITY_CATALOG.md | 11 +++-- vulns/VULNERABILITY_CATALOG.json | 33 +++++++++++-- vulns/python/cleartext-sensitive-storage.py | 55 +++++++++++++++++++++ 3 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 vulns/python/cleartext-sensitive-storage.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 5f92f81..bf65962 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,12 +7,12 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 117 -- **Expected detections:** 117 -- **`VULNERABLE:` markers:** 217 (individual lines a scanner should flag) -- **`SAFE:` markers:** 132 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 122 +- **Expected detections:** 122 +- **`VULNERABLE:` markers:** 227 (individual lines a scanner should flag) +- **`SAFE:` markers:** 137 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **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 +- **CWE categories:** 86 — 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-312, 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 ## How coverage is scored @@ -103,6 +103,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Cleartext storage of sensitive information in a local file | [`cleartext-sensitive-storage.py`](../vulns/python/cleartext-sensitive-storage.py) | CWE-312 | high | yes | 2 vuln / 1 safe | | Sensitive data sent over an unencrypted channel | [`cleartext-transmission.py`](../vulns/python/cleartext-transmission.py) | CWE-319 | high | yes | 5 vuln / 1 safe | | Session cookie missing Secure flag over HTTPS | [`cookie-without-secure.py`](../vulns/python/cookie-without-secure.py) | CWE-614 | medium | yes | 3 vuln / 2 safe | | CSRF via missing anti-CSRF token on state-changing POST | [`csrf-missing-token.py`](../vulns/python/csrf-missing-token.py) | CWE-352 | high | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index f6ebea1..5d09da1 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -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": 117, - "expected_detections": 117, - "vulnerable_markers": 217, - "safe_markers": 132, + "test_cases": 122, + "expected_detections": 122, + "vulnerable_markers": 227, + "safe_markers": 137, "languages": [ "dotenv", "go", @@ -50,6 +50,7 @@ "CWE-306", "CWE-307", "CWE-311", + "CWE-312", "CWE-319", "CWE-321", "CWE-326", @@ -1567,6 +1568,30 @@ 34 ] }, + { + "id": "py-cleartext-sensitive-storage", + "file": "vulns/python/cleartext-sensitive-storage.py", + "title": "Cleartext storage of sensitive information in a local file", + "category": "python", + "language": "python", + "cwe": "CWE-312", + "cwes": [ + "CWE-312" + ], + "severity": "high", + "expected_detection": true, + "description": "Sensitive data (session tokens, passwords, API keys) is written", + "detection_target": "open(..., \"w\") / Path.write_text / json.dump / yaml.dump", + "safe_guard": "All code is wrapped in `if False:` (unreachable dead code). No", + "attribution": "line", + "vulnerable_lines": [ + 31, + 39 + ], + "safe_lines": [ + 51 + ] + }, { "id": "py-cleartext-transmission", "file": "vulns/python/cleartext-transmission.py", diff --git a/vulns/python/cleartext-sensitive-storage.py b/vulns/python/cleartext-sensitive-storage.py new file mode 100644 index 0000000..e815857 --- /dev/null +++ b/vulns/python/cleartext-sensitive-storage.py @@ -0,0 +1,55 @@ +""" +@id py-cleartext-sensitive-storage +@test-case Cleartext storage of sensitive information in a local file +@cwe CWE-312 +@severity high +@language python +@expected-detection true +@description Sensitive data (session tokens, passwords, API keys) is written + to a local file in cleartext with no access restriction. Any + process with the app's user can read the file. The safe + counterpart encrypts the payload or stores the secret via a + restricted 0o600 file with key rotation. Detection target is a + secret-shaped value written to a filesystem sink with no + encryption step. +@safe-guard All code is wrapped in `if False:` (unreachable dead code). No + file is created; the secret literal is synthetic and protects + nothing. +@detection-target open(..., "w") / Path.write_text / json.dump / yaml.dump + where the payload contains a credential/token/session-shaped + value and the write mode is not restricted/encrypted. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + +import json +import os + + +def cache_session_token_vulnerable(session_id: str) -> None: + if False: + # VULNERABLE: CWE-312 - session token persisted in cleartext + with open("/tmp/internal/session.txt", "w") as fh: # noqa: S108 + fh.write(session_id) + return None + + +def dump_config_vulnerable(api_key: str) -> None: + if False: + # VULNERABLE: CWE-312 - API key dumped to JSON cleartext + with open("config/runtime.json", "w") as fh: + json.dump({"api_key": api_key}, fh) + return None + + +def cache_session_token_safe(session_id: str) -> None: + """Safe counterpart - the scanner should NOT flag this. + + @expected-detection false + """ + if False: + # SAFE: restricted perms + only encrypted bytes persisted + fd = os.open("/tmp/internal/session.dat", os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + with os.fdopen(fd, "wb") as fh: + fh.write(b"encrypted-bytes-here") + return None \ No newline at end of file