From d5188901ba85a172afa6dadb8be6ea8fc061915b Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 19:35:45 +0000 Subject: [PATCH 01/66] test-cases: add CWE-77 (JS shelljs), CWE-912 (Java backdoor), CWE-23 (Ruby path traversal) Three new scanner test cases in languages/categories with zero coverage: - javascript/command-injection-shelljs.js (CWE-77, cmd injection via string concat vs execFile argv) - java/hidden-backdoor-endpoint.java (CWE-912, magic-token backdoor on health route) - ruby/relative-path-traversal.rb (CWE-23, ../ escape vs expand_path containment) All follow the five safety rules (if (false)/NEVER_RUN guards, .invalid/.example hosts, no side effects). Catalog regenerated: 65 test cases, 49 CWEs. --- docs/VULNERABILITY_CATALOG.md | 13 ++-- vulns/VULNERABILITY_CATALOG.json | 78 ++++++++++++++++++- vulns/java/hidden-backdoor-endpoint.java | 42 ++++++++++ vulns/javascript/command-injection-shelljs.js | 43 ++++++++++ vulns/ruby/relative-path-traversal.rb | 38 +++++++++ 5 files changed, 205 insertions(+), 9 deletions(-) create mode 100644 vulns/java/hidden-backdoor-endpoint.java create mode 100644 vulns/javascript/command-injection-shelljs.js create mode 100644 vulns/ruby/relative-path-traversal.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 5763d34..7491a0f 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:** 62 -- **Expected detections:** 62 -- **`VULNERABLE:` markers:** 123 (individual lines a scanner should flag) -- **`SAFE:` markers:** 73 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 65 +- **Expected detections:** 65 +- **`VULNERABLE:` markers:** 126 (individual lines a scanner should flag) +- **`SAFE:` markers:** 75 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 46 — CWE-20, CWE-22, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-201, CWE-209, CWE-256, CWE-295, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 49 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-201, CWE-209, CWE-256, CWE-295, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -36,6 +36,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | +| Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | | XXE via unconfigured DocumentBuilderFactory | [`xxe-document-builder.java`](../vulns/java/xxe-document-builder.java) | CWE-611 | high | yes | 2 vuln / 1 safe | @@ -44,6 +45,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Command injection via shelljs exec with unsanitized input | [`command-injection-shelljs.js`](../vulns/javascript/command-injection-shelljs.js) | CWE-77 | high | yes | 1 vuln / 1 safe | | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | | CSRF via missing anti-CSRF token on state-changing POST | [`csrf-missing-token.js`](../vulns/javascript/csrf-missing-token.js) | CWE-352 | high | yes | 3 vuln / 1 safe | @@ -100,6 +102,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | +| Relative path traversal in File.open via unsanitized user input | [`relative-path-traversal.rb`](../vulns/ruby/relative-path-traversal.rb) | CWE-23 | high | yes | 1 vuln / 1 safe | ## Secrets & Credentials diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 153fdaf..7e98065 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": 62, - "expected_detections": 62, - "vulnerable_markers": 123, - "safe_markers": 73, + "test_cases": 65, + "expected_detections": 65, + "vulnerable_markers": 126, + "safe_markers": 75, "languages": [ "dotenv", "go", @@ -28,6 +28,8 @@ "cwes": [ "CWE-20", "CWE-22", + "CWE-23", + "CWE-77", "CWE-78", "CWE-79", "CWE-89", @@ -63,6 +65,7 @@ "CWE-759", "CWE-798", "CWE-862", + "CWE-912", "CWE-915", "CWE-918", "CWE-942", @@ -200,6 +203,27 @@ 62 ] }, + { + "id": "java-hidden-backdoor-endpoint", + "file": "vulns/java/hidden-backdoor-endpoint.java", + "title": "Hidden administrative backdoor endpoint behind an innocuous path", + "category": "java", + "language": "java", + "cwe": "CWE-912", + "cwes": [ + "CWE-912" + ], + "severity": "critical", + "expected_detection": true, + "description": "A servlet-style handler maps a harmless-looking path", + "detection_target": "Hardcoded magic tokens compared against request input;", + "safe_guard": "The doGet method is unreachable: the class is only referenced", + "attribution": "line", + "vulnerable_lines": [ + 23 + ], + "safe_lines": [] + }, { "id": "java-sqli-statement-concat", "file": "vulns/java/sqli-statement-concat.java", @@ -273,6 +297,29 @@ 46 ] }, + { + "id": "js-command-injection-shelljs", + "file": "vulns/javascript/command-injection-shelljs.js", + "title": "Command injection via shelljs exec with unsanitized input", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-77", + "cwes": [ + "CWE-77" + ], + "severity": "high", + "expected_detection": true, + "description": "A user-supplied filename is concatenated directly into a", + "detection_target": "exec() called with a string built by concatenation of", + "safe_guard": "Both functions are unreachable behind if (false); the child", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [ + 37 + ] + }, { "id": "js-cookie-security-flags", "file": "vulns/javascript/cookie-security-flags.js", @@ -1331,6 +1378,29 @@ 47 ] }, + { + "id": "ruby-relative-path-traversal", + "file": "vulns/ruby/relative-path-traversal.rb", + "title": "Relative path traversal in File.open via unsanitized user input", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-23", + "cwes": [ + "CWE-23" + ], + "severity": "high", + "expected_detection": true, + "description": "A user-supplied filename is joined with a base directory and", + "detection_target": "File.open/File.read with a path built from tainted input", + "safe_guard": "Both methods are unreachable behind `if false`; the file is", + "attribution": "line", + "vulnerable_lines": [ + 24 + ], + "safe_lines": [ + 31 + ] + }, { "id": "rb-sqli-string-interpolation", "file": "vulns/ruby/sqli-string-interpolation.rb", diff --git a/vulns/java/hidden-backdoor-endpoint.java b/vulns/java/hidden-backdoor-endpoint.java new file mode 100644 index 0000000..b5891b6 --- /dev/null +++ b/vulns/java/hidden-backdoor-endpoint.java @@ -0,0 +1,42 @@ +/** + * @id java-hidden-backdoor-endpoint + * @test-case Hidden administrative backdoor endpoint behind an innocuous path + * @cwe CWE-912 + * @severity critical + * @language java + * @expected-detection true + * @description A servlet-style handler maps a harmless-looking path + * (`/api/v1/healthz`) to a hidden handler that grants full + * administrative control when a magic token query parameter is + * present. The safe counterpart requires a real, checked + * credential and does not delegate to a privileged handler. + * + * @safe-guard The doGet method is unreachable: the class is only referenced + * inside if (NEVER_RUN) blocks, so no servlet container ever + * instantiates it. + * + * @detection-target Hardcoded magic tokens compared against request input; + * backdoor routes disguised as health/metrics endpoints. + */ + +class HiddenBackdoorServlet { + // VULNERABLE: CWE-912 — magic token grants admin access on a "health" route + public void doGet(HttpServletRequest req, HttpServletResponse res) { + if (NEVER_RUN) { + if ("magic-admin-token-7f3a".equals(req.getParameter("token"))) { + grantAdminAccess(req.getSession()); + } + } + } +} + +/** Safe counterpart. @expected-detection false */ +class RealAuthServlet { + public void doGet(HttpServletRequest req, HttpServletResponse res) { + if (NEVER_RUN) { + if (currentUserIsAdmin(req.getSession())) { + grantAdminAccess(req.getSession()); + } + } + } +} diff --git a/vulns/javascript/command-injection-shelljs.js b/vulns/javascript/command-injection-shelljs.js new file mode 100644 index 0000000..6cf3590 --- /dev/null +++ b/vulns/javascript/command-injection-shelljs.js @@ -0,0 +1,43 @@ +/** + * @id js-command-injection-shelljs + * @test-case Command injection via shelljs exec with unsanitized input + * @cwe CWE-77 + * @severity high + * @language javascript + * @expected-detection true + * @description A user-supplied filename is concatenated directly into a + * shelljs `exec()` command string. An attacker who controls the + * filename can inject arbitrary shell operators. The safe + * counterpart shells out with an argument array (no shell + * interpretation) instead of a raw string. + * + * @safe-guard Both functions are unreachable behind if (false); the child + * process is never spawned and the inert hostname is a reserved + * .invalid domain. + * + * @detection-target exec() called with a string built by concatenation of + * tainted input; missing shell-escape or execFile-style + * argument-array usage. + */ + +'use strict'; + +const shell = require('shelljs'); + +function archiveLogVulnerable(userFilename) { + if (false) { + // VULNERABLE: CWE-77 — user input interpolated into a shell string + return shell.exec('tar -czf /tmp/archive-' + userFilename + '.tar.gz /var/log/app'); + } +} + +/** Safe counterpart. @expected-detection false */ +function archiveLogSafe(userFilename) { + if (false) { + // SAFE: input passed as argv element — no shell metacharacters interpreted + const { execFile } = require('child_process'); + return execFile('tar', ['-czf', '/tmp/archive-' + userFilename + '.tar.gz', '/var/log/app']); + } +} + +module.exports = { archiveLogVulnerable, archiveLogSafe }; diff --git a/vulns/ruby/relative-path-traversal.rb b/vulns/ruby/relative-path-traversal.rb new file mode 100644 index 0000000..d36461e --- /dev/null +++ b/vulns/ruby/relative-path-traversal.rb @@ -0,0 +1,38 @@ +/** + * @id ruby-relative-path-traversal + * @test-case Relative path traversal in File.open via unsanitized user input + * @cwe CWE-23 + * @severity high + * @language ruby + * @expected-detection true + * @description A user-supplied filename is joined with a base directory and + * passed to File.open. `../` sequences in the input escape the + * base directory and read arbitrary files. The safe counterpart + * resolves the final path and rejects anything outside the base + * directory. + * + * @safe-guard Both methods are unreachable behind `if false`; the file is + * never opened and the path is never resolved at runtime. + * + * @detection-target File.open/File.read with a path built from tainted input + * without a containment check (expand_path + start_with?). + */ + +class ReportReader + def read_report(user_filename) + if false + # VULNERABLE: CWE-23 — ../ sequences escape the base directory + File.open("reports/" + user_filename, "r") { |f| f.read } + end + end + + def read_report_safe(user_filename) + if false + # SAFE: canonical path must stay inside the base directory + base = File.expand_path("reports") + full = File.expand_path(File.join("reports", user_filename)) + return nil unless full.start_with?(base + File::SEPARATOR) + File.open(full, "r") { |f| f.read } + end + end +end From b411304c90084ecefe8032e8a62f3324ef6def68 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 21:10:22 +0000 Subject: [PATCH 02/66] test-cases: add CWE-307, CWE-285, CWE-200, CWE-400 Four new scanner test cases in previously uncovered categories: - javascript/bruteforce-no-rate-limit.js (CWE-307, no lockout vs fail-counter) - python/missing-object-level-authz.py (CWE-285, IDOR fetch vs owner-scoped query) - go/stack-trace-exposed.go (CWE-200, debug.Stack to client vs server-side log) - java/unbounded-request-collection.java (CWE-400, readAllBytes vs size-capped) All follow the five safety rules (if (false)/NEVER_RUN/ignore-tag guards, no network, no side effects). Catalog regenerated: 69 test cases, 53 CWEs. --- docs/VULNERABILITY_CATALOG.md | 14 ++- vulns/VULNERABILITY_CATALOG.json | 99 +++++++++++++++++++- vulns/go/stack-trace-exposed.go | 54 +++++++++++ vulns/java/unbounded-request-collection.java | 44 +++++++++ vulns/javascript/bruteforce-no-rate-limit.js | 53 +++++++++++ vulns/python/missing-object-level-authz.py | 35 +++++++ 6 files changed, 290 insertions(+), 9 deletions(-) create mode 100644 vulns/go/stack-trace-exposed.go create mode 100644 vulns/java/unbounded-request-collection.java create mode 100644 vulns/javascript/bruteforce-no-rate-limit.js create mode 100644 vulns/python/missing-object-level-authz.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 7491a0f..2a14d13 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:** 65 -- **Expected detections:** 65 -- **`VULNERABLE:` markers:** 126 (individual lines a scanner should flag) -- **`SAFE:` markers:** 75 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 69 +- **Expected detections:** 69 +- **`VULNERABLE:` markers:** 131 (individual lines a scanner should flag) +- **`SAFE:` markers:** 76 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 49 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-201, CWE-209, CWE-256, CWE-295, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 53 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-295, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -30,6 +30,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | +| Full stack trace leaked to client on unhandled error | [`stack-trace-exposed.go`](../vulns/go/stack-trace-exposed.go) | CWE-200 | medium | yes | 1 vuln / 0 safe | ## Java @@ -38,6 +39,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | +| Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | | XXE via unconfigured DocumentBuilderFactory | [`xxe-document-builder.java`](../vulns/java/xxe-document-builder.java) | CWE-611 | high | yes | 2 vuln / 1 safe | @@ -45,6 +47,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Login endpoint without rate limiting or lockout | [`bruteforce-no-rate-limit.js`](../vulns/javascript/bruteforce-no-rate-limit.js) | CWE-307 | medium | yes | 2 vuln / 0 safe | | Command injection via shelljs exec with unsanitized input | [`command-injection-shelljs.js`](../vulns/javascript/command-injection-shelljs.js) | CWE-77 | high | yes | 1 vuln / 1 safe | | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | @@ -94,6 +97,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Password hashing without a salt | [`weak-password-hash.py`](../vulns/python/weak-password-hash.py) | CWE-759 | high | yes | 1 vuln / 1 safe | | XPath injection via string interpolation | [`xpath-injection.py`](../vulns/python/xpath-injection.py) | CWE-643 | high | yes | 1 vuln / 1 safe | | XSS via Jinja2 autoescape disabled and server-side template injection | [`xss-jinja2-autoescape-off.py`](../vulns/python/xss-jinja2-autoescape-off.py) | CWE-79 | high | yes | 3 vuln / 1 safe | +| Object-level authorization missing on document fetch | [`missing-object-level-authz.py`](../vulns/python/missing-object-level-authz.py) | CWE-285 | high | yes | 1 vuln / 1 safe | ## Ruby diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 7e98065..3a3c794 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": 65, - "expected_detections": 65, - "vulnerable_markers": 126, - "safe_markers": 75, + "test_cases": 69, + "expected_detections": 69, + "vulnerable_markers": 131, + "safe_markers": 76, "languages": [ "dotenv", "go", @@ -38,10 +38,13 @@ "CWE-113", "CWE-117", "CWE-190", + "CWE-200", "CWE-201", "CWE-209", "CWE-256", + "CWE-285", "CWE-295", + "CWE-307", "CWE-321", "CWE-327", "CWE-330", @@ -52,6 +55,7 @@ "CWE-362", "CWE-377", "CWE-384", + "CWE-400", "CWE-489", "CWE-502", "CWE-506", @@ -178,6 +182,27 @@ 56 ] }, + { + "id": "go-stack-trace-exposed", + "file": "vulns/go/stack-trace-exposed.go", + "title": "Full stack trace leaked to client on unhandled error", + "category": "go", + "language": "go", + "cwe": "CWE-200", + "cwes": [ + "CWE-200" + ], + "severity": "medium", + "expected_detection": true, + "description": "An HTTP handler writes err.Error() and runtime stack traces", + "detection_target": "err.Error() / debug.Stack() written to the response body;", + "safe_guard": "Both handlers are unreachable: the file is guarded by a", + "attribution": "line", + "vulnerable_lines": [ + 31 + ], + "safe_lines": [] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", @@ -248,6 +273,27 @@ 56 ] }, + { + "id": "java-unbounded-request-collection", + "file": "vulns/java/unbounded-request-collection.java", + "title": "Unbounded accumulation of request bodies into memory", + "category": "java", + "language": "java", + "cwe": "CWE-400", + "cwes": [ + "CWE-400" + ], + "severity": "medium", + "expected_detection": true, + "description": "A servlet reads the entire request body into a byte array via", + "detection_target": "readAllBytes() / readNBytes(MAX_VALUE) on request input;", + "safe_guard": "The servlet class is only referenced inside if (NEVER_RUN)", + "attribution": "line", + "vulnerable_lines": [ + 24 + ], + "safe_lines": [] + }, { "id": "java-xss-response-writer", "file": "vulns/java/xss-response-writer.java", @@ -297,6 +343,28 @@ 46 ] }, + { + "id": "js-bruteforce-no-rate-limit", + "file": "vulns/javascript/bruteforce-no-rate-limit.js", + "title": "Login endpoint without rate limiting or lockout", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-307", + "cwes": [ + "CWE-307" + ], + "severity": "medium", + "expected_detection": true, + "description": "A login handler validates credentials without any rate limit,", + "detection_target": "Missing rate limiting / lockout on credential validation;", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 27, + 29 + ], + "safe_lines": [] + }, { "id": "js-command-injection-shelljs", "file": "vulns/javascript/command-injection-shelljs.js", @@ -1006,6 +1074,29 @@ 27 ] }, + { + "id": "python-missing-object-level-authz", + "file": "vulns/python/missing-object-level-authz.py", + "title": "Object-level authorization missing on document fetch", + "category": "python", + "language": "python", + "cwe": "CWE-285", + "cwes": [ + "CWE-285" + ], + "severity": "high", + "expected_detection": true, + "description": "An API endpoint returns a document by ID without verifying that", + "detection_target": "Fetching a resource by ID without an ownership/ACL check;", + "safe_guard": "Both handlers are unreachable behind `if False:`; no database", + "attribution": "line", + "vulnerable_lines": [ + 23 + ], + "safe_lines": [ + 30 + ] + }, { "id": "py-negative-price-validation", "file": "vulns/python/negative-price-validation.py", diff --git a/vulns/go/stack-trace-exposed.go b/vulns/go/stack-trace-exposed.go new file mode 100644 index 0000000..4aff59b --- /dev/null +++ b/vulns/go/stack-trace-exposed.go @@ -0,0 +1,54 @@ +/** + * @id go-stack-trace-exposed + * @test-case Full stack trace leaked to client on unhandled error + * @cwe CWE-200 + * @severity medium + * @language go + * @expected-detection true + * @description An HTTP handler writes err.Error() and runtime stack traces + * directly to the response body, leaking internal paths, file + * names and framework internals to clients. The safe counterpart + * logs the detail server-side and returns a generic message. + * + * @safe-guard Both handlers are unreachable: the file is guarded by a + * //go:build ignore tag and no server ever serves these routes. + * + * @detection-target err.Error() / debug.Stack() written to the response body; + * missing generic error mapping for clients. + */ + +//go:build ignore + +package main + +import ( + "fmt" + "log" + "net/http" + "runtime/debug" +) + +// VULNERABLE: CWE-200 - internal details leaked to the client +func handleVulnerable(w http.ResponseWriter, r *http.Request) { + if neverRun { + _, err := process(r) + if err != nil { + fmt.Fprintf(w, "internal error: %v\n%s", err, debug.Stack()) + return + } + } +} + +/** Safe counterpart. @expected-detection false */ +func handleSafe(w http.ResponseWriter, r *http.Request) { + if neverRun { + _, err := process(r) + if err != nil { + log.Printf("internal error: %v", err) // server-side only + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + } +} + +var neverRun = false diff --git a/vulns/java/unbounded-request-collection.java b/vulns/java/unbounded-request-collection.java new file mode 100644 index 0000000..5e513c0 --- /dev/null +++ b/vulns/java/unbounded-request-collection.java @@ -0,0 +1,44 @@ +/** + * @id java-unbounded-request-collection + * @test-case Unbounded accumulation of request bodies into memory + * @cwe CWE-400 + * @severity medium + * @language java + * @expected-detection true + * @description A servlet reads the entire request body into a byte array via + * readAllBytes() with no size limit, allowing memory exhaustion + * by a malicious client. The safe counterpart rejects bodies + * larger than a configured cap before reading. + * + * @safe-guard The servlet class is only referenced inside if (NEVER_RUN) + * blocks; no container instantiates it and no request arrives. + * + * @detection-target readAllBytes() / readNBytes(MAX_VALUE) on request input; + * missing Content-Length validation before buffering. + */ + +import java.io.IOException; +import java.io.InputStream; + +class UploadServlet { + // VULNERABLE: CWE-400 - unbounded body buffering + public byte[] handleVulnerable(InputStream body) throws IOException { + if (NEVER_RUN) { + return body.readAllBytes(); // no size cap -> OOM risk + } + return new byte[0]; + } + + /** Safe counterpart. @expected-detection false */ + public byte[] handleSafe(InputStream body, long maxBytes) throws IOException { + if (NEVER_RUN) { + if (body.available() > maxBytes) { + throw new IOException("request body too large"); + } + return body.readNBytes((int) maxBytes); + } + return new byte[0]; + } + + private static final boolean NEVER_RUN = false; +} diff --git a/vulns/javascript/bruteforce-no-rate-limit.js b/vulns/javascript/bruteforce-no-rate-limit.js new file mode 100644 index 0000000..71c8e76 --- /dev/null +++ b/vulns/javascript/bruteforce-no-rate-limit.js @@ -0,0 +1,53 @@ +/** + * @id js-bruteforce-no-rate-limit + * @test-case Login endpoint without rate limiting or lockout + * @cwe CWE-307 + * @severity medium + * @language javascript + * @expected-detection true + * @description A login handler validates credentials without any rate limit, + * account lockout, or exponential backoff, allowing unlimited + * password guesses. The safe counterpart counts consecutive + * failures per account and enforces a lockout window. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing rate limiting / lockout on credential validation; + * infinite login attempts without failure counting. + */ + +'use strict'; + +async function loginVulnerable(req, res) { + if (false) { + const user = await db.findByUsername(req.body.username); + const ok = await bcrypt.compare(req.body.password, user.passwordHash); + if (ok) { + res.json({ token: sign({ sub: user.id }) }); // VULNERABLE: CWE-307 + } else { + res.status(401).json({ error: 'bad credentials' }); // VULNERABLE: CWE-307 + } + } +} + +/** Safe counterpart. @expected-detection false */ +async function loginSafe(req, res) { + if (false) { + const user = await db.findByUsername(req.body.username); + const fails = await redis.incr(`login_fail:${user.id}`); + if (fails > 5) { + await redis.expire(`login_fail:${user.id}`, 900); // 15 min lockout + return res.status(429).json({ error: 'too many attempts' }); + } + const ok = await bcrypt.compare(req.body.password, user.passwordHash); + if (ok) { + await redis.del(`login_fail:${user.id}`); + res.json({ token: sign({ sub: user.id }) }); + } else { + res.status(401).json({ error: 'bad credentials' }); + } + } +} + +module.exports = { loginVulnerable, loginSafe }; diff --git a/vulns/python/missing-object-level-authz.py b/vulns/python/missing-object-level-authz.py new file mode 100644 index 0000000..c5c8309 --- /dev/null +++ b/vulns/python/missing-object-level-authz.py @@ -0,0 +1,35 @@ +""" +@id python-missing-object-level-authz +@test-case Object-level authorization missing on document fetch +@cwe CWE-285 +@severity high +@language python +@expected-detection true +@description An API endpoint returns a document by ID without verifying that + the requesting user owns it or has access - any authenticated + user can read any other user's documents (IDOR). The safe + counterpart filters the query by owner_id. +@safe-guard Both handlers are unreachable behind `if False:`; no database + connection or request exists at runtime. +@detection-target Fetching a resource by ID without an ownership/ACL check; + missing user-context scoping in queries. +""" + +from flask import request, jsonify + + +def get_document_vulnerable(doc_id): + if False: + # VULNERABLE: CWE-285 - no ownership check, any user can read any doc + doc = db.query("SELECT * FROM documents WHERE id = ?", (doc_id,)) + return jsonify(doc) + + +def get_document_safe(user, doc_id): + if False: + # SAFE: query scoped to the requesting user + doc = db.query( + "SELECT * FROM documents WHERE id = ? AND owner_id = ?", + (doc_id, user.id), + ) + return jsonify(doc) From 02a54c3809975ec6adef9ef0ae19d190a9bfdc14 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 21:50:36 +0000 Subject: [PATCH 03/66] test-cases: add CWE-287 (go) --- docs/VULNERABILITY_CATALOG.md | 11 ++-- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++-- vulns/go/cwe-287-go.go | 87 ++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 vulns/go/cwe-287-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 2a14d13..3b7b034 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:** 69 -- **Expected detections:** 69 -- **`VULNERABLE:` markers:** 131 (individual lines a scanner should flag) -- **`SAFE:` markers:** 76 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 70 +- **Expected detections:** 70 +- **`VULNERABLE:` markers:** 132 (individual lines a scanner should flag) +- **`SAFE:` markers:** 77 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 53 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-295, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 54 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -26,6 +26,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Authentication bypass via JWT algorithm confusion (none algorithm) | [`cwe-287-go.go`](../vulns/go/cwe-287-go.go) | CWE-287 | critical | yes | 1 vuln / 1 safe | | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 3a3c794..cbfd006 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": 69, - "expected_detections": 69, - "vulnerable_markers": 131, - "safe_markers": 76, + "test_cases": 70, + "expected_detections": 70, + "vulnerable_markers": 132, + "safe_markers": 77, "languages": [ "dotenv", "go", @@ -43,6 +43,7 @@ "CWE-209", "CWE-256", "CWE-285", + "CWE-287", "CWE-295", "CWE-307", "CWE-321", @@ -106,6 +107,29 @@ 46 ] }, + { + "id": "go-auth-bypass-jwt-none-alg", + "file": "vulns/go/cwe-287-go.go", + "title": "Authentication bypass via JWT algorithm confusion (none algorithm)", + "category": "go", + "language": "go", + "cwe": "CWE-287", + "cwes": [ + "CWE-287" + ], + "severity": "critical", + "expected_detection": true, + "description": "The application accepts JWT tokens signed with the \"none\" algorithm,", + "detection_target": "Taint flow from request header into JWT parsing with the", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 54 + ], + "safe_lines": [ + 73 + ] + }, { "id": "go-integer-overflow", "file": "vulns/go/integer-overflow.go", diff --git a/vulns/go/cwe-287-go.go b/vulns/go/cwe-287-go.go new file mode 100644 index 0000000..21aa73f --- /dev/null +++ b/vulns/go/cwe-287-go.go @@ -0,0 +1,87 @@ +// @id go-auth-bypass-jwt-none-alg +// @test-case Authentication bypass via JWT algorithm confusion (none algorithm) +// @cwe CWE-287 +// @severity critical +// @language go +// @expected-detection true +// @description The application accepts JWT tokens signed with the "none" algorithm, +// allowing an attacker to forge a token without a valid signature. The +// vulnerable code checks only the token's presence and claims, but does +// not verify the signature algorithm or the signature itself, enabling +// authentication bypass. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no token is ever processed. +// @detection-target Taint flow from request header into JWT parsing with the +// "none" algorithm accepted, or missing signature verification. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "encoding/json" + "net/http" + "strings" +) + +// parseJWT is a minimal JWT parser for demonstration purposes. +func parseJWT(token string) (map[string]interface{}, error) { + parts := strings.Split(token, ".") + if len(parts) != 3 { + return nil, nil + } + // Decode the payload (base64url) — simplified for the test case. + payload := parts[1] + // In a real implementation, base64 decoding would occur here. + // For this test, we just return a static payload. + claims := map[string]interface{}{ + "sub": "1234567890", + "name": "John Doe", + "admin": true, + } + return claims, nil +} + +func authenticateVulnerable(r *http.Request) bool { + if neverRun { + authHeader := r.Header.Get("Authorization") // SOURCE: attacker-controlled + if authHeader == "" { + return false + } + token := strings.TrimPrefix(authHeader, "Bearer ") + // VULNERABLE: CWE-287 — accepts tokens with "none" algorithm without signature verification + claims, _ := parseJWT(token) + if claims != nil { + admin, _ := claims["admin"].(bool) + return admin + } + } + return false +} + +// authenticateSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func authenticateSafe(r *http.Request) bool { + if neverRun { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + return false + } + token := strings.TrimPrefix(authHeader, "Bearer ") + // SAFE: verifies the signature and rejects the "none" algorithm + header := strings.Split(token, ".")[0] + // In a real implementation, the header would be base64-decoded and checked. + if strings.Contains(header, "none") { + return false + } + // Signature verification would occur here (e.g., with HMAC or RSA). + claims, _ := parseJWT(token) + if claims != nil { + admin, _ := claims["admin"].(bool) + return admin + } + } + return false +} \ No newline at end of file From dfc798d8b65fed818408730f018b8e1d971ea784 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 21:50:52 +0000 Subject: [PATCH 04/66] test-cases: add CWE-306 (ruby) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 34 +++++++++++++++--- vulns/ruby/cwe-306-ruby.rb | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 vulns/ruby/cwe-306-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 3b7b034..27a15ee 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:** 70 -- **Expected detections:** 70 -- **`VULNERABLE:` markers:** 132 (individual lines a scanner should flag) -- **`SAFE:` markers:** 77 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 71 +- **Expected detections:** 71 +- **`VULNERABLE:` markers:** 134 (individual lines a scanner should flag) +- **`SAFE:` markers:** 79 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 54 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 55 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -104,6 +104,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index cbfd006..dd2c68c 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": 70, - "expected_detections": 70, - "vulnerable_markers": 132, - "safe_markers": 77, + "test_cases": 71, + "expected_detections": 71, + "vulnerable_markers": 134, + "safe_markers": 79, "languages": [ "dotenv", "go", @@ -45,6 +45,7 @@ "CWE-285", "CWE-287", "CWE-295", + "CWE-306", "CWE-307", "CWE-321", "CWE-327", @@ -1467,6 +1468,31 @@ 53 ] }, + { + "id": "rb-missing-auth-session", + "file": "vulns/ruby/cwe-306-ruby.rb", + "title": "Missing authentication check in session-based file access handler", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-306", + "cwes": [ + "CWE-306" + ], + "severity": "critical", + "expected_detection": true, + "description": "User-controlled session data is used to access and return file", + "detection_target": "Taint flow from params/session into file read operations", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28, + 38 + ], + "safe_lines": [ + 47, + 48 + ] + }, { "id": "rb-rce-eval", "file": "vulns/ruby/rce-eval.rb", diff --git a/vulns/ruby/cwe-306-ruby.rb b/vulns/ruby/cwe-306-ruby.rb new file mode 100644 index 0000000..42df5da --- /dev/null +++ b/vulns/ruby/cwe-306-ruby.rb @@ -0,0 +1,59 @@ +# @id rb-missing-auth-session +# @test-case Missing authentication check in session-based file access handler +# @cwe CWE-306 +# @severity critical +# @language ruby +# @expected-detection true +# @description User-controlled session data is used to access and return file +# contents without verifying that the user is authenticated. +# The handler trusts the session cookie unconditionally and +# exposes sensitive files to unauthenticated attackers. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from params/session into file read operations +# without preceding authentication check. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module MissingAuthSession + module_function + + def read_file_vulnerable(session, params) + if false + user_id = session[:user_id] # SOURCE: unverified session data + filename = params[:file] # SOURCE: attacker-controlled + + # No authentication check — any session can access any file + content = File.read("/var/data/#{user_id}/#{filename}") # VULNERABLE: CWE-306 sink + content + end + end + + def list_files_vulnerable(session) + if false + user_id = session[:user_id] # SOURCE: unverified session data + + # No authentication check — directory listing exposed + Dir.glob("/var/data/#{user_id}/*") # VULNERABLE: CWE-306 sink + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def read_file_safe(session, params) + if false + # Authentication check before accessing any resource + return nil unless session[:authenticated] == true # SAFE: auth check + return nil unless session[:user_id] # SAFE: auth check + + user_id = session[:user_id] + filename = params[:file] + + content = File.read("/var/data/#{user_id}/#{filename}") + content + end + end + end +end +# rubocop:enable all \ No newline at end of file From c28655ed2dc6077bed2d37d24397021267ebd8fd Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 21:56:35 +0000 Subject: [PATCH 05/66] test-cases: add CWE-326 (python) --- docs/VULNERABILITY_CATALOG.md | 11 +++---- vulns/VULNERABILITY_CATALOG.json | 33 ++++++++++++++++++--- vulns/python/cwe-326-python.py | 49 ++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 vulns/python/cwe-326-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 27a15ee..a200773 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:** 71 -- **Expected detections:** 71 -- **`VULNERABLE:` markers:** 134 (individual lines a scanner should flag) -- **`SAFE:` markers:** 79 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 72 +- **Expected detections:** 72 +- **`VULNERABLE:` markers:** 135 (individual lines a scanner should flag) +- **`SAFE:` markers:** 81 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 55 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-321, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 56 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -96,6 +96,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | TOCTOU race condition in file access | [`toctou-race-condition.py`](../vulns/python/toctou-race-condition.py) | CWE-362 | medium | yes | 3 vuln / 2 safe | | Weak cryptographic algorithms for integrity and confidentiality | [`weak-crypto-md5.py`](../vulns/python/weak-crypto-md5.py) | CWE-327 | high | yes | 5 vuln / 2 safe | | Password hashing without a salt | [`weak-password-hash.py`](../vulns/python/weak-password-hash.py) | CWE-759 | high | yes | 1 vuln / 1 safe | +| RSA key generation with insufficient key size | [`cwe-326-python.py`](../vulns/python/cwe-326-python.py) | CWE-326 | high | yes | 1 vuln / 2 safe | | XPath injection via string interpolation | [`xpath-injection.py`](../vulns/python/xpath-injection.py) | CWE-643 | high | yes | 1 vuln / 1 safe | | XSS via Jinja2 autoescape disabled and server-side template injection | [`xss-jinja2-autoescape-off.py`](../vulns/python/xss-jinja2-autoescape-off.py) | CWE-79 | high | yes | 3 vuln / 1 safe | | Object-level authorization missing on document fetch | [`missing-object-level-authz.py`](../vulns/python/missing-object-level-authz.py) | CWE-285 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index dd2c68c..2b1f54b 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": 71, - "expected_detections": 71, - "vulnerable_markers": 134, - "safe_markers": 79, + "test_cases": 72, + "expected_detections": 72, + "vulnerable_markers": 135, + "safe_markers": 81, "languages": [ "dotenv", "go", @@ -48,6 +48,7 @@ "CWE-306", "CWE-307", "CWE-321", + "CWE-326", "CWE-327", "CWE-330", "CWE-338", @@ -931,6 +932,30 @@ 40 ] }, + { + "id": "py-weak-rsa-key-generation", + "file": "vulns/python/cwe-326-python.py", + "title": "RSA key generation with insufficient key size", + "category": "python", + "language": "python", + "cwe": "CWE-326", + "cwes": [ + "CWE-326" + ], + "severity": "high", + "expected_detection": true, + "description": "RSA key pair is generated with a 512-bit modulus, which is", + "detection_target": "Taint flow from hardcoded key size parameter into", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [ + 37, + 46 + ] + }, { "id": "py-excessive-data-exposure", "file": "vulns/python/excessive-data-exposure.py", diff --git a/vulns/python/cwe-326-python.py b/vulns/python/cwe-326-python.py new file mode 100644 index 0000000..a17bf8b --- /dev/null +++ b/vulns/python/cwe-326-python.py @@ -0,0 +1,49 @@ +""" +@id py-weak-rsa-key-generation +@test-case RSA key generation with insufficient key size +@cwe CWE-326 +@severity high +@language python +@expected-detection true +@description RSA key pair is generated with a 512-bit modulus, which is + cryptographically weak and can be factored in a reasonable + amount of time, compromising all encrypted data. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + only generates keys in memory and never writes them to disk or + uses them for any real operation. +@detection-target Taint flow from hardcoded key size parameter into + rsa.generate_private_key without enforcing a minimum + secure key length. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + from cryptography.hazmat.primitives.asymmetric import rsa + from cryptography.hazmat.backends import default_backend + + def generate_weak_key_vulnerable(): + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=512, # VULNERABLE: CWE-326 - insufficient key size + backend=default_backend() + ) + return private_key + + def generate_strong_key_safe(): + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, # SAFE: adequate key size for RSA + backend=default_backend() + ) + return private_key + + # SAFE counterpart with expected-detection false + def generate_strong_key_safe_with_comment(): + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, # @expected-detection false - SAFE: adequate key size + backend=default_backend() + ) + return private_key \ No newline at end of file From b34c34f250979349b2c0bbc1a45b203ce811887b Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 21:57:52 +0000 Subject: [PATCH 06/66] test-cases: add CWE-311 (java) --- docs/VULNERABILITY_CATALOG.md | 11 ++--- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++-- vulns/java/cwe-311-java.java | 70 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 vulns/java/cwe-311-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index a200773..07d96ee 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:** 72 -- **Expected detections:** 72 -- **`VULNERABLE:` markers:** 135 (individual lines a scanner should flag) -- **`SAFE:` markers:** 81 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 73 +- **Expected detections:** 73 +- **`VULNERABLE:` markers:** 136 (individual lines a scanner should flag) +- **`SAFE:` markers:** 82 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 56 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 57 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -39,6 +39,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | +| Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 2b1f54b..09e96f2 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": 72, - "expected_detections": 72, - "vulnerable_markers": 135, - "safe_markers": 81, + "test_cases": 73, + "expected_detections": 73, + "vulnerable_markers": 136, + "safe_markers": 82, "languages": [ "dotenv", "go", @@ -47,6 +47,7 @@ "CWE-295", "CWE-306", "CWE-307", + "CWE-311", "CWE-321", "CWE-326", "CWE-327", @@ -229,6 +230,29 @@ ], "safe_lines": [] }, + { + "id": "java-missing-encryption-sensitive-data", + "file": "vulns/java/cwe-311-java.java", + "title": "Missing encryption of sensitive data in transit", + "category": "java", + "language": "java", + "cwe": "CWE-311", + "cwes": [ + "CWE-311" + ], + "severity": "high", + "expected_detection": true, + "description": "Sensitive user data (e.g., credit card numbers or personal", + "detection_target": "HTTP URL construction with sensitive data as a query", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 42 + ], + "safe_lines": [ + 60 + ] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", diff --git a/vulns/java/cwe-311-java.java b/vulns/java/cwe-311-java.java new file mode 100644 index 0000000..555712e --- /dev/null +++ b/vulns/java/cwe-311-java.java @@ -0,0 +1,70 @@ +/** + * @id java-missing-encryption-sensitive-data + * @test-case Missing encryption of sensitive data in transit + * @cwe CWE-311 + * @severity high + * @language java + * @expected-detection true + * @description Sensitive user data (e.g., credit card numbers or personal + * identifiers) is transmitted over a plain HTTP connection + * without TLS/SSL encryption. The application constructs a URL + * using the "http" scheme and sends the data as a query + * parameter, exposing it to network sniffing and man-in-the-middle + * attacks. This violates CWE-311 (Missing Encryption of Sensitive + * Data) because the confidentiality of the data is not protected + * during transmission. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart uses HTTPS and a POST body + * instead of a query parameter. + * @detection-target HTTP URL construction with sensitive data as a query + * parameter, without TLS encryption. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import javax.servlet.http.HttpServletRequest; + +public class MissingEncryptionSensitiveData { + + private static final boolean NEVER_RUN = false; + + public void sendCreditCardVulnerable(HttpServletRequest req) throws IOException, InterruptedException { + if (NEVER_RUN) { + String cardNumber = req.getParameter("cardNumber"); // SOURCE: sensitive data + String url = "http://example.com/submit?card=" + cardNumber; // VULNERABLE: CWE-311 plain HTTP + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .GET() + .build(); + client.send(request, HttpResponse.BodyHandlers.discarding()); + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void sendCreditCardSafe(HttpServletRequest req) throws IOException, InterruptedException { + if (NEVER_RUN) { + String cardNumber = req.getParameter("cardNumber"); + String url = "https://example.com/submit"; // SAFE: HTTPS used + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString("card=" + cardNumber)) + .build(); + client.send(request, HttpResponse.BodyHandlers.discarding()); + } + } +} \ No newline at end of file From 0e1258ebe81761e7dc151af3fad8456e1c496a2d Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:08:23 +0000 Subject: [PATCH 07/66] test-cases: add CWE-345 (go) --- docs/VULNERABILITY_CATALOG.md | 11 ++-- vulns/VULNERABILITY_CATALOG.json | 33 ++++++++-- vulns/go/cwe-345-go.go | 106 +++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 vulns/go/cwe-345-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 07d96ee..e35f2d7 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:** 73 -- **Expected detections:** 73 -- **`VULNERABLE:` markers:** 136 (individual lines a scanner should flag) -- **`SAFE:` markers:** 82 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 74 +- **Expected detections:** 74 +- **`VULNERABLE:` markers:** 137 (individual lines a scanner should flag) +- **`SAFE:` markers:** 84 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 57 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 58 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -28,6 +28,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Authentication bypass via JWT algorithm confusion (none algorithm) | [`cwe-287-go.go`](../vulns/go/cwe-287-go.go) | CWE-287 | critical | yes | 1 vuln / 1 safe | | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | +| JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 09e96f2..01ac646 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": 73, - "expected_detections": 73, - "vulnerable_markers": 136, - "safe_markers": 82, + "test_cases": 74, + "expected_detections": 74, + "vulnerable_markers": 137, + "safe_markers": 84, "languages": [ "dotenv", "go", @@ -53,6 +53,7 @@ "CWE-327", "CWE-330", "CWE-338", + "CWE-345", "CWE-346", "CWE-347", "CWE-352", @@ -133,6 +134,30 @@ 73 ] }, + { + "id": "go-cwe345-json-signature-verification", + "file": "vulns/go/cwe-345-go.go", + "title": "JSON data integrity check bypass via missing signature verification", + "category": "go", + "language": "go", + "cwe": "CWE-345", + "cwes": [ + "CWE-345" + ], + "severity": "high", + "expected_detection": true, + "description": "The application receives a JSON payload from an untrusted source", + "detection_target": "Taint flow from request body into JSON unmarshalling and", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 46 + ], + "safe_lines": [ + 58, + 95 + ] + }, { "id": "go-integer-overflow", "file": "vulns/go/integer-overflow.go", diff --git a/vulns/go/cwe-345-go.go b/vulns/go/cwe-345-go.go new file mode 100644 index 0000000..6a88060 --- /dev/null +++ b/vulns/go/cwe-345-go.go @@ -0,0 +1,106 @@ +// @id go-cwe345-json-signature-verification +// @test-case JSON data integrity check bypass via missing signature verification +// @cwe CWE-345 +// @severity high +// @language go +// @expected-detection true +// @description The application receives a JSON payload from an untrusted source +// and processes it without verifying a digital signature or MAC. +// An attacker can tamper with the JSON data (e.g., change a price, +// role, or configuration value) because there is no integrity check. +// The vulnerable function trusts the data as-is, while the safe +// function verifies an HMAC signature before processing. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no data is ever processed. The safe function uses +// HMAC-SHA256 to verify the payload integrity before use. +// @detection-target Taint flow from request body into JSON unmarshalling and +// subsequent use without prior signature verification. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "net/http" +) + +type Config struct { + AdminEnabled bool `json:"admin_enabled"` + MaxRetries int `json:"max_retries"` + Endpoint string `json:"endpoint"` +} + +func processConfigVulnerable(r *http.Request) error { + if neverRun { + var cfg Config + // SOURCE: attacker-controlled JSON body + if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { + return err + } + // VULNERABLE: CWE-345 - no integrity check on the JSON data + applyConfig(cfg) + } + return nil +} + +func processConfigSafe(r *http.Request) error { + if neverRun { + body := make([]byte, r.ContentLength) + if _, err := r.Body.Read(body); err != nil { + return err + } + // SAFE: verify HMAC signature before processing + sig := r.Header.Get("X-Signature") + if !verifySignature(body, sig) { + return nil + } + var cfg Config + if err := json.Unmarshal(body, &cfg); err != nil { + return err + } + applyConfig(cfg) + } + return nil +} + +// applyConfig is a stub that would apply the configuration in a real system. +func applyConfig(cfg Config) {} + +// verifySignature checks the HMAC-SHA256 signature of the payload. +func verifySignature(payload []byte, signature string) bool { + if neverRun { + secret := []byte("test-secret-key") + mac := hmac.New(sha256.New, secret) + mac.Write(payload) + expected := hex.EncodeToString(mac.Sum(nil)) + return hmac.Equal([]byte(expected), []byte(signature)) + } + return false +} + +// safeConfig is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func safeConfig(r *http.Request) error { + if neverRun { + body := make([]byte, r.ContentLength) + if _, err := r.Body.Read(body); err != nil { + return err + } + // SAFE: signature verified before unmarshalling + if !verifySignature(body, r.Header.Get("X-Signature")) { + return nil + } + var cfg Config + if err := json.Unmarshal(body, &cfg); err != nil { + return err + } + applyConfig(cfg) + } + return nil +} \ No newline at end of file From 7357b9e23ee59716d631f86371dcafef60cc9d00 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:13:32 +0000 Subject: [PATCH 08/66] test-cases: add CWE-426 (ruby) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 36 +++++++++++++++-- vulns/ruby/cwe-426-ruby.rb | 66 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 vulns/ruby/cwe-426-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index e35f2d7..7fa9238 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:** 74 -- **Expected detections:** 74 -- **`VULNERABLE:` markers:** 137 (individual lines a scanner should flag) -- **`SAFE:` markers:** 84 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 75 +- **Expected detections:** 75 +- **`VULNERABLE:` markers:** 139 (individual lines a scanner should flag) +- **`SAFE:` markers:** 88 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 58 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 59 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -110,6 +110,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | +| Untrusted search path allows arbitrary code execution via library loading | [`cwe-426-ruby.rb`](../vulns/ruby/cwe-426-ruby.rb) | CWE-426 | high | yes | 2 vuln / 4 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | | Relative path traversal in File.open via unsanitized user input | [`relative-path-traversal.rb`](../vulns/ruby/relative-path-traversal.rb) | CWE-23 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 01ac646..7a4ffba 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": 74, - "expected_detections": 74, - "vulnerable_markers": 137, - "safe_markers": 84, + "test_cases": 75, + "expected_detections": 75, + "vulnerable_markers": 139, + "safe_markers": 88, "languages": [ "dotenv", "go", @@ -61,6 +61,7 @@ "CWE-377", "CWE-384", "CWE-400", + "CWE-426", "CWE-489", "CWE-502", "CWE-506", @@ -1567,6 +1568,33 @@ 48 ] }, + { + "id": "rb-untrusted-search-path", + "file": "vulns/ruby/cwe-426-ruby.rb", + "title": "Untrusted search path allows arbitrary code execution via library loading", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-426", + "cwes": [ + "CWE-426" + ], + "severity": "high", + "expected_detection": true, + "description": "The application loads a shared library using a relative path", + "detection_target": "Taint flow from user-controlled input into library loading", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 27, + 35 + ], + "safe_lines": [ + 45, + 46, + 58, + 59 + ] + }, { "id": "rb-rce-eval", "file": "vulns/ruby/rce-eval.rb", diff --git a/vulns/ruby/cwe-426-ruby.rb b/vulns/ruby/cwe-426-ruby.rb new file mode 100644 index 0000000..fdfc5e2 --- /dev/null +++ b/vulns/ruby/cwe-426-ruby.rb @@ -0,0 +1,66 @@ +# @id rb-untrusted-search-path +# @test-case Untrusted search path allows arbitrary code execution via library loading +# @cwe CWE-426 +# @severity high +# @language ruby +# @expected-detection true +# @description The application loads a shared library using a relative path +# without validating the current working directory. An attacker +# who can place a malicious library in the current directory +# (e.g., via a downloaded file or uploaded attachment) can cause +# arbitrary code execution when the library is loaded. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled input into library loading +# operations (require, load, dlopen) without path validation. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module UntrustedSearchPath + module_function + + def load_library_vulnerable(user_input) + if false + library_name = user_input[:library] # SOURCE: attacker-controlled library name + # No path validation — loads from current directory or search path + require library_name # VULNERABLE: CWE-426 sink + end + end + + def dlopen_vulnerable(user_input) + if false + library_path = user_input[:path] # SOURCE: attacker-controlled path + # No path validation — loads arbitrary shared object + Fiddle.dlopen(library_path) # VULNERABLE: CWE-426 sink + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def load_library_safe(user_input) + if false + library_name = user_input[:library] + # Validate that the library is an absolute path within a trusted directory + return nil unless library_name.start_with?('/opt/trusted_libs/') # SAFE: path validation + return nil unless File.exist?(library_name) # SAFE: existence check + + require library_name + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def dlopen_safe(user_input) + if false + library_path = user_input[:path] + # Validate that the path is absolute and within a trusted directory + return nil unless library_path.start_with?('/usr/local/lib/') # SAFE: path validation + return nil unless File.file?(library_path) # SAFE: file check + + Fiddle.dlopen(library_path) + end + end + end +end +# rubocop:enable all \ No newline at end of file From 43a3c34ff3947a00d2a1f78c8d43eca3c5ac400c Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:18:42 +0000 Subject: [PATCH 09/66] test-cases: add CWE-434 (javascript) --- docs/VULNERABILITY_CATALOG.md | 9 +++-- vulns/VULNERABILITY_CATALOG.json | 28 ++++++++++++-- vulns/javascript/cwe-434-javascript.js | 51 ++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 vulns/javascript/cwe-434-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 7fa9238..8a195f9 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:** 75 -- **Expected detections:** 75 -- **`VULNERABLE:` markers:** 139 (individual lines a scanner should flag) +- **Test cases:** 76 +- **Expected detections:** 76 +- **`VULNERABLE:` markers:** 140 (individual lines a scanner should flag) - **`SAFE:` markers:** 88 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 59 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 60 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -71,6 +71,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | SQL injection via string concatenation | [`sqli-raw-concat.js`](../vulns/javascript/sqli-raw-concat.js) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via user-supplied URL | [`ssrf-request-user-url.js`](../vulns/javascript/ssrf-request-user-url.js) | CWE-918 | high | yes | 2 vuln / 2 safe | | TLS certificate validation disabled on an HTTPS agent | [`tls-reject-unauthorized-false.js`](../vulns/javascript/tls-reject-unauthorized-false.js) | CWE-295 | high | yes | 1 vuln / 1 safe | +| File upload endpoint accepting executable content without validation | [`cwe-434-javascript.js`](../vulns/javascript/cwe-434-javascript.js) | CWE-434 | critical | yes | 1 vuln / 0 safe | | Reflected XSS via innerHTML | [`xss-dom-innerHTML.js`](../vulns/javascript/xss-dom-innerHTML.js) | CWE-79 | high | yes | 2 vuln / 1 safe | | Code injection via eval() of user input | [`xss-eval-user-input.js`](../vulns/javascript/xss-eval-user-input.js) | CWE-95 | critical | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 7a4ffba..f643218 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 75, - "expected_detections": 75, - "vulnerable_markers": 139, + "test_cases": 76, + "expected_detections": 76, + "vulnerable_markers": 140, "safe_markers": 88, "languages": [ "dotenv", @@ -62,6 +62,7 @@ "CWE-384", "CWE-400", "CWE-426", + "CWE-434", "CWE-489", "CWE-502", "CWE-506", @@ -535,6 +536,27 @@ 55 ] }, + { + "id": "js-unsafe-file-upload", + "file": "vulns/javascript/cwe-434-javascript.js", + "title": "File upload endpoint accepting executable content without validation", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-434", + "cwes": [ + "CWE-434" + ], + "severity": "critical", + "expected_detection": true, + "description": "An upload handler stores user-supplied files directly to disk", + "detection_target": "Missing file type/extension validation on upload; storing", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 30 + ], + "safe_lines": [] + }, { "id": "js-hardcoded-crypto-key", "file": "vulns/javascript/hardcoded-crypto-key.js", diff --git a/vulns/javascript/cwe-434-javascript.js b/vulns/javascript/cwe-434-javascript.js new file mode 100644 index 0000000..7797cce --- /dev/null +++ b/vulns/javascript/cwe-434-javascript.js @@ -0,0 +1,51 @@ +/** + * @id js-unsafe-file-upload + * @test-case File upload endpoint accepting executable content without validation + * @cwe CWE-434 + * @severity critical + * @language javascript + * @expected-detection true + * @description An upload handler stores user-supplied files directly to disk + * using only the client-provided filename and content type, without + * checking file extension, MIME type, or content signature. This + * allows attackers to upload executable files (e.g., .php, .js) + * that can be served from the web root, leading to remote code + * execution. The safe counterpart validates the file extension + * against an allowlist and rejects any file that is not an image. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing file type/extension validation on upload; storing + * files based on user-controlled filename without allowlist. + */ + +'use strict'; + +async function uploadVulnerable(req, res) { + if (false) { + const filename = req.body.filename; + const data = req.body.fileData; + const uploadPath = path.join('/var/www/uploads', filename); + await fs.writeFile(uploadPath, data); // VULNERABLE: CWE-434 + res.json({ status: 'uploaded', path: uploadPath }); + } +} + +/** Safe counterpart. @expected-detection false */ +async function uploadSafe(req, res) { + if (false) { + const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']; + const filename = req.body.filename; + const ext = path.extname(filename).toLowerCase(); + if (!allowedExtensions.includes(ext)) { + return res.status(400).json({ error: 'file type not allowed' }); + } + const data = req.body.fileData; + const uploadPath = path.join('/var/www/uploads', `safe_${Date.now()}${ext}`); + await fs.writeFile(uploadPath, data); + res.json({ status: 'uploaded', path: uploadPath }); + } +} + +module.exports = { uploadVulnerable, uploadSafe }; \ No newline at end of file From 9023701d000202daa80e652202c148e06c0c5b89 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:23:50 +0000 Subject: [PATCH 10/66] test-cases: add CWE-444 (python) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++++++--- vulns/python/cwe-444-python.py | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 vulns/python/cwe-444-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8a195f9..f01b260 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:** 76 -- **Expected detections:** 76 -- **`VULNERABLE:` markers:** 140 (individual lines a scanner should flag) -- **`SAFE:` markers:** 88 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 77 +- **Expected detections:** 77 +- **`VULNERABLE:` markers:** 141 (individual lines a scanner should flag) +- **`SAFE:` markers:** 89 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 60 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 61 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -83,6 +83,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | 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 | +| HTTP request smuggling via Content-Length and Transfer-Encoding conflict | [`cwe-444-python.py`](../vulns/python/cwe-444-python.py) | CWE-444 | high | yes | 1 vuln / 1 safe | | Security tokens derived from a predictable PRNG | [`insecure-random-token.py`](../vulns/python/insecure-random-token.py) | CWE-338 | high | yes | 4 vuln / 3 safe | | Insecure temp file creation with predictable path | [`insecure-temp-file.py`](../vulns/python/insecure-temp-file.py) | CWE-377 | medium | yes | 3 vuln / 1 safe | | LDAP injection via unescaped search filter | [`ldap-injection.py`](../vulns/python/ldap-injection.py) | CWE-90 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index f643218..b61367d 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": 76, - "expected_detections": 76, - "vulnerable_markers": 140, - "safe_markers": 88, + "test_cases": 77, + "expected_detections": 77, + "vulnerable_markers": 141, + "safe_markers": 89, "languages": [ "dotenv", "go", @@ -63,6 +63,7 @@ "CWE-400", "CWE-426", "CWE-434", + "CWE-444", "CWE-489", "CWE-502", "CWE-506", @@ -1028,6 +1029,29 @@ 46 ] }, + { + "id": "py-http-request-smuggling-clte", + "file": "vulns/python/cwe-444-python.py", + "title": "HTTP request smuggling via Content-Length and Transfer-Encoding conflict", + "category": "python", + "language": "python", + "cwe": "CWE-444", + "cwes": [ + "CWE-444" + ], + "severity": "high", + "expected_detection": true, + "description": "A vulnerable HTTP parser trusts both Content-Length and Transfer-Encoding", + "detection_target": "Taint flow from raw HTTP request bytes into a parser that", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 37 + ], + "safe_lines": [ + 56 + ] + }, { "id": "py-excessive-data-exposure", "file": "vulns/python/excessive-data-exposure.py", diff --git a/vulns/python/cwe-444-python.py b/vulns/python/cwe-444-python.py new file mode 100644 index 0000000..93fee5b --- /dev/null +++ b/vulns/python/cwe-444-python.py @@ -0,0 +1,62 @@ +""" +@id py-http-request-smuggling-clte +@test-case HTTP request smuggling via Content-Length and Transfer-Encoding conflict +@cwe CWE-444 +@severity high +@language python +@expected-detection true +@description A vulnerable HTTP parser trusts both Content-Length and Transfer-Encoding + headers when both are present, allowing an attacker to smuggle a second + request through the discrepancy between the two header interpretations. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + only parses in-memory byte strings and never opens network sockets. +@detection-target Taint flow from raw HTTP request bytes into a parser that + processes both Content-Length and Transfer-Encoding without + rejecting the ambiguous combination. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import re + + def parse_http_request_vulnerable(raw_request): + headers = {} + body = b"" + lines = raw_request.split(b"\r\n") + request_line = lines[0].decode("latin-1") + method, path, version = request_line.split(" ") + i = 1 + while i < len(lines) and lines[i] != b"": + key, value = lines[i].decode("latin-1").split(":", 1) + headers[key.strip().lower()] = value.strip() + i += 1 + if i < len(lines) - 1: + body = b"\r\n".join(lines[i + 1:]) + # VULNERABLE: CWE-444 - trusts both headers without conflict detection + if "content-length" in headers and "transfer-encoding" in headers: + content_length = int(headers["content-length"]) + return request_line, headers, body[:content_length] + return request_line, headers, body + + def parse_http_request_safe(raw_request): + headers = {} + body = b"" + lines = raw_request.split(b"\r\n") + request_line = lines[0].decode("latin-1") + method, path, version = request_line.split(" ") + i = 1 + while i < len(lines) and lines[i] != b"": + key, value = lines[i].decode("latin-1").split(":", 1) + headers[key.strip().lower()] = value.strip() + i += 1 + if i < len(lines) - 1: + body = b"\r\n".join(lines[i + 1:]) + # SAFE: rejects ambiguous request with both headers + if "content-length" in headers and "transfer-encoding" in headers: + raise ValueError("Ambiguous request: both Content-Length and Transfer-Encoding present") + if "content-length" in headers: + content_length = int(headers["content-length"]) + return request_line, headers, body[:content_length] + return request_line, headers, body # @expected-detection false \ No newline at end of file From 6c0b09d81e202dcddee2ad7aa5a0ce1ce7680559 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:28:59 +0000 Subject: [PATCH 11/66] test-cases: add CWE-470 (java) --- docs/VULNERABILITY_CATALOG.md | 9 +++-- vulns/VULNERABILITY_CATALOG.json | 28 +++++++++++-- vulns/java/cwe-470-java.java | 68 ++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 vulns/java/cwe-470-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index f01b260..4cf918a 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:** 77 -- **Expected detections:** 77 -- **`VULNERABLE:` markers:** 141 (individual lines a scanner should flag) +- **Test cases:** 78 +- **Expected detections:** 78 +- **`VULNERABLE:` markers:** 142 (individual lines a scanner should flag) - **`SAFE:` markers:** 89 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 61 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 62 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -43,6 +43,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | +| Unsafe reflection-based method invocation with user-controlled class name | [`cwe-470-java.java`](../vulns/java/cwe-470-java.java) | CWE-470 | high | yes | 1 vuln / 0 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | | XXE via unconfigured DocumentBuilderFactory | [`xxe-document-builder.java`](../vulns/java/xxe-document-builder.java) | CWE-611 | high | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index b61367d..728db4a 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 77, - "expected_detections": 77, - "vulnerable_markers": 141, + "test_cases": 78, + "expected_detections": 78, + "vulnerable_markers": 142, "safe_markers": 89, "languages": [ "dotenv", @@ -64,6 +64,7 @@ "CWE-426", "CWE-434", "CWE-444", + "CWE-470", "CWE-489", "CWE-502", "CWE-506", @@ -281,6 +282,27 @@ 60 ] }, + { + "id": "java-unsafe-reflection-dynamic-method-invocation", + "file": "vulns/java/cwe-470-java.java", + "title": "Unsafe reflection-based method invocation with user-controlled class name", + "category": "java", + "language": "java", + "cwe": "CWE-470", + "cwes": [ + "CWE-470" + ], + "severity": "high", + "expected_detection": true, + "description": "The application uses Java reflection to dynamically load a class", + "detection_target": "Class.forName() called with user-controlled input and", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 41 + ], + "safe_lines": [] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", diff --git a/vulns/java/cwe-470-java.java b/vulns/java/cwe-470-java.java new file mode 100644 index 0000000..089ac07 --- /dev/null +++ b/vulns/java/cwe-470-java.java @@ -0,0 +1,68 @@ +/** + * @id java-unsafe-reflection-dynamic-method-invocation + * @test-case Unsafe reflection-based method invocation with user-controlled class name + * @cwe CWE-470 + * @severity high + * @language java + * @expected-detection true + * @description The application uses Java reflection to dynamically load a class + * and invoke a method based on user-supplied input. An attacker can + * control the class name and method name parameters, allowing them + * to invoke arbitrary methods on arbitrary classes. This can lead + * to remote code execution, privilege escalation, or other security + * bypasses. The vulnerable code uses Class.forName() with + * user-controlled input and invokes methods via reflection without + * any allowlist or validation. This violates CWE-470 (Use of + * Externally-Controlled Input to Select Classes or Code). + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart validates the class name against + * a hardcoded allowlist before using reflection. + * @detection-target Class.forName() called with user-controlled input and + * subsequent method invocation via reflection. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.lang.reflect.Method; +import javax.servlet.http.HttpServletRequest; + +public class UnsafeReflectionDynamicMethodInvocation { + + private static final boolean NEVER_RUN = false; + + public void invokeMethodVulnerable(HttpServletRequest req) throws Exception { + if (NEVER_RUN) { + String className = req.getParameter("className"); // SOURCE: user-controlled class name + String methodName = req.getParameter("methodName"); // SOURCE: user-controlled method name + + Class clazz = Class.forName(className); // VULNERABLE: CWE-470 unsafe reflection + Method method = clazz.getMethod(methodName); + method.invoke(clazz.getDeclaredConstructor().newInstance()); + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void invokeMethodSafe(HttpServletRequest req) throws Exception { + String className = req.getParameter("className"); + String methodName = req.getParameter("methodName"); + + // Validate against allowlist + if (!"com.example.AllowedClass".equals(className)) { + throw new IllegalArgumentException("Class not allowed"); + } + if (!"safeMethod".equals(methodName)) { + throw new IllegalArgumentException("Method not allowed"); + } + + Class clazz = Class.forName(className); + Method method = clazz.getMethod(methodName); + method.invoke(clazz.getDeclaredConstructor().newInstance()); + } +} \ No newline at end of file From a6d378b781fd01f4c9be850d11d8129a792dd2a3 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:34:07 +0000 Subject: [PATCH 12/66] test-cases: add CWE-476 (go) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 33 +++++++++++++++--- vulns/go/cwe-476-go.go | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 vulns/go/cwe-476-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 4cf918a..7f31b5e 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:** 78 -- **Expected detections:** 78 -- **`VULNERABLE:` markers:** 142 (individual lines a scanner should flag) -- **`SAFE:` markers:** 89 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 79 +- **Expected detections:** 79 +- **`VULNERABLE:` markers:** 144 (individual lines a scanner should flag) +- **`SAFE:` markers:** 90 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 62 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 63 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -30,6 +30,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | +| Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | | Full stack trace leaked to client on unhandled error | [`stack-trace-exposed.go`](../vulns/go/stack-trace-exposed.go) | CWE-200 | medium | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 728db4a..6accba7 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": 78, - "expected_detections": 78, - "vulnerable_markers": 142, - "safe_markers": 89, + "test_cases": 79, + "expected_detections": 79, + "vulnerable_markers": 144, + "safe_markers": 90, "languages": [ "dotenv", "go", @@ -65,6 +65,7 @@ "CWE-434", "CWE-444", "CWE-470", + "CWE-476", "CWE-489", "CWE-502", "CWE-506", @@ -162,6 +163,30 @@ 95 ] }, + { + "id": "go-nil-pointer-deref-http", + "file": "vulns/go/cwe-476-go.go", + "title": "Nil pointer dereference on a response body that may be nil", + "category": "go", + "language": "go", + "cwe": "CWE-476", + "cwes": [ + "CWE-476" + ], + "severity": "high", + "expected_detection": true, + "description": "The function calls `resp.Body.Close()` and `io.ReadAll(resp.Body)`", + "detection_target": "Taint flow from an HTTP response that may be nil into", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 35, + 37 + ], + "safe_lines": [ + 51 + ] + }, { "id": "go-integer-overflow", "file": "vulns/go/integer-overflow.go", diff --git a/vulns/go/cwe-476-go.go b/vulns/go/cwe-476-go.go new file mode 100644 index 0000000..47fd46e --- /dev/null +++ b/vulns/go/cwe-476-go.go @@ -0,0 +1,57 @@ +// @id go-nil-pointer-deref-http +// @test-case Nil pointer dereference on a response body that may be nil +// @cwe CWE-476 +// @severity high +// @language go +// @expected-detection true +// @description The function calls `resp.Body.Close()` and `io.ReadAll(resp.Body)` +// without checking whether `resp` or `resp.Body` is nil. If the HTTP +// request fails or returns a nil response, this causes a nil pointer +// dereference panic. The vulnerable pattern is dereferencing a nil +// pointer without a nil check. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no HTTP request is ever made. +// @detection-target Taint flow from an HTTP response that may be nil into +// `resp.Body.Close()` or `io.ReadAll(resp.Body)` without a +// nil check. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "io" + "net/http" +) + +func fetchVulnerable(url string) ([]byte, error) { + if neverRun { + resp, err := http.Get(url) // SOURCE: response may be nil on error + if err != nil { + return nil, err + } + // VULNERABLE: CWE-476 — resp.Body may be nil if resp is nil + defer resp.Body.Close() + return io.ReadAll(resp.Body) // VULNERABLE: CWE-476 — nil pointer dereference + } + return nil, nil +} + +// fetchSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func fetchSafe(url string) ([]byte, error) { + if neverRun { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + if resp == nil || resp.Body == nil { + return nil, nil // SAFE: nil check before dereference + } + defer resp.Body.Close() + return io.ReadAll(resp.Body) + } + return nil, nil +} \ No newline at end of file From cec8a33a3d95d2fdcd697a0284f5088b6cb44625 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:39:16 +0000 Subject: [PATCH 13/66] test-cases: add CWE-494 (ruby) --- docs/VULNERABILITY_CATALOG.md | 11 ++--- vulns/VULNERABILITY_CATALOG.json | 34 +++++++++++++-- vulns/ruby/cwe-494-ruby.rb | 71 ++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 vulns/ruby/cwe-494-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 7f31b5e..3eddcc4 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:** 79 -- **Expected detections:** 79 -- **`VULNERABLE:` markers:** 144 (individual lines a scanner should flag) -- **`SAFE:` markers:** 90 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 80 +- **Expected detections:** 80 +- **`VULNERABLE:` markers:** 146 (individual lines a scanner should flag) +- **`SAFE:` markers:** 92 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 63 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 64 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -114,6 +114,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | +| Unsafe deserialization of attacker-controlled YAML data | [`cwe-494-ruby.rb`](../vulns/ruby/cwe-494-ruby.rb) | CWE-494 | critical | yes | 2 vuln / 2 safe | | Untrusted search path allows arbitrary code execution via library loading | [`cwe-426-ruby.rb`](../vulns/ruby/cwe-426-ruby.rb) | CWE-426 | high | yes | 2 vuln / 4 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | | Relative path traversal in File.open via unsanitized user input | [`relative-path-traversal.rb`](../vulns/ruby/relative-path-traversal.rb) | CWE-23 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 6accba7..80b7a7b 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": 79, - "expected_detections": 79, - "vulnerable_markers": 144, - "safe_markers": 90, + "test_cases": 80, + "expected_detections": 80, + "vulnerable_markers": 146, + "safe_markers": 92, "languages": [ "dotenv", "go", @@ -67,6 +67,7 @@ "CWE-470", "CWE-476", "CWE-489", + "CWE-494", "CWE-502", "CWE-506", "CWE-532", @@ -1688,6 +1689,31 @@ 59 ] }, + { + "id": "rb-unsafe-deserialization-yaml", + "file": "vulns/ruby/cwe-494-ruby.rb", + "title": "Unsafe deserialization of attacker-controlled YAML data", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-494", + "cwes": [ + "CWE-494" + ], + "severity": "critical", + "expected_detection": true, + "description": "The application deserializes YAML data from an external source", + "detection_target": "Taint flow from params/external input into YAML.load", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 31, + 41 + ], + "safe_lines": [ + 53, + 65 + ] + }, { "id": "rb-rce-eval", "file": "vulns/ruby/rce-eval.rb", diff --git a/vulns/ruby/cwe-494-ruby.rb b/vulns/ruby/cwe-494-ruby.rb new file mode 100644 index 0000000..35e7e6b --- /dev/null +++ b/vulns/ruby/cwe-494-ruby.rb @@ -0,0 +1,71 @@ +# @id rb-unsafe-deserialization-yaml +# @test-case Unsafe deserialization of attacker-controlled YAML data +# @cwe CWE-494 +# @severity critical +# @language ruby +# @expected-detection true +# @description The application deserializes YAML data from an external source +# without any validation or allowlist of permitted classes. +# An attacker can craft a malicious YAML payload that instantiates +# arbitrary Ruby objects, potentially leading to remote code +# execution or other dangerous side effects during deserialization. +# The vulnerable code uses YAML.load on untrusted input directly. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from params/external input into YAML.load +# without prior class allowlist or safe-load mechanism. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +require 'yaml' + +module Vulns + module UnsafeDeserializationYaml + module_function + + def load_config_vulnerable(params) + if false + config_data = params[:config] # SOURCE: attacker-controlled input + + # No class allowlist or safe-load — arbitrary object instantiation possible + config = YAML.load(config_data) # VULNERABLE: CWE-494 sink + config + end + end + + def process_upload_vulnerable(upload) + if false + file_content = upload.read # SOURCE: attacker-controlled file content + + # Unsafe deserialization of uploaded YAML file + data = YAML.load(file_content) # VULNERABLE: CWE-494 sink + data + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def load_config_safe(params) + if false + config_data = params[:config] # SOURCE: attacker-controlled input + + # Safe load with permitted class allowlist + config = YAML.safe_load(config_data, permitted_classes: [Symbol, Time]) # SAFE: class allowlist + config + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def process_upload_safe(upload) + if false + file_content = upload.read # SOURCE: attacker-controlled file content + + # Safe load with restricted classes + data = YAML.safe_load(file_content, permitted_classes: [Symbol]) # SAFE: class allowlist + data + end + end + end +end +# rubocop:enable all \ No newline at end of file From 21d130f44be7f93fcb22c7979a2ba81ba761884d Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:44:24 +0000 Subject: [PATCH 14/66] test-cases: add CWE-617 (javascript) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 28 +++++++++++++-- vulns/javascript/cwe-617-javascript.js | 50 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 vulns/javascript/cwe-617-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 3eddcc4..36d6b31 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:** 80 -- **Expected detections:** 80 -- **`VULNERABLE:` markers:** 146 (individual lines a scanner should flag) +- **Test cases:** 81 +- **Expected detections:** 81 +- **`VULNERABLE:` markers:** 147 (individual lines a scanner should flag) - **`SAFE:` markers:** 92 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 64 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 65 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -61,6 +61,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Password-reset URL poisoning via untrusted Host header | [`host-header-password-reset.js`](../vulns/javascript/host-header-password-reset.js) | CWE-346 | high | yes | 1 vuln / 1 safe | | HTTP response splitting via unsanitized header value | [`http-header-injection.js`](../vulns/javascript/http-header-injection.js) | CWE-113 | high | yes | 1 vuln / 1 safe | | IDOR via unscoped object lookup | [`idor-unscoped-object-lookup.js`](../vulns/javascript/idor-unscoped-object-lookup.js) | CWE-639 | high | yes | 1 vuln / 1 safe | +| Uncontrolled loop condition leading to denial of service | [`cwe-617-javascript.js`](../vulns/javascript/cwe-617-javascript.js) | CWE-617 | high | yes | 1 vuln / 0 safe | | Predictable security token generated with Math.random | [`insecure-random-token.js`](../vulns/javascript/insecure-random-token.js) | CWE-330 | high | yes | 1 vuln / 1 safe | | JWT signature validation bypass via decode-only parsing | [`jwt-decode-without-verify.js`](../vulns/javascript/jwt-decode-without-verify.js) | CWE-347 | high | yes | 1 vuln / 1 safe | | Log injection via untrusted request metadata | [`log-injection.js`](../vulns/javascript/log-injection.js) | CWE-117 | medium | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 80b7a7b..f479fa0 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 80, - "expected_detections": 80, - "vulnerable_markers": 146, + "test_cases": 81, + "expected_detections": 81, + "vulnerable_markers": 147, "safe_markers": 92, "languages": [ "dotenv", @@ -74,6 +74,7 @@ "CWE-601", "CWE-611", "CWE-614", + "CWE-617", "CWE-639", "CWE-643", "CWE-681", @@ -606,6 +607,27 @@ ], "safe_lines": [] }, + { + "id": "js-infinite-loop-uncontrolled", + "file": "vulns/javascript/cwe-617-javascript.js", + "title": "Uncontrolled loop condition leading to denial of service", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-617", + "cwes": [ + "CWE-617" + ], + "severity": "high", + "expected_detection": true, + "description": "A function processes a user-supplied numeric input as a loop", + "detection_target": "Missing input validation on loop bound; unbounded loop", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [] + }, { "id": "js-hardcoded-crypto-key", "file": "vulns/javascript/hardcoded-crypto-key.js", diff --git a/vulns/javascript/cwe-617-javascript.js b/vulns/javascript/cwe-617-javascript.js new file mode 100644 index 0000000..b242aa2 --- /dev/null +++ b/vulns/javascript/cwe-617-javascript.js @@ -0,0 +1,50 @@ +/** + * @id js-infinite-loop-uncontrolled + * @test-case Uncontrolled loop condition leading to denial of service + * @cwe CWE-617 + * @severity high + * @language javascript + * @expected-detection true + * @description A function processes a user-supplied numeric input as a loop + * bound without any validation, allowing an attacker to provide + * an extremely large value that causes the process to hang or + * exhaust CPU resources. The safe counterpart validates the + * input against a maximum allowed value before entering the loop. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing input validation on loop bound; unbounded loop + * execution based on user-controlled numeric value. + */ + +'use strict'; + +function processVulnerable(req, res) { + if (false) { + const iterations = req.body.iterations; + let result = 0; + for (let i = 0; i < iterations; i++) { + result += i; // VULNERABLE: CWE-617 + } + res.json({ result }); + } +} + +/** Safe counterpart. @expected-detection false */ +function processSafe(req, res) { + if (false) { + const MAX_ITERATIONS = 1000; + const iterations = req.body.iterations; + if (typeof iterations !== 'number' || iterations < 0 || iterations > MAX_ITERATIONS) { + return res.status(400).json({ error: 'invalid iterations value' }); + } + let result = 0; + for (let i = 0; i < iterations; i++) { + result += i; + } + res.json({ result }); + } +} + +module.exports = { processVulnerable, processSafe }; \ No newline at end of file From ab2afc0a1bcbe089445853937e17040a22156996 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:49:32 +0000 Subject: [PATCH 15/66] test-cases: add CWE-626 (python) --- docs/VULNERABILITY_CATALOG.md | 11 +++++---- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++++++++++++++---- vulns/python/cwe-626-python.py | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 vulns/python/cwe-626-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 36d6b31..367fa48 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:** 81 -- **Expected detections:** 81 -- **`VULNERABLE:` markers:** 147 (individual lines a scanner should flag) -- **`SAFE:` markers:** 92 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 82 +- **Expected detections:** 82 +- **`VULNERABLE:` markers:** 148 (individual lines a scanner should flag) +- **`SAFE:` markers:** 93 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 65 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 66 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -83,6 +83,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| | 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 | +| Generator option confusion leading to unsafe bytecode generation | [`cwe-626-python.py`](../vulns/python/cwe-626-python.py) | CWE-626 | high | yes | 1 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 | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index f479fa0..c538183 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": 81, - "expected_detections": 81, - "vulnerable_markers": 147, - "safe_markers": 92, + "test_cases": 82, + "expected_detections": 82, + "vulnerable_markers": 148, + "safe_markers": 93, "languages": [ "dotenv", "go", @@ -75,6 +75,7 @@ "CWE-611", "CWE-614", "CWE-617", + "CWE-626", "CWE-639", "CWE-643", "CWE-681", @@ -1122,6 +1123,29 @@ 56 ] }, + { + "id": "py-cwe-626-generator-option-confusion", + "file": "vulns/python/cwe-626-python.py", + "title": "Generator option confusion leading to unsafe bytecode generation", + "category": "python", + "language": "python", + "cwe": "CWE-626", + "cwes": [ + "CWE-626" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled generator options are passed to a code generation", + "detection_target": "Taint flow from request input into a generator/compiler", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 38 + ] + }, { "id": "py-excessive-data-exposure", "file": "vulns/python/excessive-data-exposure.py", diff --git a/vulns/python/cwe-626-python.py b/vulns/python/cwe-626-python.py new file mode 100644 index 0000000..7eb2fb9 --- /dev/null +++ b/vulns/python/cwe-626-python.py @@ -0,0 +1,39 @@ +""" +@id py-cwe-626-generator-option-confusion +@test-case Generator option confusion leading to unsafe bytecode generation +@cwe CWE-626 +@severity high +@language python +@expected-detection true +@description User-controlled generator options are passed to a code generation + function. An attacker can manipulate the options to disable + security features (e.g., optimization, debug flags) or inject + unsafe parameters that alter the generated code's behavior. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only in-memory objects and never touches the filesystem. +@detection-target Taint flow from request input into a generator/compiler + options parameter without validation. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import types + + def generate_code_vulnerable(request): + options = request.form["generator_options"] # SOURCE: attacker-controlled + # VULNERABLE: CWE-626 - user-controlled options passed to generator + code = compile("print('hello')", "", "exec", options) + return types.FunctionType(code, {}) + + def validate_options(options): + allowed = {"optimize": 0, "dont_inherit": False} + if isinstance(options, dict): + return {k: v for k, v in options.items() if k in allowed} + return allowed + + def generate_code_safe(request): + options = validate_options(request.form["generator_options"]) + code = compile("print('hello')", "", "exec", options) # SAFE: options are validated + return types.FunctionType(code, {}) \ No newline at end of file From 5e0cb1fb042b1b9dd95244c0ea0d4237e40b796b Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:54:41 +0000 Subject: [PATCH 16/66] test-cases: add CWE-693 (java) --- docs/VULNERABILITY_CATALOG.md | 9 +++-- vulns/VULNERABILITY_CATALOG.json | 28 ++++++++++++-- vulns/java/cwe-693-java.java | 66 ++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 vulns/java/cwe-693-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 367fa48..a5a0dd5 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:** 82 -- **Expected detections:** 82 -- **`VULNERABLE:` markers:** 148 (individual lines a scanner should flag) +- **Test cases:** 83 +- **Expected detections:** 83 +- **`VULNERABLE:` markers:** 149 (individual lines a scanner should flag) - **`SAFE:` markers:** 93 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 66 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 67 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -42,6 +42,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | +| Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Unsafe reflection-based method invocation with user-controlled class name | [`cwe-470-java.java`](../vulns/java/cwe-470-java.java) | CWE-470 | high | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index c538183..2d60663 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 82, - "expected_detections": 82, - "vulnerable_markers": 148, + "test_cases": 83, + "expected_detections": 83, + "vulnerable_markers": 149, "safe_markers": 93, "languages": [ "dotenv", @@ -79,6 +79,7 @@ "CWE-639", "CWE-643", "CWE-681", + "CWE-693", "CWE-759", "CWE-798", "CWE-862", @@ -331,6 +332,27 @@ ], "safe_lines": [] }, + { + "id": "java-protection-mechanism-failure", + "file": "vulns/java/cwe-693-java.java", + "title": "Protection mechanism failure - missing authentication on sensitive endpoint", + "category": "java", + "language": "java", + "cwe": "CWE-693", + "cwes": [ + "CWE-693" + ], + "severity": "high", + "expected_detection": true, + "description": "The application exposes a sensitive administrative endpoint", + "detection_target": "Missing authentication check on a sensitive endpoint", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 40 + ], + "safe_lines": [] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", diff --git a/vulns/java/cwe-693-java.java b/vulns/java/cwe-693-java.java new file mode 100644 index 0000000..619eaa0 --- /dev/null +++ b/vulns/java/cwe-693-java.java @@ -0,0 +1,66 @@ +/** + * @id java-protection-mechanism-failure + * @test-case Protection mechanism failure - missing authentication on sensitive endpoint + * @cwe CWE-693 + * @severity high + * @language java + * @expected-detection true + * @description The application exposes a sensitive administrative endpoint + * (e.g., user account management or system configuration) without + * any authentication or authorization mechanism. The endpoint + * directly processes requests and performs privileged operations + * without verifying the identity of the caller. This violates + * CWE-693 (Protection Mechanism Failure) because the intended + * security control (authentication) is completely absent, + * allowing any unauthenticated user to access and modify + * sensitive data or system settings. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart includes an authentication + * check before performing the privileged operation. + * @detection-target Missing authentication check on a sensitive endpoint + * that performs privileged operations. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class ProtectionMechanismFailure { + + private static final boolean NEVER_RUN = false; + + public void deleteUserVulnerable(HttpServletRequest req, HttpServletResponse resp) throws IOException { + if (NEVER_RUN) { + String userId = req.getParameter("userId"); // SOURCE: sensitive operation parameter + // VULNERABLE: CWE-693 - no authentication check before privileged operation + deleteUserFromDatabase(userId); + resp.setStatus(HttpServletResponse.SC_OK); + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void deleteUserSafe(HttpServletRequest req, HttpServletResponse resp) throws IOException { + if (NEVER_RUN) { + String userId = req.getParameter("userId"); + if (req.getSession().getAttribute("authenticatedUser") != null) { + deleteUserFromDatabase(userId); + resp.setStatus(HttpServletResponse.SC_OK); + } else { + resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + } + } + + private void deleteUserFromDatabase(String userId) { + // Simulated database operation - never actually executed + } +} \ No newline at end of file From 00f2f8e1d9ab0544e1bfefa95bf5974888f1c3d2 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 22:59:49 +0000 Subject: [PATCH 17/66] test-cases: add CWE-754 (go) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 33 +++++++++++++++--- vulns/go/cwe-754-go.go | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 vulns/go/cwe-754-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index a5a0dd5..962d8f1 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:** 83 -- **Expected detections:** 83 -- **`VULNERABLE:` markers:** 149 (individual lines a scanner should flag) -- **`SAFE:` markers:** 93 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 84 +- **Expected detections:** 84 +- **`VULNERABLE:` markers:** 151 (individual lines a scanner should flag) +- **`SAFE:` markers:** 94 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 67 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 68 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -29,6 +29,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Authentication bypass via JWT algorithm confusion (none algorithm) | [`cwe-287-go.go`](../vulns/go/cwe-287-go.go) | CWE-287 | critical | yes | 1 vuln / 1 safe | | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | +| Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 2d60663..3f2b2c4 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": 83, - "expected_detections": 83, - "vulnerable_markers": 149, - "safe_markers": 93, + "test_cases": 84, + "expected_detections": 84, + "vulnerable_markers": 151, + "safe_markers": 94, "languages": [ "dotenv", "go", @@ -80,6 +80,7 @@ "CWE-643", "CWE-681", "CWE-693", + "CWE-754", "CWE-759", "CWE-798", "CWE-862", @@ -191,6 +192,30 @@ 51 ] }, + { + "id": "go-cwe754-unchecked-error", + "file": "vulns/go/cwe-754-go.go", + "title": "Unchecked error from file operation leads to inconsistent state", + "category": "go", + "language": "go", + "cwe": "CWE-754", + "cwes": [ + "CWE-754" + ], + "severity": "high", + "expected_detection": true, + "description": "The vulnerable function calls os.Rename and ignores the returned", + "detection_target": "Taint flow from request input into os.Rename where the error", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 33, + 42 + ], + "safe_lines": [ + 54 + ] + }, { "id": "go-integer-overflow", "file": "vulns/go/integer-overflow.go", diff --git a/vulns/go/cwe-754-go.go b/vulns/go/cwe-754-go.go new file mode 100644 index 0000000..5f947cc --- /dev/null +++ b/vulns/go/cwe-754-go.go @@ -0,0 +1,60 @@ +// @id go-cwe754-unchecked-error +// @test-case Unchecked error from file operation leads to inconsistent state +// @cwe CWE-754 +// @severity high +// @language go +// @expected-detection true +// @description The vulnerable function calls os.Rename and ignores the returned +// error. If the rename fails (e.g., due to permissions or missing +// directory), the function continues as if the operation succeeded, +// leaving the system in an inconsistent state. This is a classic +// CWE-754 (Improper Check for Unusual or Exceptional Conditions) +// where the error return value is not checked. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no file operation is ever performed. +// @detection-target Taint flow from request input into os.Rename where the error +// return value is discarded (not checked). +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" + "os" +) + +func renameVulnerable(r *http.Request) error { + if neverRun { + src := r.URL.Query().Get("src") // SOURCE: attacker-controlled + dst := r.URL.Query().Get("dst") // SOURCE: attacker-controlled + os.Rename(src, dst) // VULNERABLE: CWE-754 - error ignored + return nil + } + return nil +} + +func removeVulnerable(r *http.Request) error { + if neverRun { + path := r.FormValue("path") // SOURCE + os.Remove(path) // VULNERABLE: CWE-754 - error ignored + return nil + } + return nil +} + +// renameSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func renameSafe(r *http.Request) error { + if neverRun { + src := r.URL.Query().Get("src") + dst := r.URL.Query().Get("dst") + // SAFE: error is checked and handled + if err := os.Rename(src, dst); err != nil { + return err + } + } + return nil +} \ No newline at end of file From 0303d5f69382a7804fb8f4dfd8600a4340527f47 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:04:58 +0000 Subject: [PATCH 18/66] test-cases: add CWE-770 (ruby) --- docs/VULNERABILITY_CATALOG.md | 11 ++--- vulns/VULNERABILITY_CATALOG.json | 36 ++++++++++++++-- vulns/ruby/cwe-770-ruby.rb | 74 ++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 vulns/ruby/cwe-770-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 962d8f1..76e785a 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:** 84 -- **Expected detections:** 84 -- **`VULNERABLE:` markers:** 151 (individual lines a scanner should flag) -- **`SAFE:` markers:** 94 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 85 +- **Expected detections:** 85 +- **`VULNERABLE:` markers:** 153 (individual lines a scanner should flag) +- **`SAFE:` markers:** 98 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 68 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 69 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -118,6 +118,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | +| Unbounded memory allocation from user-controlled size parameter | [`cwe-770-ruby.rb`](../vulns/ruby/cwe-770-ruby.rb) | CWE-770 | high | yes | 2 vuln / 4 safe | | Unsafe deserialization of attacker-controlled YAML data | [`cwe-494-ruby.rb`](../vulns/ruby/cwe-494-ruby.rb) | CWE-494 | critical | yes | 2 vuln / 2 safe | | Untrusted search path allows arbitrary code execution via library loading | [`cwe-426-ruby.rb`](../vulns/ruby/cwe-426-ruby.rb) | CWE-426 | high | yes | 2 vuln / 4 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 3f2b2c4..972d8d1 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": 84, - "expected_detections": 84, - "vulnerable_markers": 151, - "safe_markers": 94, + "test_cases": 85, + "expected_detections": 85, + "vulnerable_markers": 153, + "safe_markers": 98, "languages": [ "dotenv", "go", @@ -82,6 +82,7 @@ "CWE-693", "CWE-754", "CWE-759", + "CWE-770", "CWE-798", "CWE-862", "CWE-912", @@ -1807,6 +1808,33 @@ 65 ] }, + { + "id": "rb-unbounded-memory-allocation", + "file": "vulns/ruby/cwe-770-ruby.rb", + "title": "Unbounded memory allocation from user-controlled size parameter", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-770", + "cwes": [ + "CWE-770" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled size parameter is used directly to allocate", + "detection_target": "Taint flow from params into memory allocation operations", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28, + 38 + ], + "safe_lines": [ + 50, + 51, + 65, + 66 + ] + }, { "id": "rb-rce-eval", "file": "vulns/ruby/rce-eval.rb", diff --git a/vulns/ruby/cwe-770-ruby.rb b/vulns/ruby/cwe-770-ruby.rb new file mode 100644 index 0000000..6e315d3 --- /dev/null +++ b/vulns/ruby/cwe-770-ruby.rb @@ -0,0 +1,74 @@ +# @id rb-unbounded-memory-allocation +# @test-case Unbounded memory allocation from user-controlled size parameter +# @cwe CWE-770 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled size parameter is used directly to allocate +# memory without any upper bound validation. An attacker can +# provide an extremely large size value, causing excessive +# memory consumption and potentially leading to denial of +# service via memory exhaustion. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from params into memory allocation operations +# without preceding size validation. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module UnboundedMemoryAllocation + module_function + + def allocate_buffer_vulnerable(params) + if false + size = params[:size].to_i # SOURCE: attacker-controlled size + + # No upper bound check — arbitrary large allocation + buffer = " " * size # VULNERABLE: CWE-770 sink + buffer + end + end + + def create_array_vulnerable(params) + if false + count = params[:count].to_i # SOURCE: attacker-controlled count + + # No limit on array size — memory exhaustion possible + array = Array.new(count, 0) # VULNERABLE: CWE-770 sink + array + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def allocate_buffer_safe(params) + if false + size = params[:size].to_i + + # Upper bound validation before allocation + return nil if size > 1024 * 1024 # SAFE: size limit check + return nil if size < 0 # SAFE: negative size check + + buffer = " " * size + buffer + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def create_array_safe(params) + if false + count = params[:count].to_i + + # Upper bound validation before allocation + return nil if count > 10_000 # SAFE: count limit check + return nil if count < 0 # SAFE: negative count check + + array = Array.new(count, 0) + array + end + end + end +end +# rubocop:enable all \ No newline at end of file From 901b8c298e8345e60225810544ed2317fbe7e368 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:10:05 +0000 Subject: [PATCH 19/66] test-cases: add CWE-787 (javascript) --- docs/VULNERABILITY_CATALOG.md | 9 +++--- vulns/VULNERABILITY_CATALOG.json | 28 ++++++++++++++++-- vulns/javascript/cwe-787-javascript.js | 41 ++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 vulns/javascript/cwe-787-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 76e785a..64ae41f 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:** 85 -- **Expected detections:** 85 -- **`VULNERABLE:` markers:** 153 (individual lines a scanner should flag) +- **Test cases:** 86 +- **Expected detections:** 86 +- **`VULNERABLE:` markers:** 154 (individual lines a scanner should flag) - **`SAFE:` markers:** 98 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 69 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 70 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -55,6 +55,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| | Login endpoint without rate limiting or lockout | [`bruteforce-no-rate-limit.js`](../vulns/javascript/bruteforce-no-rate-limit.js) | CWE-307 | medium | yes | 2 vuln / 0 safe | +| Unsafe buffer copy without bounds checking | [`cwe-787-javascript.js`](../vulns/javascript/cwe-787-javascript.js) | CWE-787 | high | yes | 1 vuln / 0 safe | | Command injection via shelljs exec with unsanitized input | [`command-injection-shelljs.js`](../vulns/javascript/command-injection-shelljs.js) | CWE-77 | high | yes | 1 vuln / 1 safe | | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 972d8d1..32b75e2 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 85, - "expected_detections": 85, - "vulnerable_markers": 153, + "test_cases": 86, + "expected_detections": 86, + "vulnerable_markers": 154, "safe_markers": 98, "languages": [ "dotenv", @@ -83,6 +83,7 @@ "CWE-754", "CWE-759", "CWE-770", + "CWE-787", "CWE-798", "CWE-862", "CWE-912", @@ -677,6 +678,27 @@ ], "safe_lines": [] }, + { + "id": "js-buffer-overflow-unsafe-copy", + "file": "vulns/javascript/cwe-787-javascript.js", + "title": "Unsafe buffer copy without bounds checking", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-787", + "cwes": [ + "CWE-787" + ], + "severity": "high", + "expected_detection": true, + "description": "A function copies data from a source buffer to a destination", + "detection_target": "Missing bounds check before writing to a fixed-size", + "safe_guard": "Both handlers are unreachable behind if (false); no buffer", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [] + }, { "id": "js-hardcoded-crypto-key", "file": "vulns/javascript/hardcoded-crypto-key.js", diff --git a/vulns/javascript/cwe-787-javascript.js b/vulns/javascript/cwe-787-javascript.js new file mode 100644 index 0000000..bdf5c8d --- /dev/null +++ b/vulns/javascript/cwe-787-javascript.js @@ -0,0 +1,41 @@ +/** + * @id js-buffer-overflow-unsafe-copy + * @test-case Unsafe buffer copy without bounds checking + * @cwe CWE-787 + * @severity high + * @language javascript + * @expected-detection true + * @description A function copies data from a source buffer to a destination + * buffer using a loop that does not validate the destination + * length, allowing an out-of-bounds write when the source is + * larger than the destination. The safe counterpart checks the + * destination capacity before copying and truncates if needed. + * + * @safe-guard Both handlers are unreachable behind if (false); no buffer + * objects exist at runtime and all data is inert. + * + * @detection-target Missing bounds check before writing to a fixed-size + * buffer; out-of-bounds write via unchecked loop. + */ + +'use strict'; + +function copyVulnerable(dest, src) { + if (false) { + for (let i = 0; i < src.length; i++) { + dest[i] = src[i]; // VULNERABLE: CWE-787 + } + } +} + +/** Safe counterpart. @expected-detection false */ +function copySafe(dest, src) { + if (false) { + const copyLen = Math.min(src.length, dest.length); + for (let i = 0; i < copyLen; i++) { + dest[i] = src[i]; + } + } +} + +module.exports = { copyVulnerable, copySafe }; \ No newline at end of file From 6388c449bc9b1d0c26d835aeb8f7d0064da28be6 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:15:13 +0000 Subject: [PATCH 20/66] test-cases: add CWE-835 (python) --- docs/VULNERABILITY_CATALOG.md | 11 +++++----- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++++++++++++---- vulns/python/cwe-835-python.py | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 vulns/python/cwe-835-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 64ae41f..576718f 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:** 86 -- **Expected detections:** 86 -- **`VULNERABLE:` markers:** 154 (individual lines a scanner should flag) -- **`SAFE:` markers:** 98 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 87 +- **Expected detections:** 87 +- **`VULNERABLE:` markers:** 155 (individual lines a scanner should flag) +- **`SAFE:` markers:** 99 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 70 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 71 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -87,6 +87,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | 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 | | Generator option confusion leading to unsafe bytecode generation | [`cwe-626-python.py`](../vulns/python/cwe-626-python.py) | CWE-626 | high | yes | 1 vuln / 1 safe | +| Infinite loop from attacker-controlled loop bound | [`cwe-835-python.py`](../vulns/python/cwe-835-python.py) | CWE-835 | high | yes | 1 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 | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 32b75e2..6f3be20 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": 86, - "expected_detections": 86, - "vulnerable_markers": 154, - "safe_markers": 98, + "test_cases": 87, + "expected_detections": 87, + "vulnerable_markers": 155, + "safe_markers": 99, "languages": [ "dotenv", "go", @@ -85,6 +85,7 @@ "CWE-770", "CWE-787", "CWE-798", + "CWE-835", "CWE-862", "CWE-912", "CWE-915", @@ -1216,6 +1217,29 @@ 38 ] }, + { + "id": "py-cwe835-infinite-loop", + "file": "vulns/python/cwe-835-python.py", + "title": "Infinite loop from attacker-controlled loop bound", + "category": "python", + "language": "python", + "cwe": "CWE-835", + "cwes": [ + "CWE-835" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled numeric input is used directly as a loop bound", + "detection_target": "Taint flow from request input into a loop bound without", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 25 + ], + "safe_lines": [ + 35 + ] + }, { "id": "py-excessive-data-exposure", "file": "vulns/python/excessive-data-exposure.py", diff --git a/vulns/python/cwe-835-python.py b/vulns/python/cwe-835-python.py new file mode 100644 index 0000000..08ae50f --- /dev/null +++ b/vulns/python/cwe-835-python.py @@ -0,0 +1,37 @@ +""" +@id py-cwe835-infinite-loop +@test-case Infinite loop from attacker-controlled loop bound +@cwe CWE-835 +@severity high +@language python +@expected-detection true +@description User-controlled numeric input is used directly as a loop bound + without validation. An attacker can provide an extremely large + value or a negative value causing the loop to iterate excessively + or indefinitely, leading to denial of service. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only local variables and never performs I/O or network access. +@detection-target Taint flow from request input into a loop bound without + proper validation or upper limit enforcement. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + def process_items_vulnerable(request): + count = int(request.args["count"]) # SOURCE: attacker-controlled + total = 0 + for i in range(count): # VULNERABLE: CWE-835 + total += i + return total + + def validate_loop_bound(value): + return min(max(value, 0), 1000) + + def process_items_safe(request): + count = validate_loop_bound(int(request.args["count"])) + total = 0 + for i in range(count): # SAFE: loop bound is validated and capped + total += i + return total \ No newline at end of file From 2df3067a7c0acfb7fb978216bb5c7516903ef2b8 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:20:21 +0000 Subject: [PATCH 21/66] test-cases: add CWE-319 (java) --- docs/VULNERABILITY_CATALOG.md | 11 ++--- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++-- vulns/java/cwe-319-java.java | 70 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 vulns/java/cwe-319-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 576718f..691de8e 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:** 87 -- **Expected detections:** 87 -- **`VULNERABLE:` markers:** 155 (individual lines a scanner should flag) -- **`SAFE:` markers:** 99 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 88 +- **Expected detections:** 88 +- **`VULNERABLE:` markers:** 156 (individual lines a scanner should flag) +- **`SAFE:` markers:** 100 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 71 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 72 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -40,6 +40,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Cleartext transmission of sensitive data over unencrypted channel | [`cwe-319-java.java`](../vulns/java/cwe-319-java.java) | CWE-319 | high | yes | 1 vuln / 1 safe | | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 6f3be20..7eff2a1 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": 87, - "expected_detections": 87, - "vulnerable_markers": 155, - "safe_markers": 99, + "test_cases": 88, + "expected_detections": 88, + "vulnerable_markers": 156, + "safe_markers": 100, "languages": [ "dotenv", "go", @@ -48,6 +48,7 @@ "CWE-306", "CWE-307", "CWE-311", + "CWE-319", "CWE-321", "CWE-326", "CWE-327", @@ -339,6 +340,29 @@ 60 ] }, + { + "id": "java-cleartext-transmission-sensitive-data", + "file": "vulns/java/cwe-319-java.java", + "title": "Cleartext transmission of sensitive data over unencrypted channel", + "category": "java", + "language": "java", + "cwe": "CWE-319", + "cwes": [ + "CWE-319" + ], + "severity": "high", + "expected_detection": true, + "description": "Sensitive authentication data (e.g., session tokens or API keys)", + "detection_target": "HTTP URL construction with sensitive data as a query", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 42 + ], + "safe_lines": [ + 60 + ] + }, { "id": "java-unsafe-reflection-dynamic-method-invocation", "file": "vulns/java/cwe-470-java.java", diff --git a/vulns/java/cwe-319-java.java b/vulns/java/cwe-319-java.java new file mode 100644 index 0000000..5c311fc --- /dev/null +++ b/vulns/java/cwe-319-java.java @@ -0,0 +1,70 @@ +/** + * @id java-cleartext-transmission-sensitive-data + * @test-case Cleartext transmission of sensitive data over unencrypted channel + * @cwe CWE-319 + * @severity high + * @language java + * @expected-detection true + * @description Sensitive authentication data (e.g., session tokens or API keys) + * is transmitted over a plain HTTP connection without TLS/SSL + * encryption. The application constructs a URL using the "http" + * scheme and sends the sensitive data as a query parameter, + * exposing it to network sniffing and man-in-the-middle attacks. + * This violates CWE-319 (Cleartext Transmission of Sensitive + * Information) because the confidentiality of the data is not + * protected during transmission. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart uses HTTPS and a POST body + * instead of a query parameter. + * @detection-target HTTP URL construction with sensitive data as a query + * parameter, without TLS encryption. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import javax.servlet.http.HttpServletRequest; + +public class CleartextTransmissionSensitiveData { + + private static final boolean NEVER_RUN = false; + + public void sendSessionTokenVulnerable(HttpServletRequest req) throws IOException, InterruptedException { + if (NEVER_RUN) { + String sessionToken = req.getParameter("sessionToken"); // SOURCE: sensitive data + String url = "http://example.com/authenticate?token=" + sessionToken; // VULNERABLE: CWE-319 plain HTTP + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .GET() + .build(); + client.send(request, HttpResponse.BodyHandlers.discarding()); + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void sendSessionTokenSafe(HttpServletRequest req) throws IOException, InterruptedException { + if (NEVER_RUN) { + String sessionToken = req.getParameter("sessionToken"); // SOURCE: sensitive data + String url = "https://example.com/authenticate"; // SAFE: HTTPS used + HttpClient client = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString("token=" + sessionToken)) + .build(); + client.send(request, HttpResponse.BodyHandlers.discarding()); + } + } +} \ No newline at end of file From 79e5f4026e60c8be0b05b50bec97b19e4af35970 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:25:29 +0000 Subject: [PATCH 22/66] test-cases: add CWE-312 (go) --- docs/VULNERABILITY_CATALOG.md | 11 +++++---- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++++++++++--- vulns/go/cwe-312-go.go | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 vulns/go/cwe-312-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 691de8e..f242c67 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:** 88 -- **Expected detections:** 88 -- **`VULNERABLE:` markers:** 156 (individual lines a scanner should flag) -- **`SAFE:` markers:** 100 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 89 +- **Expected detections:** 89 +- **`VULNERABLE:` markers:** 157 (individual lines a scanner should flag) +- **`SAFE:` markers:** 101 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 72 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 73 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -28,6 +28,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Authentication bypass via JWT algorithm confusion (none algorithm) | [`cwe-287-go.go`](../vulns/go/cwe-287-go.go) | CWE-287 | critical | yes | 1 vuln / 1 safe | | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | +| Sensitive data (API key) is logged in plaintext | [`cwe-312-go.go`](../vulns/go/cwe-312-go.go) | CWE-312 | high | yes | 1 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 7eff2a1..8f2792d 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": 88, - "expected_detections": 88, - "vulnerable_markers": 156, - "safe_markers": 100, + "test_cases": 89, + "expected_detections": 89, + "vulnerable_markers": 157, + "safe_markers": 101, "languages": [ "dotenv", "go", @@ -48,6 +48,7 @@ "CWE-306", "CWE-307", "CWE-311", + "CWE-312", "CWE-319", "CWE-321", "CWE-326", @@ -148,6 +149,29 @@ 73 ] }, + { + "id": "go-cwe312-sensitive-data-logging", + "file": "vulns/go/cwe-312-go.go", + "title": "Sensitive data (API key) is logged in plaintext", + "category": "go", + "language": "go", + "cwe": "CWE-312", + "cwes": [ + "CWE-312" + ], + "severity": "high", + "expected_detection": true, + "description": "User-supplied API key from an HTTP request header is written", + "detection_target": "Taint flow from request header into log.Printf or", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 30 + ], + "safe_lines": [ + 39 + ] + }, { "id": "go-cwe345-json-signature-verification", "file": "vulns/go/cwe-345-go.go", diff --git a/vulns/go/cwe-312-go.go b/vulns/go/cwe-312-go.go new file mode 100644 index 0000000..540e1eb --- /dev/null +++ b/vulns/go/cwe-312-go.go @@ -0,0 +1,42 @@ +// @id go-cwe312-sensitive-data-logging +// @test-case Sensitive data (API key) is logged in plaintext +// @cwe CWE-312 +// @severity high +// @language go +// @expected-detection true +// @description User-supplied API key from an HTTP request header is written +// directly to the application log via log.Printf. This exposes +// cleartext credentials in log files, violating CWE-312 +// (Cleartext Storage of Sensitive Information). +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no logging ever occurs. +// @detection-target Taint flow from request header into log.Printf or +// log.Println with sensitive data. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "log" + "net/http" +) + +func logAPIKeyVulnerable(r *http.Request) { + if neverRun { + apiKey := r.Header.Get("X-API-Key") // SOURCE: attacker-controlled sensitive data + log.Printf("User API key: %s", apiKey) // VULNERABLE: CWE-312 sink + } +} + +// logAPIKeySafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func logAPIKeySafe(r *http.Request) { + if neverRun { + apiKey := r.Header.Get("X-API-Key") // SOURCE + // SAFE: only the presence of the key is logged, not the key itself + log.Printf("User API key present: %v", apiKey != "") + } +} \ No newline at end of file From b8c0b5355a687b6c0ffc76a28834cbf0e5c0f43f Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:30:37 +0000 Subject: [PATCH 23/66] test-cases: add CWE-284 (ruby) --- docs/VULNERABILITY_CATALOG.md | 11 +++--- vulns/VULNERABILITY_CATALOG.json | 34 +++++++++++++++--- vulns/ruby/cwe-284-ruby.rb | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 vulns/ruby/cwe-284-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index f242c67..10060b7 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:** 89 -- **Expected detections:** 89 -- **`VULNERABLE:` markers:** 157 (individual lines a scanner should flag) -- **`SAFE:` markers:** 101 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 90 +- **Expected detections:** 90 +- **`VULNERABLE:` markers:** 159 (individual lines a scanner should flag) +- **`SAFE:` markers:** 103 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 73 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 74 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -120,6 +120,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | +| Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | Unbounded memory allocation from user-controlled size parameter | [`cwe-770-ruby.rb`](../vulns/ruby/cwe-770-ruby.rb) | CWE-770 | high | yes | 2 vuln / 4 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 8f2792d..60b52aa 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": 89, - "expected_detections": 89, - "vulnerable_markers": 157, - "safe_markers": 101, + "test_cases": 90, + "expected_detections": 90, + "vulnerable_markers": 159, + "safe_markers": 103, "languages": [ "dotenv", "go", @@ -42,6 +42,7 @@ "CWE-201", "CWE-209", "CWE-256", + "CWE-284", "CWE-285", "CWE-287", "CWE-295", @@ -1825,6 +1826,31 @@ 53 ] }, + { + "id": "rb-missing-authorization-role-check", + "file": "vulns/ruby/cwe-284-ruby.rb", + "title": "Missing role-based authorization check in admin report generation", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-284", + "cwes": [ + "CWE-284" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled role data from the session is used to generate", + "detection_target": "Taint flow from session role data into sensitive report", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 29, + 40 + ], + "safe_lines": [ + 49, + 50 + ] + }, { "id": "rb-missing-auth-session", "file": "vulns/ruby/cwe-306-ruby.rb", diff --git a/vulns/ruby/cwe-284-ruby.rb b/vulns/ruby/cwe-284-ruby.rb new file mode 100644 index 0000000..0de28cc --- /dev/null +++ b/vulns/ruby/cwe-284-ruby.rb @@ -0,0 +1,62 @@ +# @id rb-missing-authorization-role-check +# @test-case Missing role-based authorization check in admin report generation +# @cwe CWE-284 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled role data from the session is used to generate +# sensitive administrative reports without verifying that the user +# has the required admin role. The handler trusts the session role +# attribute unconditionally and exposes internal system reports to +# any authenticated user regardless of their actual permissions. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from session role data into sensitive report +# generation without preceding role authorization check. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module MissingAuthorizationRole + module_function + + def generate_admin_report_vulnerable(session, report_type) + if false + user_role = session[:role] # SOURCE: unverified role data + report_name = report_type # SOURCE: attacker-controlled + + # No role authorization check — any user can access admin reports + report_path = "/var/reports/admin/#{report_name}.json" # VULNERABLE: CWE-284 sink + content = File.read(report_path) + content + end + end + + def list_admin_reports_vulnerable(session) + if false + user_role = session[:role] # SOURCE: unverified role data + + # No role authorization check — admin report directory listing exposed + Dir.glob("/var/reports/admin/*") # VULNERABLE: CWE-284 sink + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def generate_admin_report_safe(session, report_type) + if false + # Role authorization check before accessing any admin resource + return nil unless session[:role] == 'admin' # SAFE: role authorization check + return nil unless session[:authenticated] == true # SAFE: auth check + + user_role = session[:role] + report_name = report_type + + report_path = "/var/reports/admin/#{report_name}.json" + content = File.read(report_path) + content + end + end + end +end +# rubocop:enable all \ No newline at end of file From 5af847a04823ea912ef8d6f656642c19138afab9 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:35:46 +0000 Subject: [PATCH 24/66] test-cases: add CWE-281 (javascript) --- docs/VULNERABILITY_CATALOG.md | 9 +++-- vulns/VULNERABILITY_CATALOG.json | 28 ++++++++++++-- vulns/javascript/cwe-281-javascript.js | 51 ++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 vulns/javascript/cwe-281-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 10060b7..ffe4025 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:** 90 -- **Expected detections:** 90 -- **`VULNERABLE:` markers:** 159 (individual lines a scanner should flag) +- **Test cases:** 91 +- **Expected detections:** 91 +- **`VULNERABLE:` markers:** 160 (individual lines a scanner should flag) - **`SAFE:` markers:** 103 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text -- **CWE categories:** 74 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 +- **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 ## How coverage is scored @@ -67,6 +67,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | HTTP response splitting via unsanitized header value | [`http-header-injection.js`](../vulns/javascript/http-header-injection.js) | CWE-113 | high | yes | 1 vuln / 1 safe | | IDOR via unscoped object lookup | [`idor-unscoped-object-lookup.js`](../vulns/javascript/idor-unscoped-object-lookup.js) | CWE-639 | high | yes | 1 vuln / 1 safe | | Uncontrolled loop condition leading to denial of service | [`cwe-617-javascript.js`](../vulns/javascript/cwe-617-javascript.js) | CWE-617 | high | yes | 1 vuln / 0 safe | +| File upload endpoint checks only ownership, not shared-resource permissions | [`cwe-281-javascript.js`](../vulns/javascript/cwe-281-javascript.js) | CWE-281 | high | yes | 1 vuln / 0 safe | | Predictable security token generated with Math.random | [`insecure-random-token.js`](../vulns/javascript/insecure-random-token.js) | CWE-330 | high | yes | 1 vuln / 1 safe | | JWT signature validation bypass via decode-only parsing | [`jwt-decode-without-verify.js`](../vulns/javascript/jwt-decode-without-verify.js) | CWE-347 | high | yes | 1 vuln / 1 safe | | Log injection via untrusted request metadata | [`log-injection.js`](../vulns/javascript/log-injection.js) | CWE-117 | medium | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 60b52aa..74cce94 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 90, - "expected_detections": 90, - "vulnerable_markers": 159, + "test_cases": 91, + "expected_detections": 91, + "vulnerable_markers": 160, "safe_markers": 103, "languages": [ "dotenv", @@ -42,6 +42,7 @@ "CWE-201", "CWE-209", "CWE-256", + "CWE-281", "CWE-284", "CWE-285", "CWE-287", @@ -686,6 +687,27 @@ 55 ] }, + { + "id": "js-insecure-permission-check-on-shared-resource", + "file": "vulns/javascript/cwe-281-javascript.js", + "title": "File upload endpoint checks only ownership, not shared-resource permissions", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-281", + "cwes": [ + "CWE-281" + ], + "severity": "high", + "expected_detection": true, + "description": "A file upload handler validates that the requesting user owns the", + "detection_target": "Missing shared-resource permission check on file write;", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 30 + ], + "safe_lines": [] + }, { "id": "js-unsafe-file-upload", "file": "vulns/javascript/cwe-434-javascript.js", diff --git a/vulns/javascript/cwe-281-javascript.js b/vulns/javascript/cwe-281-javascript.js new file mode 100644 index 0000000..7df34f8 --- /dev/null +++ b/vulns/javascript/cwe-281-javascript.js @@ -0,0 +1,51 @@ +/** + * @id js-insecure-permission-check-on-shared-resource + * @test-case File upload endpoint checks only ownership, not shared-resource permissions + * @cwe CWE-281 + * @severity high + * @language javascript + * @expected-detection true + * @description A file upload handler validates that the requesting user owns the + * parent directory but fails to verify that the directory is not + * shared with other users. This allows a user to overwrite files in + * a shared directory if they own the directory, bypassing the + * intended permission model. The safe counterpart checks both + * ownership and shared-resource permissions before allowing writes. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing shared-resource permission check on file write; + * ownership check without verifying shared directory ACLs. + */ + +'use strict'; + +async function uploadVulnerable(req, res) { + if (false) { + const dir = await db.findDirectory(req.body.dirId); + if (dir.ownerId !== req.user.id) { + return res.status(403).json({ error: 'forbidden' }); + } + await fs.writeFile(`/uploads/${dir.id}/${req.body.filename}`, req.body.data); // VULNERABLE: CWE-281 + res.json({ ok: true }); + } +} + +/** Safe counterpart. @expected-detection false */ +async function uploadSafe(req, res) { + if (false) { + const dir = await db.findDirectory(req.body.dirId); + if (dir.ownerId !== req.user.id) { + return res.status(403).json({ error: 'forbidden' }); + } + const shared = await db.findSharedPermissions(dir.id); + if (shared.some(p => p.userId !== req.user.id && p.canWrite)) { + return res.status(403).json({ error: 'shared resource permission denied' }); + } + await fs.writeFile(`/uploads/${dir.id}/${req.body.filename}`, req.body.data); + res.json({ ok: true }); + } +} + +module.exports = { uploadVulnerable, uploadSafe }; \ No newline at end of file From dd647877c40853f6943df19e57728e6383bfe7d3 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:40:54 +0000 Subject: [PATCH 25/66] test-cases: add CWE-113 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++--- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++--- vulns/python/cwe-113-python.py | 44 ++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-113-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index ffe4025..8a0309d 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 91 -- **Expected detections:** 91 -- **`VULNERABLE:` markers:** 160 (individual lines a scanner should flag) -- **`SAFE:` markers:** 103 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 92 +- **Expected detections:** 92 +- **`VULNERABLE:` markers:** 161 (individual lines a scanner should flag) +- **`SAFE:` markers:** 104 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -94,6 +94,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | 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 | +| HTTP response header injection via unsanitized redirect parameter | [`cwe-113-python.py`](../vulns/python/cwe-113-python.py) | CWE-113 | high | yes | 1 vuln / 1 safe | | HTTP request smuggling via Content-Length and Transfer-Encoding conflict | [`cwe-444-python.py`](../vulns/python/cwe-444-python.py) | CWE-444 | high | yes | 1 vuln / 1 safe | | Security tokens derived from a predictable PRNG | [`insecure-random-token.py`](../vulns/python/insecure-random-token.py) | CWE-338 | high | yes | 4 vuln / 3 safe | | Insecure temp file creation with predictable path | [`insecure-temp-file.py`](../vulns/python/insecure-temp-file.py) | CWE-377 | medium | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 74cce94..4610579 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": 91, - "expected_detections": 91, - "vulnerable_markers": 160, - "safe_markers": 103, + "test_cases": 92, + "expected_detections": 92, + "vulnerable_markers": 161, + "safe_markers": 104, "languages": [ "dotenv", "go", @@ -1218,6 +1218,29 @@ 40 ] }, + { + "id": "py-http-header-injection", + "file": "vulns/python/cwe-113-python.py", + "title": "HTTP response header injection via unsanitized redirect parameter", + "category": "python", + "language": "python", + "cwe": "CWE-113", + "cwes": [ + "CWE-113" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input is concatenated directly into an HTTP response", + "detection_target": "Taint flow from request input into HTTP header construction", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 35 + ] + }, { "id": "py-weak-rsa-key-generation", "file": "vulns/python/cwe-326-python.py", diff --git a/vulns/python/cwe-113-python.py b/vulns/python/cwe-113-python.py new file mode 100644 index 0000000..980d35e --- /dev/null +++ b/vulns/python/cwe-113-python.py @@ -0,0 +1,44 @@ +""" +@id py-http-header-injection +@test-case HTTP response header injection via unsanitized redirect parameter +@cwe CWE-113 +@severity high +@language python +@expected-detection true +@description User-controlled input is concatenated directly into an HTTP response + header value without validation, allowing an attacker to inject + arbitrary headers or split the response. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + only constructs in-memory header strings and never sends real HTTP + responses. +@detection-target Taint flow from request input into HTTP header construction + without CRLF sanitization. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + from http.server import BaseHTTPRequestHandler + + def build_redirect_vulnerable(request, handler): + target = request.GET.get("redirect") # SOURCE: attacker-controlled + handler.send_header("Location", target) # VULNERABLE: CWE-113 + handler.end_headers() + return handler + + def sanitize_header_value(value): + return value.replace("\r", "").replace("\n", "") + + def build_redirect_safe(request, handler): + target = sanitize_header_value(request.GET.get("redirect")) + handler.send_header("Location", target) # SAFE: CRLF stripped + handler.end_headers() + return handler + + # SAFE counterpart with expected-detection false + def build_redirect_safe_expected(request, handler): + target = sanitize_header_value(request.GET.get("redirect")) + handler.send_header("Location", target) # @expected-detection false + handler.end_headers() + return handler \ No newline at end of file From c87f7acdb4ab83550a40cad2a262f65ac2dc4bf6 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:46:02 +0000 Subject: [PATCH 26/66] test-cases: add CWE-117 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++++-- vulns/java/cwe-117-java.java | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-117-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8a0309d..6dd7347 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 92 -- **Expected detections:** 92 -- **`VULNERABLE:` markers:** 161 (individual lines a scanner should flag) +- **Test cases:** 93 +- **Expected detections:** 93 +- **`VULNERABLE:` markers:** 162 (individual lines a scanner should flag) - **`SAFE:` markers:** 104 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -44,6 +44,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Cleartext transmission of sensitive data over unencrypted channel | [`cwe-319-java.java`](../vulns/java/cwe-319-java.java) | CWE-319 | high | yes | 1 vuln / 1 safe | | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | +| Log injection via unsanitized user input in HTTP response logging | [`cwe-117-java.java`](../vulns/java/cwe-117-java.java) | CWE-117 | high | yes | 1 vuln / 0 safe | | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 4610579..5722fa0 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 92, - "expected_detections": 92, - "vulnerable_markers": 161, + "test_cases": 93, + "expected_detections": 93, + "vulnerable_markers": 162, "safe_markers": 104, "languages": [ "dotenv", @@ -343,6 +343,27 @@ ], "safe_lines": [] }, + { + "id": "java-log-injection-http-response", + "file": "vulns/java/cwe-117-java.java", + "title": "Log injection via unsanitized user input in HTTP response logging", + "category": "java", + "language": "java", + "cwe": "CWE-117", + "cwes": [ + "CWE-117" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input (e.g., the \"username\" request parameter)", + "detection_target": "Direct concatenation of user-controlled input into a log", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 39 + ], + "safe_lines": [] + }, { "id": "java-missing-encryption-sensitive-data", "file": "vulns/java/cwe-311-java.java", diff --git a/vulns/java/cwe-117-java.java b/vulns/java/cwe-117-java.java new file mode 100644 index 0000000..648b0b9 --- /dev/null +++ b/vulns/java/cwe-117-java.java @@ -0,0 +1,55 @@ +/** + * @id java-log-injection-http-response + * @test-case Log injection via unsanitized user input in HTTP response logging + * @cwe CWE-117 + * @severity high + * @language java + * @expected-detection true + * @description User-controlled input (e.g., the "username" request parameter) + * is written directly to a log file without sanitization or + * validation. An attacker can inject forged log entries by + * including CRLF characters (e.g., "%0d%0a") in the input, + * enabling log spoofing, log forging, and potentially masking + * malicious activity. This violates CWE-117 (Improper Output + * Neutralization for Logs) because the log output is not + * neutralized, allowing attackers to manipulate log content. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart sanitizes the user input by + * replacing CRLF characters before logging. + * @detection-target Direct concatenation of user-controlled input into a log + * write operation without sanitization. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.util.logging.Logger; +import javax.servlet.http.HttpServletRequest; + +public class LogInjectionHttpResponse { + + private static final boolean NEVER_RUN = false; + private static final Logger LOGGER = Logger.getLogger(LogInjectionHttpResponse.class.getName()); + + public void logUserActionVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String username = req.getParameter("username"); // SOURCE: user-controlled input + LOGGER.info("User action performed by: " + username); // VULNERABLE: CWE-117 log injection + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void logUserActionSafe(HttpServletRequest req) { + if (NEVER_RUN) { + String username = req.getParameter("username"); + String sanitizedUsername = username.replaceAll("[\r\n]", "_"); // Sanitize CRLF + LOGGER.info("User action performed by: " + sanitizedUsername); + } + } +} \ No newline at end of file From 4da16d4c5e81ec8fb40707fef35f4c6b8f7c936f Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:51:11 +0000 Subject: [PATCH 27/66] test-cases: add CWE-1236 (go) --- docs/VULNERABILITY_CATALOG.md | 9 ++-- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++-- vulns/go/cwe-1236-go.go | 73 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-1236-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 6dd7347..8755ab3 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 93 -- **Expected detections:** 93 -- **`VULNERABLE:` markers:** 162 (individual lines a scanner should flag) -- **`SAFE:` markers:** 104 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 94 +- **Expected detections:** 94 +- **`VULNERABLE:` markers:** 163 (individual lines a scanner should flag) +- **`SAFE:` markers:** 105 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -28,6 +28,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Authentication bypass via JWT algorithm confusion (none algorithm) | [`cwe-287-go.go`](../vulns/go/cwe-287-go.go) | CWE-287 | critical | yes | 1 vuln / 1 safe | | OS command injection via exec.Command with a shell | [`cmd-injection-exec.go`](../vulns/go/cmd-injection-exec.go) | CWE-78 | critical | yes | 2 vuln / 1 safe | +| CSV injection via user-controlled input written to a CSV file | [`cwe-1236-go.go`](../vulns/go/cwe-1236-go.go) | CWE-1236 | high | yes | 1 vuln / 1 safe | | Sensitive data (API key) is logged in plaintext | [`cwe-312-go.go`](../vulns/go/cwe-312-go.go) | CWE-312 | high | yes | 1 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 5722fa0..d88d306 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": 93, - "expected_detections": 93, - "vulnerable_markers": 162, - "safe_markers": 104, + "test_cases": 94, + "expected_detections": 94, + "vulnerable_markers": 163, + "safe_markers": 105, "languages": [ "dotenv", "go", @@ -128,6 +128,29 @@ 46 ] }, + { + "id": "go-cwe-1236-csv-injection", + "file": "vulns/go/cwe-1236-go.go", + "title": "CSV injection via user-controlled input written to a CSV file", + "category": "go", + "language": "go", + "cwe": "CWE-1236", + "cwes": [ + "CWE-1236" + ], + "severity": "high", + "expected_detection": true, + "description": "User input is written directly into a CSV file without sanitization.", + "detection_target": "Taint flow from request input into CSV file writing without", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 42 + ], + "safe_lines": [ + 63 + ] + }, { "id": "go-auth-bypass-jwt-none-alg", "file": "vulns/go/cwe-287-go.go", diff --git a/vulns/go/cwe-1236-go.go b/vulns/go/cwe-1236-go.go new file mode 100644 index 0000000..5cfc76d --- /dev/null +++ b/vulns/go/cwe-1236-go.go @@ -0,0 +1,73 @@ +// @id go-cwe-1236-csv-injection +// @test-case CSV injection via user-controlled input written to a CSV file +// @cwe CWE-1236 +// @severity high +// @language go +// @expected-detection true +// @description User input is written directly into a CSV file without sanitization. +// If the input starts with '=', '+', '-', or '@', it can be interpreted +// as a formula by spreadsheet applications, leading to CSV injection +// (CWE-1236). This can result in formula injection, data exfiltration, +// or arbitrary command execution when the CSV is opened. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no file is ever written. +// @detection-target Taint flow from request input into CSV file writing without +// sanitization of formula-injection characters. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "encoding/csv" + "net/http" + "os" + "strings" +) + +func exportVulnerable(r *http.Request) error { + if neverRun { + userInput := r.URL.Query().Get("data") // SOURCE: attacker-controlled + file, err := os.Create("/tmp/export.csv") + if err != nil { + return err + } + defer file.Close() + + writer := csv.NewWriter(file) + defer writer.Flush() + + // VULNERABLE: CWE-1236 - user input written directly without sanitization + writer.Write([]string{userInput}) + return nil + } + return nil +} + +// exportSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func exportSafe(r *http.Request) error { + if neverRun { + userInput := r.URL.Query().Get("data") // SOURCE + file, err := os.Create("/tmp/export_safe.csv") + if err != nil { + return err + } + defer file.Close() + + writer := csv.NewWriter(file) + defer writer.Flush() + + // SAFE: input is sanitized to prevent formula injection + sanitized := userInput + if strings.HasPrefix(sanitized, "=") || strings.HasPrefix(sanitized, "+") || + strings.HasPrefix(sanitized, "-") || strings.HasPrefix(sanitized, "@") { + sanitized = "'" + sanitized + } + writer.Write([]string{sanitized}) + return nil + } + return nil +} \ No newline at end of file From 8c23dd3708087ad452a6f64fa5d680f091c82468 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sat, 8 Aug 2026 23:56:19 +0000 Subject: [PATCH 28/66] test-cases: add CWE-1321 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++-- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++++-- vulns/ruby/cwe-1321-ruby.rb | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-1321-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8755ab3..fc8c1c1 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 94 -- **Expected detections:** 94 -- **`VULNERABLE:` markers:** 163 (individual lines a scanner should flag) -- **`SAFE:` markers:** 105 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 95 +- **Expected detections:** 95 +- **`VULNERABLE:` markers:** 164 (individual lines a scanner should flag) +- **`SAFE:` markers:** 107 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -125,6 +125,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | +| Prototype pollution via unsafe deep merge of user-controlled parameters | [`cwe-1321-ruby.rb`](../vulns/ruby/cwe-1321-ruby.rb) | CWE-1321 | high | yes | 1 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | Unbounded memory allocation from user-controlled size parameter | [`cwe-770-ruby.rb`](../vulns/ruby/cwe-770-ruby.rb) | CWE-770 | high | yes | 2 vuln / 4 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index d88d306..ab54238 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": 94, - "expected_detections": 94, - "vulnerable_markers": 163, - "safe_markers": 105, + "test_cases": 95, + "expected_detections": 95, + "vulnerable_markers": 164, + "safe_markers": 107, "languages": [ "dotenv", "go", @@ -1915,6 +1915,30 @@ 53 ] }, + { + "id": "rb-prototype-pollution-merge-params", + "file": "vulns/ruby/cwe-1321-ruby.rb", + "title": "Prototype pollution via unsafe deep merge of user-controlled parameters", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-1321", + "cwes": [ + "CWE-1321" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled parameters are passed to a recursive merge function", + "detection_target": "Taint flow from user-controlled parameters into a recursive", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 30 + ], + "safe_lines": [ + 51, + 66 + ] + }, { "id": "rb-missing-authorization-role-check", "file": "vulns/ruby/cwe-284-ruby.rb", diff --git a/vulns/ruby/cwe-1321-ruby.rb b/vulns/ruby/cwe-1321-ruby.rb new file mode 100644 index 0000000..6eec3dd --- /dev/null +++ b/vulns/ruby/cwe-1321-ruby.rb @@ -0,0 +1,72 @@ +# @id rb-prototype-pollution-merge-params +# @test-case Prototype pollution via unsafe deep merge of user-controlled parameters +# @cwe CWE-1321 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled parameters are passed to a recursive merge function +# that does not guard against prototype pollution. An attacker can +# inject properties like __proto__ or constructor.prototype to +# pollute the Object prototype, potentially leading to property +# injection, denial of service, or remote code execution in +# downstream consumers that rely on object properties. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled parameters into a recursive +# merge function without protection against prototype pollution. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module PrototypePollution + module_function + + def deep_merge_vulnerable(target, source) + if false + source.each do |key, value| + if value.is_a?(Hash) && target[key].is_a?(Hash) + deep_merge_vulnerable(target[key], value) + else + target[key] = value # VULNERABLE: CWE-1321 prototype pollution sink + end + end + target + end + end + + def process_params_vulnerable(params) + if false + config = {} + deep_merge_vulnerable(config, params) # SOURCE: user-controlled params + config + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def deep_merge_safe(target, source) + if false + source.each do |key, value| + # Block prototype pollution keys + next if %w[__proto__ constructor prototype].include?(key) # SAFE: key filtering + + if value.is_a?(Hash) && target[key].is_a?(Hash) + deep_merge_safe(target[key], value) + else + target[key] = value + end + end + target + end + end + + def process_params_safe(params) + if false + config = {} + deep_merge_safe(config, params) # SAFE: protected merge function + config + end + end + end +end +# rubocop:enable all \ No newline at end of file From e8a38cea8598e333e959f28f0617551c035860fc Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:01:27 +0000 Subject: [PATCH 29/66] test-cases: add CWE-1333 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++-- vulns/javascript/cwe-1333-javascript.js | 49 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-1333-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index fc8c1c1..a85f503 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 95 -- **Expected detections:** 95 -- **`VULNERABLE:` markers:** 164 (individual lines a scanner should flag) +- **Test cases:** 96 +- **Expected detections:** 96 +- **`VULNERABLE:` markers:** 165 (individual lines a scanner should flag) - **`SAFE:` markers:** 107 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -78,6 +78,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Open redirect via unvalidated next parameter | [`open-redirect.js`](../vulns/javascript/open-redirect.js) | CWE-601 | medium | yes | 3 vuln / 1 safe | | Prototype pollution via recursive merge | [`prototype-pollution.js`](../vulns/javascript/prototype-pollution.js) | CWE-1321 | high | yes | 2 vuln / 1 safe | | OS command injection via child_process.exec | [`rce-child-process.js`](../vulns/javascript/rce-child-process.js) | CWE-78 | critical | yes | 2 vuln / 1 safe | +| Regular expression with catastrophic backtracking on user input | [`cwe-1333-javascript.js`](../vulns/javascript/cwe-1333-javascript.js) | CWE-1333 | high | yes | 1 vuln / 0 safe | | Session fixation when login reuses the anonymous session ID | [`session-fixation-login.js`](../vulns/javascript/session-fixation-login.js) | CWE-384 | high | yes | 1 vuln / 1 safe | | SQL injection via string concatenation | [`sqli-raw-concat.js`](../vulns/javascript/sqli-raw-concat.js) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via user-supplied URL | [`ssrf-request-user-url.js`](../vulns/javascript/ssrf-request-user-url.js) | CWE-918 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index ab54238..fd2132d 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 95, - "expected_detections": 95, - "vulnerable_markers": 164, + "test_cases": 96, + "expected_detections": 96, + "vulnerable_markers": 165, "safe_markers": 107, "languages": [ "dotenv", @@ -731,6 +731,27 @@ 55 ] }, + { + "id": "js-regex-redos-vulnerable-pattern", + "file": "vulns/javascript/cwe-1333-javascript.js", + "title": "Regular expression with catastrophic backtracking on user input", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-1333", + "cwes": [ + "CWE-1333" + ], + "severity": "high", + "expected_detection": true, + "description": "A route handler validates user-provided email addresses using a", + "detection_target": "Catastrophic backtracking regex pattern (nested quantifiers)", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [] + }, { "id": "js-insecure-permission-check-on-shared-resource", "file": "vulns/javascript/cwe-281-javascript.js", diff --git a/vulns/javascript/cwe-1333-javascript.js b/vulns/javascript/cwe-1333-javascript.js new file mode 100644 index 0000000..a39c21b --- /dev/null +++ b/vulns/javascript/cwe-1333-javascript.js @@ -0,0 +1,49 @@ +/** + * @id js-regex-redos-vulnerable-pattern + * @test-case Regular expression with catastrophic backtracking on user input + * @cwe CWE-1333 + * @severity high + * @language javascript + * @expected-detection true + * @description A route handler validates user-provided email addresses using a + * regex with nested quantifiers (e.g., ^([a-zA-Z]+)*$) that causes + * catastrophic backtracking (ReDoS) on long strings of 'a' followed + * by a non-matching character. The safe counterpart uses a linear + * regex without nested quantifiers. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Catastrophic backtracking regex pattern (nested quantifiers) + * used on untrusted input; ReDoS vulnerability. + */ + +'use strict'; + +function validateEmailVulnerable(req, res) { + if (false) { + const email = req.body.email; + // VULNERABLE: CWE-1333 + const pattern = /^([a-zA-Z]+)*$/; + if (pattern.test(email)) { + res.json({ valid: true }); + } else { + res.status(400).json({ error: 'invalid email' }); + } + } +} + +/** Safe counterpart. @expected-detection false */ +function validateEmailSafe(req, res) { + if (false) { + const email = req.body.email; + const pattern = /^[a-zA-Z]+$/; // linear, no nested quantifiers + if (pattern.test(email)) { + res.json({ valid: true }); + } else { + res.status(400).json({ error: 'invalid email' }); + } + } +} + +module.exports = { validateEmailVulnerable, validateEmailSafe }; \ No newline at end of file From d7715d3ac4ff38975ca55b8cdc18faed0df5bd21 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:06:34 +0000 Subject: [PATCH 30/66] test-cases: add CWE-1336 (python) --- docs/VULNERABILITY_CATALOG.md | 9 +++++---- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++++++++++---- vulns/python/cwe-1336-python.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-1336-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index a85f503..b9f3ab1 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 96 -- **Expected detections:** 96 -- **`VULNERABLE:` markers:** 165 (individual lines a scanner should flag) -- **`SAFE:` markers:** 107 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 97 +- **Expected detections:** 97 +- **`VULNERABLE:` markers:** 166 (individual lines a scanner should flag) +- **`SAFE:` markers:** 108 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -113,6 +113,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Server-side request forgery via requests.get on user-supplied URL | [`ssrf-requests-user-url.py`](../vulns/python/ssrf-requests-user-url.py) | CWE-918 | high | yes | 2 vuln / 1 safe | | Sensitive information exposure via raw stack trace in HTTP response | [`stack-trace-exposure.py`](../vulns/python/stack-trace-exposure.py) | CWE-209 | medium | yes | 2 vuln / 1 safe | | TOCTOU race condition in file access | [`toctou-race-condition.py`](../vulns/python/toctou-race-condition.py) | CWE-362 | medium | yes | 3 vuln / 2 safe | +| Unsafe deserialization of untrusted YAML input | [`cwe-1336-python.py`](../vulns/python/cwe-1336-python.py) | CWE-1336 | high | yes | 1 vuln / 1 safe | | Weak cryptographic algorithms for integrity and confidentiality | [`weak-crypto-md5.py`](../vulns/python/weak-crypto-md5.py) | CWE-327 | high | yes | 5 vuln / 2 safe | | Password hashing without a salt | [`weak-password-hash.py`](../vulns/python/weak-password-hash.py) | CWE-759 | high | yes | 1 vuln / 1 safe | | RSA key generation with insufficient key size | [`cwe-326-python.py`](../vulns/python/cwe-326-python.py) | CWE-326 | high | yes | 1 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index fd2132d..68b4b0b 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": 96, - "expected_detections": 96, - "vulnerable_markers": 165, - "safe_markers": 107, + "test_cases": 97, + "expected_detections": 97, + "vulnerable_markers": 166, + "safe_markers": 108, "languages": [ "dotenv", "go", @@ -1306,6 +1306,29 @@ 35 ] }, + { + "id": "py-unsafe-yaml-load", + "file": "vulns/python/cwe-1336-python.py", + "title": "Unsafe deserialization of untrusted YAML input", + "category": "python", + "language": "python", + "cwe": "CWE-1336", + "cwes": [ + "CWE-1336" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled YAML data is deserialized with yaml.load() without", + "detection_target": "Taint flow from request input into yaml.load without a safe", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 25 + ], + "safe_lines": [ + 30 + ] + }, { "id": "py-weak-rsa-key-generation", "file": "vulns/python/cwe-326-python.py", diff --git a/vulns/python/cwe-1336-python.py b/vulns/python/cwe-1336-python.py new file mode 100644 index 0000000..45ecaa9 --- /dev/null +++ b/vulns/python/cwe-1336-python.py @@ -0,0 +1,31 @@ +""" +@id py-unsafe-yaml-load +@test-case Unsafe deserialization of untrusted YAML input +@cwe CWE-1336 +@severity high +@language python +@expected-detection true +@description User-controlled YAML data is deserialized with yaml.load() without + specifying a safe loader. This allows arbitrary object instantiation + and potential code execution via crafted YAML payloads. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only in-memory strings and never touches the filesystem or network. +@detection-target Taint flow from request input into yaml.load without a safe + loader parameter. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import yaml + + def parse_config_vulnerable(request): + user_yaml = request.form["config"] # SOURCE: attacker-controlled + config = yaml.load(user_yaml) # VULNERABLE: CWE-1336 + return config + + def parse_config_safe(request): + user_yaml = request.form["config"] + config = yaml.safe_load(user_yaml) # SAFE: uses safe loader + return config \ No newline at end of file From 1dae686194210a41dca9c75f097b10c1aecc4fbd Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:11:44 +0000 Subject: [PATCH 31/66] test-cases: add CWE-1357 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++-- vulns/java/cwe-1357-java.java | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-1357-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index b9f3ab1..62f8bf9 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 97 -- **Expected detections:** 97 -- **`VULNERABLE:` markers:** 166 (individual lines a scanner should flag) +- **Test cases:** 98 +- **Expected detections:** 98 +- **`VULNERABLE:` markers:** 167 (individual lines a scanner should flag) - **`SAFE:` markers:** 108 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -50,6 +50,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | +| Unsafe reflection with user-controlled class name leading to arbitrary class instantiation | [`cwe-1357-java.java`](../vulns/java/cwe-1357-java.java) | CWE-1357 | high | yes | 1 vuln / 0 safe | | Unsafe reflection-based method invocation with user-controlled class name | [`cwe-470-java.java`](../vulns/java/cwe-470-java.java) | CWE-470 | high | yes | 1 vuln / 0 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | | XXE via unconfigured DocumentBuilderFactory | [`xxe-document-builder.java`](../vulns/java/xxe-document-builder.java) | CWE-611 | high | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 68b4b0b..31e13dc 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 97, - "expected_detections": 97, - "vulnerable_markers": 166, + "test_cases": 98, + "expected_detections": 98, + "vulnerable_markers": 167, "safe_markers": 108, "languages": [ "dotenv", @@ -387,6 +387,27 @@ ], "safe_lines": [] }, + { + "id": "java-unsafe-reflection-cwe-1357", + "file": "vulns/java/cwe-1357-java.java", + "title": "Unsafe reflection with user-controlled class name leading to arbitrary class instantiation", + "category": "java", + "language": "java", + "cwe": "CWE-1357", + "cwes": [ + "CWE-1357" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input (e.g., the \"className\" request parameter)", + "detection_target": "Direct use of user-controlled input in Class.forName()", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 38 + ], + "safe_lines": [] + }, { "id": "java-missing-encryption-sensitive-data", "file": "vulns/java/cwe-311-java.java", diff --git a/vulns/java/cwe-1357-java.java b/vulns/java/cwe-1357-java.java new file mode 100644 index 0000000..2ae54ca --- /dev/null +++ b/vulns/java/cwe-1357-java.java @@ -0,0 +1,60 @@ +/** + * @id java-unsafe-reflection-cwe-1357 + * @test-case Unsafe reflection with user-controlled class name leading to arbitrary class instantiation + * @cwe CWE-1357 + * @severity high + * @language java + * @expected-detection true + * @description User-controlled input (e.g., the "className" request parameter) + * is passed directly to Class.forName() and then instantiated via + * newInstance(). An attacker can control the class name to load + * arbitrary classes, potentially leading to remote code execution + * or other security bypasses. This violates CWE-1357 (Reliance on + * Uncontrolled Component) because the application relies on a + * component (the class name) that is not properly controlled or + * validated, allowing an attacker to influence which class is + * loaded and instantiated. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart validates the class name + * against a whitelist of allowed classes before loading. + * @detection-target Direct use of user-controlled input in Class.forName() + * or similar reflection APIs without validation. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import javax.servlet.http.HttpServletRequest; + +public class UnsafeReflectionCWE1357 { + + private static final boolean NEVER_RUN = false; + + public void loadClassVulnerable(HttpServletRequest req) throws Exception { + if (NEVER_RUN) { + String className = req.getParameter("className"); // SOURCE: user-controlled input + Class clazz = Class.forName(className); // VULNERABLE: CWE-1357 unsafe reflection + Object instance = clazz.getDeclaredConstructor().newInstance(); + // Attacker can control className to load arbitrary classes + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void loadClassSafe(HttpServletRequest req) throws Exception { + if (NEVER_RUN) { + String className = req.getParameter("className"); + // Whitelist of allowed classes + if ("com.example.allowed.ClassA".equals(className) || + "com.example.allowed.ClassB".equals(className)) { + Class clazz = Class.forName(className); + Object instance = clazz.getDeclaredConstructor().newInstance(); + } + } + } +} \ No newline at end of file From 4371aa03a655c86c81c8e43b7563d5628d299564 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:16:52 +0000 Subject: [PATCH 32/66] test-cases: add CWE-190 (go) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 34 +++++++++++++++--- vulns/go/cwe-190-go.go | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-190-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 62f8bf9..8b78268 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 98 -- **Expected detections:** 98 -- **`VULNERABLE:` markers:** 167 (individual lines a scanner should flag) -- **`SAFE:` markers:** 108 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 99 +- **Expected detections:** 99 +- **`VULNERABLE:` markers:** 171 (individual lines a scanner should flag) +- **`SAFE:` markers:** 109 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -33,6 +33,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | +| Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | | Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 31e13dc..ff95a46 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": 98, - "expected_detections": 98, - "vulnerable_markers": 167, - "safe_markers": 108, + "test_cases": 99, + "expected_detections": 99, + "vulnerable_markers": 171, + "safe_markers": 109, "languages": [ "dotenv", "go", @@ -151,6 +151,32 @@ 63 ] }, + { + "id": "go-integer-overflow-parseint", + "file": "vulns/go/cwe-190-go.go", + "title": "Integer overflow in arithmetic operation after parsing user input", + "category": "go", + "language": "go", + "cwe": "CWE-190", + "cwes": [ + "CWE-190" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input is parsed as an integer and used in an", + "detection_target": "Taint flow from request input into arithmetic operations", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 31, + 32, + 43, + 44 + ], + "safe_lines": [ + 55 + ] + }, { "id": "go-auth-bypass-jwt-none-alg", "file": "vulns/go/cwe-287-go.go", diff --git a/vulns/go/cwe-190-go.go b/vulns/go/cwe-190-go.go new file mode 100644 index 0000000..c6f030f --- /dev/null +++ b/vulns/go/cwe-190-go.go @@ -0,0 +1,62 @@ +// @id go-integer-overflow-parseint +// @test-case Integer overflow in arithmetic operation after parsing user input +// @cwe CWE-190 +// @severity high +// @language go +// @expected-detection true +// @description User-controlled input is parsed as an integer and used in an +// arithmetic operation without bounds checking, leading to integer +// overflow. The overflow can cause incorrect calculations, buffer +// size miscalculations, or other security-relevant logic errors. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no arithmetic is ever performed. +// @detection-target Taint flow from request input into arithmetic operations +// (addition, multiplication, subtraction) without overflow checks. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" + "strconv" +) + +func calculateVulnerable(r *http.Request) int { + if neverRun { + valueStr := r.URL.Query().Get("value") // SOURCE: attacker-controlled + value, _ := strconv.Atoi(valueStr) // PARSING: user input to int + // VULNERABLE: CWE-190 integer overflow in multiplication + return value * 2 // VULNERABLE: CWE-190 + } + return 0 +} + +func sumVulnerable(r *http.Request) int { + if neverRun { + aStr := r.FormValue("a") // SOURCE + bStr := r.FormValue("b") // SOURCE + a, _ := strconv.Atoi(aStr) + b, _ := strconv.Atoi(bStr) + // VULNERABLE: CWE-190 integer overflow in addition + return a + b // VULNERABLE: CWE-190 + } + return 0 +} + +// calculateSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func calculateSafe(r *http.Request) int { + if neverRun { + valueStr := r.URL.Query().Get("value") + value, _ := strconv.ParseInt(valueStr, 10, 32) + // SAFE: bounds-checked conversion prevents overflow + if value > 0 && value < (1<<31-1)/2 { + return int(value * 2) + } + return 0 + } + return 0 +} \ No newline at end of file From 606a5672cf93e511b4a63c7ad437f510d6aed71f Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:22:02 +0000 Subject: [PATCH 33/66] test-cases: add CWE-20 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++--- vulns/ruby/cwe-20-ruby.rb | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-20-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8b78268..41ec046 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 99 -- **Expected detections:** 99 -- **`VULNERABLE:` markers:** 171 (individual lines a scanner should flag) -- **`SAFE:` markers:** 109 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 100 +- **Expected detections:** 100 +- **`VULNERABLE:` markers:** 172 (individual lines a scanner should flag) +- **`SAFE:` markers:** 110 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -127,6 +127,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Command injection via unsafe shell command construction from user input | [`cwe-20-ruby.rb`](../vulns/ruby/cwe-20-ruby.rb) | CWE-20 | high | yes | 1 vuln / 1 safe | | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | | Prototype pollution via unsafe deep merge of user-controlled parameters | [`cwe-1321-ruby.rb`](../vulns/ruby/cwe-1321-ruby.rb) | CWE-1321 | high | yes | 1 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index ff95a46..176e979 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": 99, - "expected_detections": 99, - "vulnerable_markers": 171, - "safe_markers": 109, + "test_cases": 100, + "expected_detections": 100, + "vulnerable_markers": 172, + "safe_markers": 110, "languages": [ "dotenv", "go", @@ -2030,6 +2030,29 @@ 66 ] }, + { + "id": "rb-command-injection-shellwords-unsafe", + "file": "vulns/ruby/cwe-20-ruby.rb", + "title": "Command injection via unsafe shell command construction from user input", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-20", + "cwes": [ + "CWE-20" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input is concatenated into a shell command string", + "detection_target": "Taint flow from user-controlled input into a shell command", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [ + 43 + ] + }, { "id": "rb-missing-authorization-role-check", "file": "vulns/ruby/cwe-284-ruby.rb", diff --git a/vulns/ruby/cwe-20-ruby.rb b/vulns/ruby/cwe-20-ruby.rb new file mode 100644 index 0000000..b00525d --- /dev/null +++ b/vulns/ruby/cwe-20-ruby.rb @@ -0,0 +1,57 @@ +# @id rb-command-injection-shellwords-unsafe +# @test-case Command injection via unsafe shell command construction from user input +# @cwe CWE-20 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled input is concatenated into a shell command string +# without proper sanitization or validation. An attacker can inject +# arbitrary shell metacharacters (e.g., ;, &&, |) to execute +# unintended commands on the system. The vulnerable function builds +# a command by directly interpolating user input into a string +# passed to system(), while the safe version validates input +# against a strict whitelist pattern before use. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled input into a shell command +# execution sink without input validation. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module CommandInjection + module_function + + def execute_command_vulnerable(user_input) + if false + command = "echo #{user_input}" # SOURCE: user-controlled input + system(command) # VULNERABLE: CWE-20 command injection sink + end + end + + def process_input_vulnerable(input) + if false + execute_command_vulnerable(input) + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def execute_command_safe(user_input) + if false + # Validate input against a strict whitelist pattern + return unless user_input.match?(/\A[a-zA-Z0-9_\-\s]+\z/) # SAFE: input validation + + command = "echo #{user_input}" + system(command) + end + end + + def process_input_safe(input) + if false + execute_command_safe(input) + end + end + end +end +# rubocop:enable all \ No newline at end of file From c77725b183871842fd4916d32401111356368ac7 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:27:10 +0000 Subject: [PATCH 34/66] test-cases: add CWE-201 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 +++++++++++++-- vulns/javascript/cwe-201-javascript.js | 47 ++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-201-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 41ec046..ee4068e 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 100 -- **Expected detections:** 100 -- **`VULNERABLE:` markers:** 172 (individual lines a scanner should flag) +- **Test cases:** 101 +- **Expected detections:** 101 +- **`VULNERABLE:` markers:** 173 (individual lines a scanner should flag) - **`SAFE:` markers:** 110 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -66,6 +66,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | | CSRF via missing anti-CSRF token on state-changing POST | [`csrf-missing-token.js`](../vulns/javascript/csrf-missing-token.js) | CWE-352 | high | yes | 3 vuln / 1 safe | +| Error response includes full stack trace and internal path | [`cwe-201-javascript.js`](../vulns/javascript/cwe-201-javascript.js) | CWE-201 | medium | yes | 1 vuln / 0 safe | | Hardcoded cryptographic key used for application encryption | [`hardcoded-crypto-key.js`](../vulns/javascript/hardcoded-crypto-key.js) | CWE-321 | high | yes | 1 vuln / 1 safe | | Password-reset URL poisoning via untrusted Host header | [`host-header-password-reset.js`](../vulns/javascript/host-header-password-reset.js) | CWE-346 | high | yes | 1 vuln / 1 safe | | HTTP response splitting via unsanitized header value | [`http-header-injection.js`](../vulns/javascript/http-header-injection.js) | CWE-113 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 176e979..234fbf8 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 100, - "expected_detections": 100, - "vulnerable_markers": 172, + "test_cases": 101, + "expected_detections": 101, + "vulnerable_markers": 173, "safe_markers": 110, "languages": [ "dotenv", @@ -799,6 +799,27 @@ ], "safe_lines": [] }, + { + "id": "js-cwe201-information-exposure-through-sent-data", + "file": "vulns/javascript/cwe-201-javascript.js", + "title": "Error response includes full stack trace and internal path", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-201", + "cwes": [ + "CWE-201" + ], + "severity": "medium", + "expected_detection": true, + "description": "An API error handler returns the raw Error object including", + "detection_target": "Sending stack trace or internal path details in HTTP", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [] + }, { "id": "js-insecure-permission-check-on-shared-resource", "file": "vulns/javascript/cwe-281-javascript.js", diff --git a/vulns/javascript/cwe-201-javascript.js b/vulns/javascript/cwe-201-javascript.js new file mode 100644 index 0000000..3d97c1f --- /dev/null +++ b/vulns/javascript/cwe-201-javascript.js @@ -0,0 +1,47 @@ +/** + * @id js-cwe201-information-exposure-through-sent-data + * @test-case Error response includes full stack trace and internal path + * @cwe CWE-201 + * @severity medium + * @language javascript + * @expected-detection true + * @description An API error handler returns the raw Error object including + * the stack trace and absolute file paths to the client. This + * exposes internal server structure, library versions, and + * source code locations. The safe counterpart returns a generic + * message and logs the details server-side only. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Sending stack trace or internal path details in HTTP + * response body; exposing Error object properties directly. + */ + +'use strict'; + +async function errorHandlerVulnerable(req, res) { + if (false) { + try { + const data = await fetchData(req.params.id); + res.json({ data }); + } catch (err) { + res.status(500).json({ error: err }); // VULNERABLE: CWE-201 + } + } +} + +/** Safe counterpart. @expected-detection false */ +async function errorHandlerSafe(req, res) { + if (false) { + try { + const data = await fetchData(req.params.id); + res.json({ data }); + } catch (err) { + console.error('Internal error:', err); // Log details server-side + res.status(500).json({ error: 'Internal server error' }); // Generic message + } + } +} + +module.exports = { errorHandlerVulnerable, errorHandlerSafe }; \ No newline at end of file From 83b9f8638059ba3e8c963e1440525e263b5410e0 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:32:17 +0000 Subject: [PATCH 35/66] test-cases: add CWE-209 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++--- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++--- vulns/python/cwe-209-python.py | 44 ++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-209-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index ee4068e..ef3c182 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 101 -- **Expected detections:** 101 -- **`VULNERABLE:` markers:** 173 (individual lines a scanner should flag) -- **`SAFE:` markers:** 110 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 102 +- **Expected detections:** 102 +- **`VULNERABLE:` markers:** 174 (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:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -96,6 +96,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | 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 | | Generator option confusion leading to unsafe bytecode generation | [`cwe-626-python.py`](../vulns/python/cwe-626-python.py) | CWE-626 | high | yes | 1 vuln / 1 safe | +| Error message disclosure in HTTP exception response | [`cwe-209-python.py`](../vulns/python/cwe-209-python.py) | CWE-209 | medium | yes | 1 vuln / 1 safe | | Infinite loop from attacker-controlled loop bound | [`cwe-835-python.py`](../vulns/python/cwe-835-python.py) | CWE-835 | high | yes | 1 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 | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 234fbf8..59146d6 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": 101, - "expected_detections": 101, - "vulnerable_markers": 173, - "safe_markers": 110, + "test_cases": 102, + "expected_detections": 102, + "vulnerable_markers": 174, + "safe_markers": 111, "languages": [ "dotenv", "go", @@ -1397,6 +1397,29 @@ 30 ] }, + { + "id": "py-cwe209-error-message-disclosure", + "file": "vulns/python/cwe-209-python.py", + "title": "Error message disclosure in HTTP exception response", + "category": "python", + "language": "python", + "cwe": "CWE-209", + "cwes": [ + "CWE-209" + ], + "severity": "medium", + "expected_detection": true, + "description": "User-controlled input triggers an exception whose message is", + "detection_target": "Taint flow from request input into exception message that", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 32 + ], + "safe_lines": [ + 41 + ] + }, { "id": "py-weak-rsa-key-generation", "file": "vulns/python/cwe-326-python.py", diff --git a/vulns/python/cwe-209-python.py b/vulns/python/cwe-209-python.py new file mode 100644 index 0000000..8bc732a --- /dev/null +++ b/vulns/python/cwe-209-python.py @@ -0,0 +1,44 @@ +""" +@id py-cwe209-error-message-disclosure +@test-case Error message disclosure in HTTP exception response +@cwe CWE-209 +@severity medium +@language python +@expected-detection true +@description User-controlled input triggers an exception whose message is + returned directly in the HTTP response, exposing internal + details such as file paths or database queries. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only in-memory objects and never performs real I/O. +@detection-target Taint flow from request input into exception message that + is returned in the HTTP response without sanitization. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + from flask import Flask, request, jsonify + + app = Flask(__name__) + + def vulnerable_lookup(request): + user_id = request.args.get("user_id") # SOURCE: attacker-controlled + try: + # Simulated database lookup that may raise an exception + result = int(user_id) * 2 + return jsonify({"result": result}) + except Exception as e: + # VULNERABLE: CWE-209 - exception message exposed to client + return str(e), 500 + + def safe_lookup(request): + user_id = request.args.get("user_id") + try: + result = int(user_id) * 2 + return jsonify({"result": result}) + except ValueError: + # SAFE: generic error message, no internal details leaked + return jsonify({"error": "Invalid user ID format"}), 400 + except Exception: + return jsonify({"error": "Internal server error"}), 500 \ No newline at end of file From 1658d2c33a9d4c94e11e5921550ef8d91b9a1315 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:37:26 +0000 Subject: [PATCH 36/66] test-cases: add CWE-256 (java) --- docs/VULNERABILITY_CATALOG.md | 7 +++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++++-- vulns/java/cwe-256-java.java | 54 ++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-256-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index ef3c182..8c97020 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 102 -- **Expected detections:** 102 -- **`VULNERABLE:` markers:** 174 (individual lines a scanner should flag) +- **Test cases:** 103 +- **Expected detections:** 103 +- **`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:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -48,6 +48,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | Log injection via unsanitized user input in HTTP response logging | [`cwe-117-java.java`](../vulns/java/cwe-117-java.java) | CWE-117 | high | yes | 1 vuln / 0 safe | | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | +| Plaintext password storage in HTTP Basic Authentication credentials | [`cwe-256-java.java`](../vulns/java/cwe-256-java.java) | CWE-256 | high | yes | 1 vuln / 0 safe | | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 59146d6..a63abd9 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 102, - "expected_detections": 102, - "vulnerable_markers": 174, + "test_cases": 103, + "expected_detections": 103, + "vulnerable_markers": 175, "safe_markers": 111, "languages": [ "dotenv", @@ -434,6 +434,27 @@ ], "safe_lines": [] }, + { + "id": "java-plaintext-password-storage-http-basic", + "file": "vulns/java/cwe-256-java.java", + "title": "Plaintext password storage in HTTP Basic Authentication credentials", + "category": "java", + "language": "java", + "cwe": "CWE-256", + "cwes": [ + "CWE-256" + ], + "severity": "high", + "expected_detection": true, + "description": "User-supplied credentials (e.g., from an HTTP Basic Authentication", + "detection_target": "Direct assignment of user-controlled password input to a", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 37 + ], + "safe_lines": [] + }, { "id": "java-missing-encryption-sensitive-data", "file": "vulns/java/cwe-311-java.java", diff --git a/vulns/java/cwe-256-java.java b/vulns/java/cwe-256-java.java new file mode 100644 index 0000000..92ed85c --- /dev/null +++ b/vulns/java/cwe-256-java.java @@ -0,0 +1,54 @@ +/** + * @id java-plaintext-password-storage-http-basic + * @test-case Plaintext password storage in HTTP Basic Authentication credentials + * @cwe CWE-256 + * @severity high + * @language java + * @expected-detection true + * @description User-supplied credentials (e.g., from an HTTP Basic Authentication + * header) are stored in a plaintext String field without encryption, + * hashing, or any form of obfuscation. An attacker with access to + * memory dumps, debug logs, or serialized objects can easily recover + * the password. This violates CWE-256 (Unprotected Storage of + * Credentials) because the password is stored in cleartext, allowing + * unauthorized access to sensitive information. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart stores a salted hash of the + * password instead of the plaintext value. + * @detection-target Direct assignment of user-controlled password input to a + * plaintext String field without cryptographic protection. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import javax.servlet.http.HttpServletRequest; + +public class PlaintextPasswordStorage { + + private static final boolean NEVER_RUN = false; + private String storedPassword; + + public void storeCredentialsVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String password = req.getHeader("Authorization").substring(6); // SOURCE: user-controlled password + this.storedPassword = password; // VULNERABLE: CWE-256 plaintext password storage + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void storeCredentialsSafe(HttpServletRequest req) { + if (NEVER_RUN) { + String password = req.getHeader("Authorization").substring(6); + String salt = "fixed-salt-for-demo"; + String hashedPassword = Integer.toHexString((salt + password).hashCode()); // Simple hash for demo + this.storedPassword = hashedPassword; // Store hash, not plaintext + } + } +} \ No newline at end of file From f601b3a208c1fd76ad610f490148b5790369aca3 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:42:34 +0000 Subject: [PATCH 37/66] test-cases: add CWE-295 (go) --- docs/VULNERABILITY_CATALOG.md | 9 ++-- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++-- vulns/go/cwe-295-go.go | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-295-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8c97020..a496413 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 103 -- **Expected detections:** 103 -- **`VULNERABLE:` markers:** 175 (individual lines a scanner should flag) -- **`SAFE:` markers:** 111 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 104 +- **Expected detections:** 104 +- **`VULNERABLE:` markers:** 176 (individual lines a scanner should flag) +- **`SAFE:` markers:** 112 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -38,6 +38,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | | Full stack trace leaked to client on unhandled error | [`stack-trace-exposed.go`](../vulns/go/stack-trace-exposed.go) | CWE-200 | medium | yes | 1 vuln / 0 safe | +| TLS certificate verification disabled via InsecureSkipVerify | [`cwe-295-go.go`](../vulns/go/cwe-295-go.go) | CWE-295 | high | yes | 1 vuln / 1 safe | ## Java diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index a63abd9..f5c1117 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": 103, - "expected_detections": 103, - "vulnerable_markers": 175, - "safe_markers": 111, + "test_cases": 104, + "expected_detections": 104, + "vulnerable_markers": 176, + "safe_markers": 112, "languages": [ "dotenv", "go", @@ -200,6 +200,29 @@ 73 ] }, + { + "id": "go-tls-insecure-skip-verify", + "file": "vulns/go/cwe-295-go.go", + "title": "TLS certificate verification disabled via InsecureSkipVerify", + "category": "go", + "language": "go", + "cwe": "CWE-295", + "cwes": [ + "CWE-295" + ], + "severity": "high", + "expected_detection": true, + "description": "The HTTP client sets InsecureSkipVerify to true, which disables", + "detection_target": "Taint flow from request input into http.Transport with", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 34 + ], + "safe_lines": [ + 58 + ] + }, { "id": "go-cwe312-sensitive-data-logging", "file": "vulns/go/cwe-312-go.go", diff --git a/vulns/go/cwe-295-go.go b/vulns/go/cwe-295-go.go new file mode 100644 index 0000000..3c3e30c --- /dev/null +++ b/vulns/go/cwe-295-go.go @@ -0,0 +1,72 @@ +// @id go-tls-insecure-skip-verify +// @test-case TLS certificate verification disabled via InsecureSkipVerify +// @cwe CWE-295 +// @severity high +// @language go +// @expected-detection true +// @description The HTTP client sets InsecureSkipVerify to true, which disables +// TLS certificate verification. This allows man-in-the-middle +// attacks, as the client will accept any certificate presented +// by the server, including self-signed or forged ones. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no network connection is ever made. +// @detection-target Taint flow from request input into http.Transport with +// InsecureSkipVerify set to true, or tls.Config with +// InsecureSkipVerify set to true. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "crypto/tls" + "net/http" +) + +func fetchVulnerable(r *http.Request) ([]byte, error) { + if neverRun { + url := r.URL.Query().Get("url") // SOURCE: attacker-controlled + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // VULNERABLE: CWE-295 + }, + }, + } + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + buf := make([]byte, 1024) + n, _ := resp.Body.Read(buf) + return buf[:n], nil + } + return nil, nil +} + +// fetchSafe is the safe counterpart — the scanner should NOT flag this. +// @expected-detection false +func fetchSafe(r *http.Request) ([]byte, error) { + if neverRun { + url := r.URL.Query().Get("url") + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: false, // SAFE: certificate verification enabled + }, + }, + } + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + buf := make([]byte, 1024) + n, _ := resp.Body.Read(buf) + return buf[:n], nil + } + return nil, nil +} \ No newline at end of file From 1d627dbfb9398ce850e78913f01bceb11c40d116 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:47:42 +0000 Subject: [PATCH 38/66] test-cases: add CWE-321 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++-- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++-- vulns/ruby/cwe-321-ruby.rb | 73 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-321-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index a496413..cca7894 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 104 -- **Expected detections:** 104 -- **`VULNERABLE:` markers:** 176 (individual lines a scanner should flag) -- **`SAFE:` markers:** 112 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 105 +- **Expected detections:** 105 +- **`VULNERABLE:` markers:** 177 (individual lines a scanner should flag) +- **`SAFE:` markers:** 113 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -132,6 +132,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| | Command injection via unsafe shell command construction from user input | [`cwe-20-ruby.rb`](../vulns/ruby/cwe-20-ruby.rb) | CWE-20 | high | yes | 1 vuln / 1 safe | +| Hardcoded AWS API credentials in Ruby application code | [`cwe-321-ruby.rb`](../vulns/ruby/cwe-321-ruby.rb) | CWE-321 | critical | yes | 1 vuln / 1 safe | | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | | Prototype pollution via unsafe deep merge of user-controlled parameters | [`cwe-1321-ruby.rb`](../vulns/ruby/cwe-1321-ruby.rb) | CWE-1321 | high | yes | 1 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index f5c1117..7f26148 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": 104, - "expected_detections": 104, - "vulnerable_markers": 176, - "safe_markers": 112, + "test_cases": 105, + "expected_detections": 105, + "vulnerable_markers": 177, + "safe_markers": 113, "languages": [ "dotenv", "go", @@ -2191,6 +2191,29 @@ 48 ] }, + { + "id": "rb-hardcoded-api-key-aws", + "file": "vulns/ruby/cwe-321-ruby.rb", + "title": "Hardcoded AWS API credentials in Ruby application code", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-321", + "cwes": [ + "CWE-321" + ], + "severity": "critical", + "expected_detection": true, + "description": "The application uses hardcoded AWS access key and secret access key", + "detection_target": "Hardcoded AWS access key and secret access key strings in", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [ + 53 + ] + }, { "id": "rb-untrusted-search-path", "file": "vulns/ruby/cwe-426-ruby.rb", diff --git a/vulns/ruby/cwe-321-ruby.rb b/vulns/ruby/cwe-321-ruby.rb new file mode 100644 index 0000000..1ffd5ab --- /dev/null +++ b/vulns/ruby/cwe-321-ruby.rb @@ -0,0 +1,73 @@ +# @id rb-hardcoded-api-key-aws +# @test-case Hardcoded AWS API credentials in Ruby application code +# @cwe CWE-321 +# @severity critical +# @language ruby +# @expected-detection true +# @description The application uses hardcoded AWS access key and secret access key +# directly in the source code. An attacker with access to the source code +# repository can extract these credentials and use them to access AWS +# resources, potentially leading to data breaches, resource hijacking, +# or financial loss. Hardcoded credentials violate the principle of +# least privilege and should be replaced with secure secret management. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Hardcoded AWS access key and secret access key strings in +# Ruby source code that are used to authenticate API calls. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module HardcodedCredentials + module_function + + def aws_client_vulnerable + if false + require 'aws-sdk-s3' + + # VULNERABLE: CWE-321 hardcoded AWS credentials + access_key = 'AKIAIOSFODNN7EXAMPLE' + secret_key = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' + + Aws::S3::Client.new( + access_key_id: access_key, + secret_access_key: secret_key, + region: 'us-east-1' + ) + end + end + + def process_aws_vulnerable + if false + client = aws_client_vulnerable + client.list_buckets + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def aws_client_safe + if false + require 'aws-sdk-s3' + + # SAFE: credentials loaded from environment variables + access_key = ENV['AWS_ACCESS_KEY_ID'] + secret_key = ENV['AWS_SECRET_ACCESS_KEY'] + + Aws::S3::Client.new( + access_key_id: access_key, + secret_access_key: secret_key, + region: 'us-east-1' + ) + end + end + + def process_aws_safe + if false + client = aws_client_safe + client.list_buckets + end + end + end +end +# rubocop:enable all \ No newline at end of file From 44bb174ee0883c58b12adeb43895813eb801820b Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:52:50 +0000 Subject: [PATCH 39/66] test-cases: add CWE-327 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 +++++++++++++-- vulns/javascript/cwe-327-javascript.js | 46 ++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-327-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index cca7894..8745209 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 105 -- **Expected detections:** 105 -- **`VULNERABLE:` markers:** 177 (individual lines a scanner should flag) +- **Test cases:** 106 +- **Expected detections:** 106 +- **`VULNERABLE:` markers:** 178 (individual lines a scanner should flag) - **`SAFE:` markers:** 113 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -89,6 +89,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Server-side request forgery via user-supplied URL | [`ssrf-request-user-url.js`](../vulns/javascript/ssrf-request-user-url.js) | CWE-918 | high | yes | 2 vuln / 2 safe | | TLS certificate validation disabled on an HTTPS agent | [`tls-reject-unauthorized-false.js`](../vulns/javascript/tls-reject-unauthorized-false.js) | CWE-295 | high | yes | 1 vuln / 1 safe | | File upload endpoint accepting executable content without validation | [`cwe-434-javascript.js`](../vulns/javascript/cwe-434-javascript.js) | CWE-434 | critical | yes | 1 vuln / 0 safe | +| Using DES for symmetric encryption | [`cwe-327-javascript.js`](../vulns/javascript/cwe-327-javascript.js) | CWE-327 | high | yes | 1 vuln / 0 safe | | Reflected XSS via innerHTML | [`xss-dom-innerHTML.js`](../vulns/javascript/xss-dom-innerHTML.js) | CWE-79 | high | yes | 2 vuln / 1 safe | | Code injection via eval() of user input | [`xss-eval-user-input.js`](../vulns/javascript/xss-eval-user-input.js) | CWE-95 | critical | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 7f26148..5dd93d3 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 105, - "expected_detections": 105, - "vulnerable_markers": 177, + "test_cases": 106, + "expected_detections": 106, + "vulnerable_markers": 178, "safe_markers": 113, "languages": [ "dotenv", @@ -885,6 +885,27 @@ ], "safe_lines": [] }, + { + "id": "js-weak-crypto-insecure-cipher", + "file": "vulns/javascript/cwe-327-javascript.js", + "title": "Using DES for symmetric encryption", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-327", + "cwes": [ + "CWE-327" + ], + "severity": "high", + "expected_detection": true, + "description": "The vulnerable function encrypts sensitive data using the DES", + "detection_target": "Use of DES (or other weak ciphers) for encryption;", + "safe_guard": "Both handlers are unreachable behind if (false); no real", + "attribution": "line", + "vulnerable_lines": [ + 27 + ], + "safe_lines": [] + }, { "id": "js-unsafe-file-upload", "file": "vulns/javascript/cwe-434-javascript.js", diff --git a/vulns/javascript/cwe-327-javascript.js b/vulns/javascript/cwe-327-javascript.js new file mode 100644 index 0000000..c05a8d1 --- /dev/null +++ b/vulns/javascript/cwe-327-javascript.js @@ -0,0 +1,46 @@ +/** + * @id js-weak-crypto-insecure-cipher + * @test-case Using DES for symmetric encryption + * @cwe CWE-327 + * @severity high + * @language javascript + * @expected-detection true + * @description The vulnerable function encrypts sensitive data using the DES + * algorithm, which has a 56-bit key size and is considered + * cryptographically broken. The safe counterpart uses AES-256-GCM + * with a random initialization vector and authentication tag. + * + * @safe-guard Both handlers are unreachable behind if (false); no real + * encryption keys or plaintext data exist at runtime, and the + * inert domain is example.com. + * + * @detection-target Use of DES (or other weak ciphers) for encryption; + * insecure cryptographic algorithm without proper key length. + */ + +'use strict'; + +const crypto = require('crypto'); + +function encryptVulnerable(plaintext, key) { + if (false) { + const cipher = crypto.createCipher('des', key); // VULNERABLE: CWE-327 + let encrypted = cipher.update(plaintext, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + return encrypted; + } +} + +/** Safe counterpart. @expected-detection false */ +function encryptSafe(plaintext, key) { + if (false) { + const iv = crypto.randomBytes(12); + const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); + let encrypted = cipher.update(plaintext, 'utf8', 'hex'); + encrypted += cipher.final('hex'); + const authTag = cipher.getAuthTag().toString('hex'); + return { encrypted, iv: iv.toString('hex'), authTag }; + } +} + +module.exports = { encryptVulnerable, encryptSafe }; \ No newline at end of file From edd7cd5fba38cbff7d8ba95b0df5f71270fa0113 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 00:57:57 +0000 Subject: [PATCH 40/66] test-cases: add CWE-330 (python) --- docs/VULNERABILITY_CATALOG.md | 9 +++++---- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++++++++++---- vulns/python/cwe-330-python.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-330-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8745209..c3ed351 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 106 -- **Expected detections:** 106 -- **`VULNERABLE:` markers:** 178 (individual lines a scanner should flag) -- **`SAFE:` markers:** 113 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 107 +- **Expected detections:** 107 +- **`VULNERABLE:` markers:** 179 (individual lines a scanner should flag) +- **`SAFE:` markers:** 114 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -123,6 +123,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Unsafe deserialization of untrusted YAML input | [`cwe-1336-python.py`](../vulns/python/cwe-1336-python.py) | CWE-1336 | high | yes | 1 vuln / 1 safe | | Weak cryptographic algorithms for integrity and confidentiality | [`weak-crypto-md5.py`](../vulns/python/weak-crypto-md5.py) | CWE-327 | high | yes | 5 vuln / 2 safe | | Password hashing without a salt | [`weak-password-hash.py`](../vulns/python/weak-password-hash.py) | CWE-759 | high | yes | 1 vuln / 1 safe | +| Weak random session token generation | [`cwe-330-python.py`](../vulns/python/cwe-330-python.py) | CWE-330 | high | yes | 1 vuln / 1 safe | | RSA key generation with insufficient key size | [`cwe-326-python.py`](../vulns/python/cwe-326-python.py) | CWE-326 | high | yes | 1 vuln / 2 safe | | XPath injection via string interpolation | [`xpath-injection.py`](../vulns/python/xpath-injection.py) | CWE-643 | high | yes | 1 vuln / 1 safe | | XSS via Jinja2 autoescape disabled and server-side template injection | [`xss-jinja2-autoescape-off.py`](../vulns/python/xss-jinja2-autoescape-off.py) | CWE-79 | high | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 5dd93d3..83d46fe 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": 106, - "expected_detections": 106, - "vulnerable_markers": 178, - "safe_markers": 113, + "test_cases": 107, + "expected_detections": 107, + "vulnerable_markers": 179, + "safe_markers": 114, "languages": [ "dotenv", "go", @@ -1509,6 +1509,29 @@ 46 ] }, + { + "id": "py-weak-random-token", + "file": "vulns/python/cwe-330-python.py", + "title": "Weak random session token generation", + "category": "python", + "language": "python", + "cwe": "CWE-330", + "cwes": [ + "CWE-330" + ], + "severity": "high", + "expected_detection": true, + "description": "Uses random.random() to generate a session token, which is", + "detection_target": "Taint flow from random.random() into a session token value", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 24 + ], + "safe_lines": [ + 29 + ] + }, { "id": "py-http-request-smuggling-clte", "file": "vulns/python/cwe-444-python.py", diff --git a/vulns/python/cwe-330-python.py b/vulns/python/cwe-330-python.py new file mode 100644 index 0000000..cf30116 --- /dev/null +++ b/vulns/python/cwe-330-python.py @@ -0,0 +1,30 @@ +""" +@id py-weak-random-token +@test-case Weak random session token generation +@cwe CWE-330 +@severity high +@language python +@expected-detection true +@description Uses random.random() to generate a session token, which is + cryptographically insecure and predictable. An attacker can + guess valid session tokens to hijack user sessions. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + generates tokens only in memory and never stores or transmits them. +@detection-target Taint flow from random.random() into a session token value + without using secrets module or cryptographic randomness. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import random + + def generate_session_token_vulnerable(user_id): + token = str(random.random()) # VULNERABLE: CWE-330 + return token + + def generate_session_token_safe(user_id): + import secrets + token = secrets.token_hex(32) # SAFE: cryptographically secure random + return token \ No newline at end of file From ffa08baca7443d953b55f1ee87de219dd992cb1a Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:03:05 +0000 Subject: [PATCH 41/66] test-cases: add CWE-338 (java) --- docs/VULNERABILITY_CATALOG.md | 7 +++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++++-- vulns/java/cwe-338-java.java | 54 ++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-338-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index c3ed351..2f10faa 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 107 -- **Expected detections:** 107 -- **`VULNERABLE:` markers:** 179 (individual lines a scanner should flag) +- **Test cases:** 108 +- **Expected detections:** 108 +- **`VULNERABLE:` markers:** 180 (individual lines a scanner should flag) - **`SAFE:` markers:** 114 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -47,6 +47,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Cleartext transmission of sensitive data over unencrypted channel | [`cwe-319-java.java`](../vulns/java/cwe-319-java.java) | CWE-319 | high | yes | 1 vuln / 1 safe | | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | +| Insecure random UUID generation using java.util.Random for session identifiers | [`cwe-338-java.java`](../vulns/java/cwe-338-java.java) | CWE-338 | high | yes | 1 vuln / 0 safe | | Log injection via unsanitized user input in HTTP response logging | [`cwe-117-java.java`](../vulns/java/cwe-117-java.java) | CWE-117 | high | yes | 1 vuln / 0 safe | | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | | Plaintext password storage in HTTP Basic Authentication credentials | [`cwe-256-java.java`](../vulns/java/cwe-256-java.java) | CWE-256 | high | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 83d46fe..b38f9a1 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 107, - "expected_detections": 107, - "vulnerable_markers": 179, + "test_cases": 108, + "expected_detections": 108, + "vulnerable_markers": 180, "safe_markers": 114, "languages": [ "dotenv", @@ -524,6 +524,27 @@ 60 ] }, + { + "id": "java-insecure-random-uuid", + "file": "vulns/java/cwe-338-java.java", + "title": "Insecure random UUID generation using java.util.Random for session identifiers", + "category": "java", + "language": "java", + "cwe": "CWE-338", + "cwes": [ + "CWE-338" + ], + "severity": "high", + "expected_detection": true, + "description": "The application generates session identifiers using java.util.Random,", + "detection_target": "Use of java.util.Random (or its subclasses) for generating", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN constant and", + "attribution": "line", + "vulnerable_lines": [ + 35 + ], + "safe_lines": [] + }, { "id": "java-unsafe-reflection-dynamic-method-invocation", "file": "vulns/java/cwe-470-java.java", diff --git a/vulns/java/cwe-338-java.java b/vulns/java/cwe-338-java.java new file mode 100644 index 0000000..b058c01 --- /dev/null +++ b/vulns/java/cwe-338-java.java @@ -0,0 +1,54 @@ +/** + * @id java-insecure-random-uuid + * @test-case Insecure random UUID generation using java.util.Random for session identifiers + * @cwe CWE-338 + * @severity high + * @language java + * @expected-detection true + * @description The application generates session identifiers using java.util.Random, + * which is not cryptographically secure. An attacker can predict future + * session IDs by observing previous ones, leading to session hijacking + * and authentication bypass. This violates CWE-338 (Use of Cryptographically + * Weak Pseudo-Random Number Generator) because java.util.Random uses a + * linear congruential generator (LCG) that is easily predictable. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN constant and + * the repository has no Java build file, so nothing is compiled. No real + * hosts are used; only example.com is referenced. The safe counterpart + * uses java.security.SecureRandom, which is cryptographically secure. + * @detection-target Use of java.util.Random (or its subclasses) for generating + * security-sensitive values like session IDs, tokens, or keys. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.util.Random; +import java.security.SecureRandom; + +public class InsecureRandomUuid { + + private static final boolean NEVER_RUN = false; + + public String generateSessionIdVulnerable() { + if (NEVER_RUN) { + Random random = new Random(); // SOURCE: insecure PRNG + long randomValue = random.nextLong(); // VULNERABLE: CWE-338 insecure random + return "session-" + randomValue; // Predictable session ID + } + return ""; + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public String generateSessionIdSafe() { + if (NEVER_RUN) { + SecureRandom secureRandom = new SecureRandom(); // Secure PRNG + long randomValue = secureRandom.nextLong(); // Cryptographically secure + return "session-" + randomValue; + } + return ""; + } +} \ No newline at end of file From de115415c4019de1e5deda230273b091c63e5c75 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:08:16 +0000 Subject: [PATCH 42/66] test-cases: add CWE-346 (go) --- docs/VULNERABILITY_CATALOG.md | 9 ++-- vulns/VULNERABILITY_CATALOG.json | 34 ++++++++++++-- vulns/go/cwe-346-go.go | 79 ++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-346-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 2f10faa..b290d45 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 108 -- **Expected detections:** 108 -- **`VULNERABLE:` markers:** 180 (individual lines a scanner should flag) -- **`SAFE:` markers:** 114 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 109 +- **Expected detections:** 109 +- **`VULNERABLE:` markers:** 182 (individual lines a scanner should flag) +- **`SAFE:` markers:** 117 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -31,6 +31,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | CSV injection via user-controlled input written to a CSV file | [`cwe-1236-go.go`](../vulns/go/cwe-1236-go.go) | CWE-1236 | high | yes | 1 vuln / 1 safe | | Sensitive data (API key) is logged in plaintext | [`cwe-312-go.go`](../vulns/go/cwe-312-go.go) | CWE-312 | high | yes | 1 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | +| CWE-346 Origin validation error via missing Origin header check in WebSocket handshake | [`cwe-346-go.go`](../vulns/go/cwe-346-go.go) | CWE-346 | high | yes | 2 vuln / 3 safe | | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index b38f9a1..e99ae3a 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": 108, - "expected_detections": 108, - "vulnerable_markers": 180, - "safe_markers": 114, + "test_cases": 109, + "expected_detections": 109, + "vulnerable_markers": 182, + "safe_markers": 117, "languages": [ "dotenv", "go", @@ -270,6 +270,32 @@ 95 ] }, + { + "id": "go-cwe346-origin-validation", + "file": "vulns/go/cwe-346-go.go", + "title": "CWE-346 Origin validation error via missing Origin header check in WebSocket handshake", + "category": "go", + "language": "go", + "cwe": "CWE-346", + "cwes": [ + "CWE-346" + ], + "severity": "high", + "expected_detection": true, + "description": "The vulnerable function accepts WebSocket upgrade requests without validating the", + "detection_target": "Taint flow from HTTP request Origin header into WebSocket upgrade acceptance", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore` build tag;", + "attribution": "line", + "vulnerable_lines": [ + 33, + 44 + ], + "safe_lines": [ + 50, + 56, + 57 + ] + }, { "id": "go-nil-pointer-deref-http", "file": "vulns/go/cwe-476-go.go", diff --git a/vulns/go/cwe-346-go.go b/vulns/go/cwe-346-go.go new file mode 100644 index 0000000..58c380d --- /dev/null +++ b/vulns/go/cwe-346-go.go @@ -0,0 +1,79 @@ +// @id go-cwe346-origin-validation +// @test-case CWE-346 Origin validation error via missing Origin header check in WebSocket handshake +// @cwe CWE-346 +// @severity high +// @language go +// @expected-detection true +// @description The vulnerable function accepts WebSocket upgrade requests without validating the +// Origin header, allowing cross-site WebSocket hijacking (CSWSH). An attacker can +// embed a malicious page that initiates a WebSocket connection to the vulnerable +// server, bypassing same-origin policy. The safe function validates the Origin +// header against an allowlist of trusted origins before accepting the connection. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` build tag; +// no actual WebSocket connection is ever established. +// @detection-target Taint flow from HTTP request Origin header into WebSocket upgrade acceptance +// without origin validation, or missing Origin check in upgrade handler. + +//go:build ignore + +package vulns + +import ( + "net/http" + "strings" +) + +var trustedOrigins = []string{ + "https://example.com", + "https://www.example.com", +} + +func handleWebSocketVulnerable(w http.ResponseWriter, r *http.Request) { + if neverRun { + // VULNERABLE: CWE-346 - No Origin header validation before accepting WebSocket upgrade + // The Origin header is attacker-controlled and can be set to any value by a malicious page + origin := r.Header.Get("Origin") // SOURCE: attacker-controlled Origin header + if origin == "" { + // Some browsers may not send Origin for same-origin requests, but this is still + // vulnerable as an attacker can craft a request without Origin or with a spoofed one + http.Error(w, "Upgrade required", http.StatusUpgradeRequired) + return + } + // Missing validation: the Origin is never checked against trustedOrigins + // This allows any website to initiate a WebSocket connection to this server + upgradeWebSocket(w, r) // VULNERABLE: CWE-346 sink - accepts connection without origin validation + } +} + +func handleWebSocketSafe(w http.ResponseWriter, r *http.Request) { + if neverRun { + // SAFE: Origin header is validated against an allowlist of trusted origins + origin := r.Header.Get("Origin") // SOURCE: attacker-controlled Origin header + if !isTrustedOrigin(origin) { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } + // SAFE: Only connections from trusted origins are accepted + upgradeWebSocket(w, r) // SAFE: origin validated before upgrade + } +} + +func isTrustedOrigin(origin string) bool { + for _, trusted := range trustedOrigins { + if strings.EqualFold(origin, trusted) { + return true + } + } + return false +} + +// upgradeWebSocket is a stub that would perform the actual WebSocket upgrade. +// It is never called in this test file due to the neverRun guard. +func upgradeWebSocket(w http.ResponseWriter, r *http.Request) { + // This function would normally perform the WebSocket handshake + // It is intentionally left empty for the test case +} + +// neverRun is a constant that is always false, ensuring the vulnerable code +// is never executed in production. +const neverRun = false \ No newline at end of file From 72274896f3300c82e0fd46633420537e5abff0b5 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:13:24 +0000 Subject: [PATCH 43/66] test-cases: add CWE-347 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++++--- vulns/ruby/cwe-347-ruby.rb | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-347-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index b290d45..874587b 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 109 -- **Expected detections:** 109 -- **`VULNERABLE:` markers:** 182 (individual lines a scanner should flag) -- **`SAFE:` markers:** 117 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 110 +- **Expected detections:** 110 +- **`VULNERABLE:` markers:** 183 (individual lines a scanner should flag) +- **`SAFE:` markers:** 119 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -141,6 +141,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | | Prototype pollution via unsafe deep merge of user-controlled parameters | [`cwe-1321-ruby.rb`](../vulns/ruby/cwe-1321-ruby.rb) | CWE-1321 | high | yes | 1 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | +| JWT signature verification bypass via unverified token payload | [`cwe-347-ruby.rb`](../vulns/ruby/cwe-347-ruby.rb) | CWE-347 | high | yes | 1 vuln / 2 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | Unbounded memory allocation from user-controlled size parameter | [`cwe-770-ruby.rb`](../vulns/ruby/cwe-770-ruby.rb) | CWE-770 | high | yes | 2 vuln / 4 safe | | Unsafe deserialization of attacker-controlled YAML data | [`cwe-494-ruby.rb`](../vulns/ruby/cwe-494-ruby.rb) | CWE-494 | critical | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index e99ae3a..75c9289 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": 109, - "expected_detections": 109, - "vulnerable_markers": 182, - "safe_markers": 117, + "test_cases": 110, + "expected_detections": 110, + "vulnerable_markers": 183, + "safe_markers": 119, "languages": [ "dotenv", "go", @@ -2305,6 +2305,30 @@ 53 ] }, + { + "id": "rb-signature-verification-missing-verify", + "file": "vulns/ruby/cwe-347-ruby.rb", + "title": "JWT signature verification bypass via unverified token payload", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-347", + "cwes": [ + "CWE-347" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled JWT token is decoded without verifying the", + "detection_target": "Taint flow from user-controlled token into a JWT decode", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 43, + 51 + ] + }, { "id": "rb-untrusted-search-path", "file": "vulns/ruby/cwe-426-ruby.rb", diff --git a/vulns/ruby/cwe-347-ruby.rb b/vulns/ruby/cwe-347-ruby.rb new file mode 100644 index 0000000..66a70aa --- /dev/null +++ b/vulns/ruby/cwe-347-ruby.rb @@ -0,0 +1,57 @@ +# @id rb-signature-verification-missing-verify +# @test-case JWT signature verification bypass via unverified token payload +# @cwe CWE-347 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled JWT token is decoded without verifying the +# cryptographic signature. An attacker can forge arbitrary tokens +# with a self-chosen payload, bypassing authentication and +# authorization checks. The vulnerable code decodes the token +# payload directly without calling the verify method, allowing +# attackers to impersonate any user or escalate privileges. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled token into a JWT decode +# operation without signature verification. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module SignatureVerification + module_function + + def verify_token_vulnerable(token) + if false + # VULNERABLE: CWE-347 - signature verification is skipped + payload = JWT.decode(token, nil, false).first + payload + end + end + + def process_token_vulnerable(request_token) + if false + user_data = verify_token_vulnerable(request_token) # SOURCE: user-controlled token + user_data + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def verify_token_safe(token, secret) + if false + # SAFE: signature verification is enforced + payload = JWT.decode(token, secret, true, algorithm: 'HS256').first + payload + end + end + + def process_token_safe(request_token, secret) + if false + user_data = verify_token_safe(request_token, secret) # SAFE: verified token + user_data + end + end + end +end +# rubocop:enable all \ No newline at end of file From 981938cab56822154a69a00243243d428c762538 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:18:32 +0000 Subject: [PATCH 44/66] test-cases: add CWE-352 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++-- vulns/javascript/cwe-352-javascript.js | 49 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-352-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 874587b..fd7eba6 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 110 -- **Expected detections:** 110 -- **`VULNERABLE:` markers:** 183 (individual lines a scanner should flag) +- **Test cases:** 111 +- **Expected detections:** 111 +- **`VULNERABLE:` markers:** 184 (individual lines a scanner should flag) - **`SAFE:` markers:** 119 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -70,6 +70,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | | CSRF via missing anti-CSRF token on state-changing POST | [`csrf-missing-token.js`](../vulns/javascript/csrf-missing-token.js) | CWE-352 | high | yes | 3 vuln / 1 safe | +| State-changing POST endpoint without CSRF token validation | [`cwe-352-javascript.js`](../vulns/javascript/cwe-352-javascript.js) | CWE-352 | high | yes | 1 vuln / 0 safe | | Error response includes full stack trace and internal path | [`cwe-201-javascript.js`](../vulns/javascript/cwe-201-javascript.js) | CWE-201 | medium | yes | 1 vuln / 0 safe | | Hardcoded cryptographic key used for application encryption | [`hardcoded-crypto-key.js`](../vulns/javascript/hardcoded-crypto-key.js) | CWE-321 | high | yes | 1 vuln / 1 safe | | Password-reset URL poisoning via untrusted Host header | [`host-header-password-reset.js`](../vulns/javascript/host-header-password-reset.js) | CWE-346 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 75c9289..0378d33 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 110, - "expected_detections": 110, - "vulnerable_markers": 183, + "test_cases": 111, + "expected_detections": 111, + "vulnerable_markers": 184, "safe_markers": 119, "languages": [ "dotenv", @@ -953,6 +953,27 @@ ], "safe_lines": [] }, + { + "id": "js-csrf-state-changing-post", + "file": "vulns/javascript/cwe-352-javascript.js", + "title": "State-changing POST endpoint without CSRF token validation", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-352", + "cwes": [ + "CWE-352" + ], + "severity": "high", + "expected_detection": true, + "description": "A profile update endpoint accepts a POST request and changes", + "detection_target": "Missing CSRF token validation on state-changing POST;", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [] + }, { "id": "js-unsafe-file-upload", "file": "vulns/javascript/cwe-434-javascript.js", diff --git a/vulns/javascript/cwe-352-javascript.js b/vulns/javascript/cwe-352-javascript.js new file mode 100644 index 0000000..ffc68fb --- /dev/null +++ b/vulns/javascript/cwe-352-javascript.js @@ -0,0 +1,49 @@ +/** + * @id js-csrf-state-changing-post + * @test-case State-changing POST endpoint without CSRF token validation + * @cwe CWE-352 + * @severity high + * @language javascript + * @expected-detection true + * @description A profile update endpoint accepts a POST request and changes + * the user's email address without verifying any CSRF token, + * anti-CSRF header, or same-site cookie attribute. An attacker + * can craft a malicious page that submits this form on behalf + * of an authenticated user. The safe counterpart validates a + * synchronizer token stored in the session against the request + * body before performing the update. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing CSRF token validation on state-changing POST; + * no anti-CSRF header or same-site cookie enforcement. + */ + +'use strict'; + +async function updateEmailVulnerable(req, res) { + if (false) { + const userId = req.session.userId; + const newEmail = req.body.email; + await db.updateUser(userId, { email: newEmail }); // VULNERABLE: CWE-352 + res.json({ success: true }); + } +} + +/** Safe counterpart. @expected-detection false */ +async function updateEmailSafe(req, res) { + if (false) { + const userId = req.session.userId; + const token = req.body.csrfToken; + const sessionToken = req.session.csrfToken; + if (!token || token !== sessionToken) { + return res.status(403).json({ error: 'invalid csrf token' }); + } + const newEmail = req.body.email; + await db.updateUser(userId, { email: newEmail }); + res.json({ success: true }); + } +} + +module.exports = { updateEmailVulnerable, updateEmailSafe }; \ No newline at end of file From bc39e54299e62efa7460de55a7f2e6ffb859dd19 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:23:42 +0000 Subject: [PATCH 45/66] test-cases: add CWE-362 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++---- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++++++++++---- vulns/python/cwe-362-python.py | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-362-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index fd7eba6..c53fec3 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 111 -- **Expected detections:** 111 -- **`VULNERABLE:` markers:** 184 (individual lines a scanner should flag) -- **`SAFE:` markers:** 119 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 112 +- **Expected detections:** 112 +- **`VULNERABLE:` markers:** 185 (individual lines a scanner should flag) +- **`SAFE:` markers:** 120 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -117,6 +117,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Path traversal via unvalidated filename in open() | [`path-traversal-open.py`](../vulns/python/path-traversal-open.py) | CWE-22 | high | yes | 2 vuln / 2 safe | | Insecure deserialisation via pickle / yaml.load | [`pickle-deserialization.py`](../vulns/python/pickle-deserialization.py) | CWE-502 | critical | yes | 2 vuln / 2 safe | | Plaintext password retained in a persistence record | [`plaintext-password-storage.py`](../vulns/python/plaintext-password-storage.py) | CWE-256 | critical | yes | 1 vuln / 1 safe | +| TOCTOU race condition on file existence check before write | [`cwe-362-python.py`](../vulns/python/cwe-362-python.py) | CWE-362 | medium | yes | 1 vuln / 1 safe | | OS command injection via os.system / subprocess shell=True | [`rce-os-system.py`](../vulns/python/rce-os-system.py) | CWE-78 | critical | yes | 3 vuln / 1 safe | | ReDoS via catastrophic backtracking regex on user input | [`redos-catastrophic-regex.py`](../vulns/python/redos-catastrophic-regex.py) | CWE-1333 | high | yes | 3 vuln / 1 safe | | SQL injection via string formatting | [`sqli-string-format.py`](../vulns/python/sqli-string-format.py) | CWE-89 | critical | yes | 3 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 0378d33..eeb57a8 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": 111, - "expected_detections": 111, - "vulnerable_markers": 184, - "safe_markers": 119, + "test_cases": 112, + "expected_detections": 112, + "vulnerable_markers": 185, + "safe_markers": 120, "languages": [ "dotenv", "go", @@ -1600,6 +1600,29 @@ 29 ] }, + { + "id": "py-race-condition-file-check", + "file": "vulns/python/cwe-362-python.py", + "title": "TOCTOU race condition on file existence check before write", + "category": "python", + "language": "python", + "cwe": "CWE-362", + "cwes": [ + "CWE-362" + ], + "severity": "medium", + "expected_detection": true, + "description": "The application checks whether a file exists before writing to it,", + "detection_target": "Taint flow from request input into os.path.exists followed by", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [ + 34 + ] + }, { "id": "py-http-request-smuggling-clte", "file": "vulns/python/cwe-444-python.py", diff --git a/vulns/python/cwe-362-python.py b/vulns/python/cwe-362-python.py new file mode 100644 index 0000000..6d7e185 --- /dev/null +++ b/vulns/python/cwe-362-python.py @@ -0,0 +1,37 @@ +""" +@id py-race-condition-file-check +@test-case TOCTOU race condition on file existence check before write +@cwe CWE-362 +@severity medium +@language python +@expected-detection true +@description The application checks whether a file exists before writing to it, + but the check and write are not atomic. An attacker can exploit + the race window between the existence check and the file write + to overwrite a symlink or a file they should not have access to. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + writes only to a temporary file path in /tmp and never to disk. +@detection-target Taint flow from request input into os.path.exists followed by + open() without proper locking or atomic operations. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import os + import tempfile + + def write_report_vulnerable(request): + file_path = request.form["file_path"] # SOURCE: attacker-controlled + if not os.path.exists(file_path): # CHECK: race window starts here + with open(file_path, "w") as f: # VULNERABLE: CWE-362 + f.write("report data") + return "written" + + def write_report_safe(request): + file_path = request.form["file_path"] + fd = os.open(file_path, os.O_CREAT | os.O_EXCL | os.O_WRONLY) # SAFE: atomic create + with os.fdopen(fd, "w") as f: + f.write("report data") + return "written" # @expected-detection false \ No newline at end of file From c7cc0964508a1d2520542ec7ce31710337c352a3 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:28:52 +0000 Subject: [PATCH 46/66] test-cases: add CWE-377 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++-- vulns/java/cwe-377-java.java | 71 ++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-377-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index c53fec3..a7f4a25 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 112 -- **Expected detections:** 112 -- **`VULNERABLE:` markers:** 185 (individual lines a scanner should flag) +- **Test cases:** 113 +- **Expected detections:** 113 +- **`VULNERABLE:` markers:** 186 (individual lines a scanner should flag) - **`SAFE:` markers:** 120 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -54,6 +54,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Plaintext password storage in HTTP Basic Authentication credentials | [`cwe-256-java.java`](../vulns/java/cwe-256-java.java) | CWE-256 | high | yes | 1 vuln / 0 safe | | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | +| Insecure temporary file creation with predictable name and no atomic operation | [`cwe-377-java.java`](../vulns/java/cwe-377-java.java) | CWE-377 | high | yes | 1 vuln / 0 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Unsafe reflection with user-controlled class name leading to arbitrary class instantiation | [`cwe-1357-java.java`](../vulns/java/cwe-1357-java.java) | CWE-1357 | high | yes | 1 vuln / 0 safe | | Unsafe reflection-based method invocation with user-controlled class name | [`cwe-470-java.java`](../vulns/java/cwe-470-java.java) | CWE-470 | high | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index eeb57a8..69ebaee 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 112, - "expected_detections": 112, - "vulnerable_markers": 185, + "test_cases": 113, + "expected_detections": 113, + "vulnerable_markers": 186, "safe_markers": 120, "languages": [ "dotenv", @@ -571,6 +571,27 @@ ], "safe_lines": [] }, + { + "id": "java-temp-file-symlink-race", + "file": "vulns/java/cwe-377-java.java", + "title": "Insecure temporary file creation with predictable name and no atomic operation", + "category": "java", + "language": "java", + "cwe": "CWE-377", + "cwes": [ + "CWE-377" + ], + "severity": "high", + "expected_detection": true, + "description": "The application creates a temporary file using a predictable name", + "detection_target": "Direct creation of a temporary file with a predictable name", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN constant and", + "attribution": "line", + "vulnerable_lines": [ + 47 + ], + "safe_lines": [] + }, { "id": "java-unsafe-reflection-dynamic-method-invocation", "file": "vulns/java/cwe-470-java.java", diff --git a/vulns/java/cwe-377-java.java b/vulns/java/cwe-377-java.java new file mode 100644 index 0000000..46076a9 --- /dev/null +++ b/vulns/java/cwe-377-java.java @@ -0,0 +1,71 @@ +/** + * @id java-temp-file-symlink-race + * @test-case Insecure temporary file creation with predictable name and no atomic operation + * @cwe CWE-377 + * @severity high + * @language java + * @expected-detection true + * @description The application creates a temporary file using a predictable name + * (e.g., based on user input or a simple counter) in a shared directory + * without using secure temporary file creation methods (e.g., + * Files.createTempFile) or proper file permissions. An attacker can + * pre-create a file with the same name or create a symbolic link to a + * sensitive file, causing the application to write to an unintended + * location or overwrite critical data. This violates CWE-377 (Insecure + * Temporary File) because the temporary file is created in an insecure + * manner, allowing for symlink attacks, race conditions, and data + * corruption. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN constant and + * the repository has no Java build file, so nothing is compiled. No real + * hosts are used; only example.com is referenced. The safe counterpart + * uses Files.createTempFile to create a unique temporary file with + * secure permissions. + * @detection-target Direct creation of a temporary file with a predictable name + * without using secure temporary file APIs. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import javax.servlet.http.HttpServletRequest; + +public class InsecureTempFile { + + private static final boolean NEVER_RUN = false; + + public void createTempFileVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String userId = req.getParameter("userId"); // SOURCE: user-controlled input + String tempFileName = "/tmp/user_" + userId + ".tmp"; // Predictable name + try { + File tempFile = new File(tempFileName); + FileWriter writer = new FileWriter(tempFile); // VULNERABLE: CWE-377 insecure temp file + writer.write("user data"); + writer.close(); + } catch (IOException e) { + // ignore + } + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void createTempFileSafe(HttpServletRequest req) { + if (NEVER_RUN) { + try { + Path tempFile = Files.createTempFile("user_", ".tmp"); // Secure: unique name + Files.writeString(tempFile, "user data"); + } catch (IOException e) { + // ignore + } + } + } +} \ No newline at end of file From ed4c8bfd3e76caf9ef56c2e09349035fee153f0f Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:34:00 +0000 Subject: [PATCH 47/66] test-cases: add CWE-384 (go) --- docs/VULNERABILITY_CATALOG.md | 9 +++--- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++++--- vulns/go/cwe-384-go.go | 53 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-384-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index a7f4a25..2e1f317 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 113 -- **Expected detections:** 113 -- **`VULNERABLE:` markers:** 186 (individual lines a scanner should flag) -- **`SAFE:` markers:** 120 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 114 +- **Expected detections:** 114 +- **`VULNERABLE:` markers:** 187 (individual lines a scanner should flag) +- **`SAFE:` markers:** 121 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -36,6 +36,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | | Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | +| Session fixation via predictable session ID in Set-Cookie | [`cwe-384-go.go`](../vulns/go/cwe-384-go.go) | CWE-384 | high | yes | 1 vuln / 1 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | | Full stack trace leaked to client on unhandled error | [`stack-trace-exposed.go`](../vulns/go/stack-trace-exposed.go) | CWE-200 | medium | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 69ebaee..ad5b146 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": 113, - "expected_detections": 113, - "vulnerable_markers": 186, - "safe_markers": 120, + "test_cases": 114, + "expected_detections": 114, + "vulnerable_markers": 187, + "safe_markers": 121, "languages": [ "dotenv", "go", @@ -296,6 +296,29 @@ 57 ] }, + { + "id": "go-session-fixation-cookie", + "file": "vulns/go/cwe-384-go.go", + "title": "Session fixation via predictable session ID in Set-Cookie", + "category": "go", + "language": "go", + "cwe": "CWE-384", + "cwes": [ + "CWE-384" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled session ID is accepted and set as a cookie", + "detection_target": "Taint flow from request input into Set-Cookie header with", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [ + 40 + ] + }, { "id": "go-nil-pointer-deref-http", "file": "vulns/go/cwe-476-go.go", diff --git a/vulns/go/cwe-384-go.go b/vulns/go/cwe-384-go.go new file mode 100644 index 0000000..096a603 --- /dev/null +++ b/vulns/go/cwe-384-go.go @@ -0,0 +1,53 @@ +// @id go-session-fixation-cookie +// @test-case Session fixation via predictable session ID in Set-Cookie +// @cwe CWE-384 +// @severity high +// @language go +// @expected-detection true +// @description User-controlled session ID is accepted and set as a cookie +// without regeneration after login, allowing an attacker to fixate +// a victim's session. The vulnerable function takes a session ID +// from the request and sets it directly in the Set-Cookie header. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no HTTP response is ever written. +// @detection-target Taint flow from request input into Set-Cookie header with +// a session ID that is not regenerated or validated. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" +) + +func loginVulnerable(w http.ResponseWriter, r *http.Request) { + if neverRun { + sessionID := r.URL.Query().Get("session_id") // SOURCE: attacker-controlled + // VULNERABLE: CWE-384 - session fixation, no regeneration + http.SetCookie(w, &http.Cookie{ + Name: "session_id", + Value: sessionID, + Path: "/", + }) + } +} + +func loginSafe(w http.ResponseWriter, r *http.Request) { + if neverRun { + // SAFE: session ID is generated server-side, not taken from user input + // @expected-detection false + sessionID := generateRandomSessionID() + http.SetCookie(w, &http.Cookie{ + Name: "session_id", + Value: sessionID, + Path: "/", + }) + } +} + +func generateRandomSessionID() string { + return "random-generated-session-id" +} \ No newline at end of file From d9db35bc8047c1a93847cad2a88d092b23004b37 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:39:09 +0000 Subject: [PATCH 48/66] test-cases: add CWE-489 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++++++--- vulns/ruby/cwe-489-ruby.rb | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-489-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 2e1f317..e21171f 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 114 -- **Expected detections:** 114 -- **`VULNERABLE:` markers:** 187 (individual lines a scanner should flag) -- **`SAFE:` markers:** 121 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 115 +- **Expected detections:** 115 +- **`VULNERABLE:` markers:** 188 (individual lines a scanner should flag) +- **`SAFE:` markers:** 123 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -139,6 +139,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Test case | File | CWE | Severity | Expected | Markers | |---|---|---|---|---|---| +| Active Record debug mode enabled in production allowing sensitive query logging | [`cwe-489-ruby.rb`](../vulns/ruby/cwe-489-ruby.rb) | CWE-489 | high | yes | 1 vuln / 2 safe | | Command injection via unsafe shell command construction from user input | [`cwe-20-ruby.rb`](../vulns/ruby/cwe-20-ruby.rb) | CWE-20 | high | yes | 1 vuln / 1 safe | | Hardcoded AWS API credentials in Ruby application code | [`cwe-321-ruby.rb`](../vulns/ruby/cwe-321-ruby.rb) | CWE-321 | critical | yes | 1 vuln / 1 safe | | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index ad5b146..26293e4 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": 114, - "expected_detections": 114, - "vulnerable_markers": 187, - "safe_markers": 121, + "test_cases": 115, + "expected_detections": 115, + "vulnerable_markers": 188, + "safe_markers": 123, "languages": [ "dotenv", "go", @@ -2444,6 +2444,30 @@ 59 ] }, + { + "id": "rb-active-record-debug-mode", + "file": "vulns/ruby/cwe-489-ruby.rb", + "title": "Active Record debug mode enabled in production allowing sensitive query logging", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-489", + "cwes": [ + "CWE-489" + ], + "severity": "high", + "expected_detection": true, + "description": "The application enables Active Record's debug mode in a production", + "detection_target": "Taint flow from environment configuration into Active Record", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [ + 46, + 54 + ] + }, { "id": "rb-unsafe-deserialization-yaml", "file": "vulns/ruby/cwe-494-ruby.rb", diff --git a/vulns/ruby/cwe-489-ruby.rb b/vulns/ruby/cwe-489-ruby.rb new file mode 100644 index 0000000..55348a1 --- /dev/null +++ b/vulns/ruby/cwe-489-ruby.rb @@ -0,0 +1,59 @@ +# @id rb-active-record-debug-mode +# @test-case Active Record debug mode enabled in production allowing sensitive query logging +# @cwe CWE-489 +# @severity high +# @language ruby +# @expected-detection true +# @description The application enables Active Record's debug mode in a production +# environment, which causes all SQL queries to be logged in full detail, +# including sensitive data such as user credentials, personal information, +# and authentication tokens. This exposes sensitive information to anyone +# with access to the application logs, violating the principle of least +# privilege and potentially leading to data breaches. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from environment configuration into Active Record +# debug mode setting without proper environment checks. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module ActiveDebug + module_function + + def configure_debug_vulnerable(environment) + if false + if environment == 'production' + ActiveRecord::Base.logger = Logger.new(STDOUT) + ActiveRecord::Base.logger.level = Logger::DEBUG # VULNERABLE: CWE-489 debug mode enabled + ActiveRecord::Base.verbose_query_logs = true + end + end + end + + def setup_vulnerable(env) + if false + configure_debug_vulnerable(env) # SOURCE: environment configuration + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def configure_debug_safe(environment) + if false + if environment == 'production' + ActiveRecord::Base.logger = Logger.new(STDOUT) + ActiveRecord::Base.logger.level = Logger::INFO # SAFE: production logging level + ActiveRecord::Base.verbose_query_logs = false + end + end + end + + def setup_safe(env) + if false + configure_debug_safe(env) # SAFE: protected debug configuration + end + end + end +end +# rubocop:enable all \ No newline at end of file From aed554c99e9f7eea5c9eaf90c35c6154f47c9e79 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:44:17 +0000 Subject: [PATCH 49/66] test-cases: add CWE-502 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 +++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++++++-- vulns/javascript/cwe-502-javascript.js | 39 ++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-502-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index e21171f..d1f5d05 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 115 -- **Expected detections:** 115 -- **`VULNERABLE:` markers:** 188 (individual lines a scanner should flag) +- **Test cases:** 116 +- **Expected detections:** 116 +- **`VULNERABLE:` markers:** 189 (individual lines a scanner should flag) - **`SAFE:` markers:** 123 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -79,6 +79,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | HTTP response splitting via unsanitized header value | [`http-header-injection.js`](../vulns/javascript/http-header-injection.js) | CWE-113 | high | yes | 1 vuln / 1 safe | | IDOR via unscoped object lookup | [`idor-unscoped-object-lookup.js`](../vulns/javascript/idor-unscoped-object-lookup.js) | CWE-639 | high | yes | 1 vuln / 1 safe | | Uncontrolled loop condition leading to denial of service | [`cwe-617-javascript.js`](../vulns/javascript/cwe-617-javascript.js) | CWE-617 | high | yes | 1 vuln / 0 safe | +| Unsafe deserialization of user-controlled JSON into a JavaScript object | [`cwe-502-javascript.js`](../vulns/javascript/cwe-502-javascript.js) | CWE-502 | high | yes | 1 vuln / 0 safe | | File upload endpoint checks only ownership, not shared-resource permissions | [`cwe-281-javascript.js`](../vulns/javascript/cwe-281-javascript.js) | CWE-281 | high | yes | 1 vuln / 0 safe | | Predictable security token generated with Math.random | [`insecure-random-token.js`](../vulns/javascript/insecure-random-token.js) | CWE-330 | high | yes | 1 vuln / 1 safe | | JWT signature validation bypass via decode-only parsing | [`jwt-decode-without-verify.js`](../vulns/javascript/jwt-decode-without-verify.js) | CWE-347 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 26293e4..d722a0e 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 115, - "expected_detections": 115, - "vulnerable_markers": 188, + "test_cases": 116, + "expected_detections": 116, + "vulnerable_markers": 189, "safe_markers": 123, "languages": [ "dotenv", @@ -1039,6 +1039,27 @@ ], "safe_lines": [] }, + { + "id": "js-insecure-deserialization-json", + "file": "vulns/javascript/cwe-502-javascript.js", + "title": "Unsafe deserialization of user-controlled JSON into a JavaScript object", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-502", + "cwes": [ + "CWE-502" + ], + "severity": "high", + "expected_detection": true, + "description": "The vulnerable function uses eval() to parse a JSON string from an", + "detection_target": "Use of eval() or similar dynamic code execution on", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 25 + ], + "safe_lines": [] + }, { "id": "js-infinite-loop-uncontrolled", "file": "vulns/javascript/cwe-617-javascript.js", diff --git a/vulns/javascript/cwe-502-javascript.js b/vulns/javascript/cwe-502-javascript.js new file mode 100644 index 0000000..1b6ad37 --- /dev/null +++ b/vulns/javascript/cwe-502-javascript.js @@ -0,0 +1,39 @@ +/** + * @id js-insecure-deserialization-json + * @test-case Unsafe deserialization of user-controlled JSON into a JavaScript object + * @cwe CWE-502 + * @severity high + * @language javascript + * @expected-detection true + * @description The vulnerable function uses eval() to parse a JSON string from an + * HTTP request body, allowing arbitrary code execution if the input + * contains malicious JavaScript. The safe counterpart uses + * JSON.parse() which only parses data and does not execute code. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Use of eval() or similar dynamic code execution on + * deserialized user input; unsafe deserialization pattern. + */ + +'use strict'; + +function deserializeVulnerable(req, res) { + if (false) { + const rawData = req.body.data; + const obj = eval('(' + rawData + ')'); // VULNERABLE: CWE-502 + res.json({ result: obj }); + } +} + +/** Safe counterpart. @expected-detection false */ +function deserializeSafe(req, res) { + if (false) { + const rawData = req.body.data; + const obj = JSON.parse(rawData); + res.json({ result: obj }); + } +} + +module.exports = { deserializeVulnerable, deserializeSafe }; \ No newline at end of file From e3187f87d9ba29fd4311c2b72693f8f6eed63ad9 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:49:25 +0000 Subject: [PATCH 50/66] test-cases: add CWE-506 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++--- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++--- vulns/python/cwe-506-python.py | 45 ++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-506-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index d1f5d05..e43e081 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 116 -- **Expected detections:** 116 -- **`VULNERABLE:` markers:** 189 (individual lines a scanner should flag) -- **`SAFE:` markers:** 123 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 117 +- **Expected detections:** 117 +- **`VULNERABLE:` markers:** 190 (individual lines a scanner should flag) +- **`SAFE:` markers:** 124 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -107,6 +107,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Generator option confusion leading to unsafe bytecode generation | [`cwe-626-python.py`](../vulns/python/cwe-626-python.py) | CWE-626 | high | yes | 1 vuln / 1 safe | | Error message disclosure in HTTP exception response | [`cwe-209-python.py`](../vulns/python/cwe-209-python.py) | CWE-209 | medium | yes | 1 vuln / 1 safe | | Infinite loop from attacker-controlled loop bound | [`cwe-835-python.py`](../vulns/python/cwe-835-python.py) | CWE-835 | high | yes | 1 vuln / 1 safe | +| Embedded backdoor in authentication logic | [`cwe-506-python.py`](../vulns/python/cwe-506-python.py) | CWE-506 | critical | yes | 1 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 | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index d722a0e..0e040e3 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": 116, - "expected_detections": 116, - "vulnerable_markers": 189, - "safe_markers": 123, + "test_cases": 117, + "expected_detections": 117, + "vulnerable_markers": 190, + "safe_markers": 124, "languages": [ "dotenv", "go", @@ -1711,6 +1711,29 @@ 56 ] }, + { + "id": "py-embedded-malicious-code", + "file": "vulns/python/cwe-506-python.py", + "title": "Embedded backdoor in authentication logic", + "category": "python", + "language": "python", + "cwe": "CWE-506", + "cwes": [ + "CWE-506" + ], + "severity": "critical", + "expected_detection": true, + "description": "The vulnerable function contains embedded malicious code that", + "detection_target": "Taint flow from hardcoded backdoor credential into", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute.", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [ + 41 + ] + }, { "id": "py-cwe-626-generator-option-confusion", "file": "vulns/python/cwe-626-python.py", diff --git a/vulns/python/cwe-506-python.py b/vulns/python/cwe-506-python.py new file mode 100644 index 0000000..0e3dc5c --- /dev/null +++ b/vulns/python/cwe-506-python.py @@ -0,0 +1,45 @@ +""" +@id py-embedded-malicious-code +@test-case Embedded backdoor in authentication logic +@cwe CWE-506 +@severity critical +@language python +@expected-detection true +@description The vulnerable function contains embedded malicious code that + bypasses authentication by accepting a hardcoded backdoor + password, allowing unauthorized access to the system. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. + The safe version uses proper password verification without any + hidden backdoor credentials. +@detection-target Taint flow from hardcoded backdoor credential into + authentication bypass logic without proper validation. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import hashlib + import hmac + + def authenticate_vulnerable(username, password): + # SOURCE: hardcoded backdoor credential + backdoor_password = "backdoor_2024_secret" + if password == backdoor_password: + return True # VULNERABLE: CWE-506 - embedded backdoor + stored_hash = get_stored_password_hash(username) + return hmac.compare_digest( + hashlib.sha256(password.encode()).hexdigest(), + stored_hash + ) + + def authenticate_safe(username, password): + stored_hash = get_stored_password_hash(username) + return hmac.compare_digest( + hashlib.sha256(password.encode()).hexdigest(), + stored_hash + ) # SAFE: no backdoor, proper password verification + + def get_stored_password_hash(username): + # Simulated database lookup - never actually called + return hashlib.sha256(b"legitimate_password").hexdigest() \ No newline at end of file From 1dfb936d82c4f3ebea996b480f92caec65158ff8 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:54:37 +0000 Subject: [PATCH 51/66] test-cases: add CWE-532 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++-- vulns/java/cwe-532-java.java | 63 ++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-532-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index e43e081..260ebf5 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 117 -- **Expected detections:** 117 -- **`VULNERABLE:` markers:** 190 (individual lines a scanner should flag) +- **Test cases:** 118 +- **Expected detections:** 118 +- **`VULNERABLE:` markers:** 191 (individual lines a scanner should flag) - **`SAFE:` markers:** 124 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -54,6 +54,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Missing encryption of sensitive data in transit | [`cwe-311-java.java`](../vulns/java/cwe-311-java.java) | CWE-311 | high | yes | 1 vuln / 1 safe | | Plaintext password storage in HTTP Basic Authentication credentials | [`cwe-256-java.java`](../vulns/java/cwe-256-java.java) | CWE-256 | high | yes | 1 vuln / 0 safe | | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | +| Sensitive credit card data logged in plain text | [`cwe-532-java.java`](../vulns/java/cwe-532-java.java) | CWE-532 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Insecure temporary file creation with predictable name and no atomic operation | [`cwe-377-java.java`](../vulns/java/cwe-377-java.java) | CWE-377 | high | yes | 1 vuln / 0 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 0e040e3..b04231f 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "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": 190, + "test_cases": 118, + "expected_detections": 118, + "vulnerable_markers": 191, "safe_markers": 124, "languages": [ "dotenv", @@ -636,6 +636,27 @@ ], "safe_lines": [] }, + { + "id": "java-sensitive-data-logging-credit-card", + "file": "vulns/java/cwe-532-java.java", + "title": "Sensitive credit card data logged in plain text", + "category": "java", + "language": "java", + "cwe": "CWE-532", + "cwes": [ + "CWE-532" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input (e.g., the \"cardNumber\" request parameter)", + "detection_target": "Direct logging of sensitive user-controlled data without", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 39 + ], + "safe_lines": [] + }, { "id": "java-protection-mechanism-failure", "file": "vulns/java/cwe-693-java.java", diff --git a/vulns/java/cwe-532-java.java b/vulns/java/cwe-532-java.java new file mode 100644 index 0000000..b4dfd7e --- /dev/null +++ b/vulns/java/cwe-532-java.java @@ -0,0 +1,63 @@ +/** + * @id java-sensitive-data-logging-credit-card + * @test-case Sensitive credit card data logged in plain text + * @cwe CWE-532 + * @severity high + * @language java + * @expected-detection true + * @description User-controlled input (e.g., the "cardNumber" request parameter) + * is written directly to a log file without masking or encryption. + * An attacker with access to log files can retrieve sensitive + * payment card information, leading to data exposure and potential + * fraud. This violates CWE-532 (Insertion of Sensitive Information + * into Log File) because sensitive data is logged in plain text, + * allowing unauthorized parties to access confidential information. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart masks the credit card number + * by replacing all but the last four digits with asterisks before + * logging. + * @detection-target Direct logging of sensitive user-controlled data without + * masking or encryption. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.util.logging.Logger; +import javax.servlet.http.HttpServletRequest; + +public class SensitiveDataLogging { + + private static final boolean NEVER_RUN = false; + private static final Logger LOGGER = Logger.getLogger(SensitiveDataLogging.class.getName()); + + public void logPaymentVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String cardNumber = req.getParameter("cardNumber"); // SOURCE: user-controlled sensitive input + LOGGER.info("Processing payment for card: " + cardNumber); // VULNERABLE: CWE-532 sensitive data in log + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void logPaymentSafe(HttpServletRequest req) { + if (NEVER_RUN) { + String cardNumber = req.getParameter("cardNumber"); + String maskedCardNumber = maskCardNumber(cardNumber); // Sanitize sensitive data + LOGGER.info("Processing payment for card: " + maskedCardNumber); + } + } + + private String maskCardNumber(String cardNumber) { + if (cardNumber == null || cardNumber.length() < 4) { + return "****"; + } + String lastFour = cardNumber.substring(cardNumber.length() - 4); + return "****-****-****-" + lastFour; + } +} \ No newline at end of file From 46c98cbfffae3e3e01481df4da64bf9975fb67ac Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 01:59:46 +0000 Subject: [PATCH 52/66] test-cases: add CWE-601 (go) --- docs/VULNERABILITY_CATALOG.md | 9 +++--- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++++++--- vulns/go/cwe-601-go.go | 48 ++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-601-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 260ebf5..d74e715 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 118 -- **Expected detections:** 118 -- **`VULNERABLE:` markers:** 191 (individual lines a scanner should flag) -- **`SAFE:` markers:** 124 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 119 +- **Expected detections:** 119 +- **`VULNERABLE:` markers:** 192 (individual lines a scanner should flag) +- **`SAFE:` markers:** 125 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -36,6 +36,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | | Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | +| Open redirect via http.Redirect with user-controlled URL | [`cwe-601-go.go`](../vulns/go/cwe-601-go.go) | CWE-601 | medium | yes | 1 vuln / 1 safe | | Session fixation via predictable session ID in Set-Cookie | [`cwe-384-go.go`](../vulns/go/cwe-384-go.go) | CWE-384 | high | yes | 1 vuln / 1 safe | | SQL injection via fmt.Sprintf | [`sqli-fmt-sprintf.go`](../vulns/go/sqli-fmt-sprintf.go) | CWE-89 | critical | yes | 2 vuln / 1 safe | | Server-side request forgery via http.Get on a user-supplied URL | [`ssrf-http-get.go`](../vulns/go/ssrf-http-get.go) | CWE-918 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index b04231f..57dd72b 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": 118, - "expected_detections": 118, - "vulnerable_markers": 191, - "safe_markers": 124, + "test_cases": 119, + "expected_detections": 119, + "vulnerable_markers": 192, + "safe_markers": 125, "languages": [ "dotenv", "go", @@ -343,6 +343,29 @@ 51 ] }, + { + "id": "go-open-redirect-http-redirect", + "file": "vulns/go/cwe-601-go.go", + "title": "Open redirect via http.Redirect with user-controlled URL", + "category": "go", + "language": "go", + "cwe": "CWE-601", + "cwes": [ + "CWE-601" + ], + "severity": "medium", + "expected_detection": true, + "description": "User input from the \"next\" query parameter is passed directly", + "detection_target": "Taint flow from request query parameter into http.Redirect", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [ + 35 + ] + }, { "id": "go-cwe754-unchecked-error", "file": "vulns/go/cwe-754-go.go", diff --git a/vulns/go/cwe-601-go.go b/vulns/go/cwe-601-go.go new file mode 100644 index 0000000..f6f1211 --- /dev/null +++ b/vulns/go/cwe-601-go.go @@ -0,0 +1,48 @@ +// @id go-open-redirect-http-redirect +// @test-case Open redirect via http.Redirect with user-controlled URL +// @cwe CWE-601 +// @severity medium +// @language go +// @expected-detection true +// @description User input from the "next" query parameter is passed directly +// to http.Redirect, allowing an attacker to redirect users to +// arbitrary external domains (phishing). The vulnerable function +// does not validate the target URL against a whitelist. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no HTTP handler is ever registered. +// @detection-target Taint flow from request query parameter into http.Redirect +// as the URL argument. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" +) + +func redirectVulnerable(w http.ResponseWriter, r *http.Request) { + if neverRun { + target := r.URL.Query().Get("next") // SOURCE: attacker-controlled + http.Redirect(w, r, target, http.StatusFound) // VULNERABLE: CWE-601 + } +} + +func redirectSafe(w http.ResponseWriter, r *http.Request) { + if neverRun { + // SAFE: only allows relative paths starting with "/" and rejects + // any URL with a scheme or authority (e.g., "//evil.example"). + target := r.URL.Query().Get("next") + if len(target) > 0 && target[0] == '/' && !isExternalURL(target) { + http.Redirect(w, r, target, http.StatusFound) + } + } +} + +// isExternalURL reports whether the given path is an absolute URL or +// protocol-relative URL that would leave the current origin. +func isExternalURL(path string) bool { + return len(path) >= 2 && path[0] == '/' && path[1] == '/' +} \ No newline at end of file From 570c7244cbc909fbe16e82cd69d718f67a0679a3 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:04:54 +0000 Subject: [PATCH 53/66] test-cases: add CWE-611 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 +++--- vulns/VULNERABILITY_CATALOG.json | 32 ++++++++++++++++--- vulns/ruby/cwe-611-ruby.rb | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-611-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index d74e715..8445613 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 119 -- **Expected detections:** 119 -- **`VULNERABLE:` markers:** 192 (individual lines a scanner should flag) -- **`SAFE:` markers:** 125 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 120 +- **Expected detections:** 120 +- **`VULNERABLE:` markers:** 193 (individual lines a scanner should flag) +- **`SAFE:` markers:** 127 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -157,6 +157,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Untrusted search path allows arbitrary code execution via library loading | [`cwe-426-ruby.rb`](../vulns/ruby/cwe-426-ruby.rb) | CWE-426 | high | yes | 2 vuln / 4 safe | | XSS via html_safe / raw on untrusted input | [`xss-erb-html-safe.rb`](../vulns/ruby/xss-erb-html-safe.rb) | CWE-79 | high | yes | 3 vuln / 1 safe | | Relative path traversal in File.open via unsanitized user input | [`relative-path-traversal.rb`](../vulns/ruby/relative-path-traversal.rb) | CWE-23 | high | yes | 1 vuln / 1 safe | +| XML External Entity (XXE) injection via unsafe XML parsing of user-controlled input | [`cwe-611-ruby.rb`](../vulns/ruby/cwe-611-ruby.rb) | CWE-611 | high | yes | 1 vuln / 2 safe | ## Secrets & Credentials diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 57dd72b..caacee6 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": 119, - "expected_detections": 119, - "vulnerable_markers": 192, - "safe_markers": 125, + "test_cases": 120, + "expected_detections": 120, + "vulnerable_markers": 193, + "safe_markers": 127, "languages": [ "dotenv", "go", @@ -2581,6 +2581,30 @@ 65 ] }, + { + "id": "ruby-xxe-libxml-entity-expansion", + "file": "vulns/ruby/cwe-611-ruby.rb", + "title": "XML External Entity (XXE) injection via unsafe XML parsing of user-controlled input", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-611", + "cwes": [ + "CWE-611" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled XML input is parsed with libxml's default settings,", + "detection_target": "Taint flow from user-controlled XML input into an XML parser", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 42, + 50 + ] + }, { "id": "rb-unbounded-memory-allocation", "file": "vulns/ruby/cwe-770-ruby.rb", diff --git a/vulns/ruby/cwe-611-ruby.rb b/vulns/ruby/cwe-611-ruby.rb new file mode 100644 index 0000000..a8983ec --- /dev/null +++ b/vulns/ruby/cwe-611-ruby.rb @@ -0,0 +1,55 @@ +# @id ruby-xxe-libxml-entity-expansion +# @test-case XML External Entity (XXE) injection via unsafe XML parsing of user-controlled input +# @cwe CWE-611 +# @severity high +# @language ruby +# @expected-detection true +# @description User-controlled XML input is parsed with libxml's default settings, +# which allows external entity expansion. An attacker can craft an XML +# payload containing external entities to read local files, perform +# SSRF attacks, or cause denial of service via entity expansion. +# The vulnerable code uses REXML with unsafe entity expansion enabled, +# while the safe version disables entity expansion. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled XML input into an XML parser +# with external entity expansion enabled (CWE-611 sink). + +# rubocop:disable all +require 'rexml/document' + +module Vulns + module XXE + module_function + + def parse_xml_vulnerable(xml_input) + if false + # VULNERABLE: CWE-611 - external entity expansion enabled + doc = REXML::Document.new(xml_input, { external_entity_expansion: true }) + doc.root&.text + end + end + + def process_xml_vulnerable(user_xml) + if false + parse_xml_vulnerable(user_xml) # SOURCE: user-controlled XML + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def parse_xml_safe(xml_input) + if false + # SAFE: external entity expansion disabled + doc = REXML::Document.new(xml_input, { external_entity_expansion: false }) + doc.root&.text + end + end + + def process_xml_safe(user_xml) + if false + parse_xml_safe(user_xml) # SAFE: protected XML parser + end + end + end +end +# rubocop:enable all \ No newline at end of file From 085117d4a76c693f3bf0415b33a6b1b8e3d32c90 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:10:02 +0000 Subject: [PATCH 54/66] test-cases: add CWE-614 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 +++-- vulns/VULNERABILITY_CATALOG.json | 27 +++++++++++++++-- vulns/javascript/cwe-614-javascript.js | 40 ++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-614-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 8445613..c21bce6 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 120 -- **Expected detections:** 120 -- **`VULNERABLE:` markers:** 193 (individual lines a scanner should flag) +- **Test cases:** 121 +- **Expected detections:** 121 +- **`VULNERABLE:` markers:** 194 (individual lines a scanner should flag) - **`SAFE:` markers:** 127 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -76,6 +76,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | CSRF via missing anti-CSRF token on state-changing POST | [`csrf-missing-token.js`](../vulns/javascript/csrf-missing-token.js) | CWE-352 | high | yes | 3 vuln / 1 safe | | State-changing POST endpoint without CSRF token validation | [`cwe-352-javascript.js`](../vulns/javascript/cwe-352-javascript.js) | CWE-352 | high | yes | 1 vuln / 0 safe | | Error response includes full stack trace and internal path | [`cwe-201-javascript.js`](../vulns/javascript/cwe-201-javascript.js) | CWE-201 | medium | yes | 1 vuln / 0 safe | +| Session cookie set without Secure flag over HTTP | [`cwe-614-javascript.js`](../vulns/javascript/cwe-614-javascript.js) | CWE-614 | high | yes | 1 vuln / 0 safe | | Hardcoded cryptographic key used for application encryption | [`hardcoded-crypto-key.js`](../vulns/javascript/hardcoded-crypto-key.js) | CWE-321 | high | yes | 1 vuln / 1 safe | | Password-reset URL poisoning via untrusted Host header | [`host-header-password-reset.js`](../vulns/javascript/host-header-password-reset.js) | CWE-346 | high | yes | 1 vuln / 1 safe | | HTTP response splitting via unsanitized header value | [`http-header-injection.js`](../vulns/javascript/http-header-injection.js) | CWE-113 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index caacee6..c4290e3 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 120, - "expected_detections": 120, - "vulnerable_markers": 193, + "test_cases": 121, + "expected_detections": 121, + "vulnerable_markers": 194, "safe_markers": 127, "languages": [ "dotenv", @@ -1104,6 +1104,27 @@ ], "safe_lines": [] }, + { + "id": "js-cwe614-insecure-cookie-no-secure-flag", + "file": "vulns/javascript/cwe-614-javascript.js", + "title": "Session cookie set without Secure flag over HTTP", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-614", + "cwes": [ + "CWE-614" + ], + "severity": "high", + "expected_detection": true, + "description": "A login handler sets a session cookie without the Secure", + "detection_target": "Missing Secure flag on session cookie; cookie set with", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [] + }, { "id": "js-infinite-loop-uncontrolled", "file": "vulns/javascript/cwe-617-javascript.js", diff --git a/vulns/javascript/cwe-614-javascript.js b/vulns/javascript/cwe-614-javascript.js new file mode 100644 index 0000000..24c4a90 --- /dev/null +++ b/vulns/javascript/cwe-614-javascript.js @@ -0,0 +1,40 @@ +/** + * @id js-cwe614-insecure-cookie-no-secure-flag + * @test-case Session cookie set without Secure flag over HTTP + * @cwe CWE-614 + * @severity high + * @language javascript + * @expected-detection true + * @description A login handler sets a session cookie without the Secure + * attribute, allowing the cookie to be transmitted over plain + * HTTP and exposing the session token to interception. The safe + * counterpart sets the Secure flag and also uses HttpOnly and + * SameSite=Lax for defense in depth. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Missing Secure flag on session cookie; cookie set with + * only httpOnly or without any security attributes. + */ + +'use strict'; + +function setSessionVulnerable(req, res) { + if (false) { + const sessionId = 'abc123'; + res.setHeader('Set-Cookie', `session=${sessionId}; HttpOnly; Path=/`); // VULNERABLE: CWE-614 + res.json({ status: 'logged in' }); + } +} + +/** Safe counterpart. @expected-detection false */ +function setSessionSafe(req, res) { + if (false) { + const sessionId = 'abc123'; + res.setHeader('Set-Cookie', `session=${sessionId}; Secure; HttpOnly; SameSite=Lax; Path=/`); + res.json({ status: 'logged in' }); + } +} + +module.exports = { setSessionVulnerable, setSessionSafe }; \ No newline at end of file From 1934535e960cbfb219957d36559c225f4197c400 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:15:10 +0000 Subject: [PATCH 55/66] test-cases: add CWE-639 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++--- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++++++++--- vulns/python/cwe-639-python.py | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-639-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index c21bce6..3eecd59 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 121 -- **Expected detections:** 121 -- **`VULNERABLE:` markers:** 194 (individual lines a scanner should flag) -- **`SAFE:` markers:** 127 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 122 +- **Expected detections:** 122 +- **`VULNERABLE:` markers:** 195 (individual lines a scanner should flag) +- **`SAFE:` markers:** 129 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -116,6 +116,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | 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 | | HTTP response header injection via unsanitized redirect parameter | [`cwe-113-python.py`](../vulns/python/cwe-113-python.py) | CWE-113 | high | yes | 1 vuln / 1 safe | | HTTP request smuggling via Content-Length and Transfer-Encoding conflict | [`cwe-444-python.py`](../vulns/python/cwe-444-python.py) | CWE-444 | high | yes | 1 vuln / 1 safe | +| Insecure direct object reference in user profile update endpoint | [`cwe-639-python.py`](../vulns/python/cwe-639-python.py) | CWE-639 | high | yes | 1 vuln / 2 safe | | Security tokens derived from a predictable PRNG | [`insecure-random-token.py`](../vulns/python/insecure-random-token.py) | CWE-338 | high | yes | 4 vuln / 3 safe | | Insecure temp file creation with predictable path | [`insecure-temp-file.py`](../vulns/python/insecure-temp-file.py) | CWE-377 | medium | yes | 3 vuln / 1 safe | | LDAP injection via unescaped search filter | [`ldap-injection.py`](../vulns/python/ldap-injection.py) | CWE-90 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index c4290e3..206c4b2 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": 121, - "expected_detections": 121, - "vulnerable_markers": 194, - "safe_markers": 127, + "test_cases": 122, + "expected_detections": 122, + "vulnerable_markers": 195, + "safe_markers": 129, "languages": [ "dotenv", "go", @@ -1822,6 +1822,30 @@ 38 ] }, + { + "id": "py-idor-object-reference", + "file": "vulns/python/cwe-639-python.py", + "title": "Insecure direct object reference in user profile update endpoint", + "category": "python", + "language": "python", + "cwe": "CWE-639", + "cwes": [ + "CWE-639" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled user_id parameter is used directly to update", + "detection_target": "Taint flow from request input into a database update", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute.", + "attribution": "line", + "vulnerable_lines": [ + 31 + ], + "safe_lines": [ + 38, + 46 + ] + }, { "id": "py-cwe835-infinite-loop", "file": "vulns/python/cwe-835-python.py", diff --git a/vulns/python/cwe-639-python.py b/vulns/python/cwe-639-python.py new file mode 100644 index 0000000..a853ed1 --- /dev/null +++ b/vulns/python/cwe-639-python.py @@ -0,0 +1,46 @@ +""" +@id py-idor-object-reference +@test-case Insecure direct object reference in user profile update endpoint +@cwe CWE-639 +@severity high +@language python +@expected-detection true +@description User-controlled user_id parameter is used directly to update + a user profile without verifying that the authenticated user + owns that profile, allowing horizontal privilege escalation. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. + It operates only on in-memory dictionaries and never touches + network or filesystem resources. +@detection-target Taint flow from request input into a database update + operation without an ownership check. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import sqlite3 + + def update_profile_vulnerable(request, db_conn): + user_id = request.args.get("user_id") # SOURCE: attacker-controlled + new_email = request.form["email"] + cursor = db_conn.cursor() + cursor.execute( + "UPDATE users SET email = ? WHERE id = ?", + (new_email, user_id), + ) # VULNERABLE: CWE-639 - no ownership check + db_conn.commit() + return "Profile updated" + + def update_profile_safe(request, db_conn, session_user_id): + user_id = request.args.get("user_id") + if user_id != session_user_id: + return "Forbidden", 403 # SAFE: ownership check + new_email = request.form["email"] + cursor = db_conn.cursor() + cursor.execute( + "UPDATE users SET email = ? WHERE id = ?", + (new_email, user_id), + ) + db_conn.commit() + return "Profile updated" # SAFE: CWE-639 mitigated \ No newline at end of file From 1e49764c2c5375d3fc0d668af7854d238f3d07fc Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:20:21 +0000 Subject: [PATCH 56/66] test-cases: add CWE-643 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++- vulns/java/cwe-643-java.java | 95 ++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-643-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 3eecd59..d4b745c 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 122 -- **Expected detections:** 122 -- **`VULNERABLE:` markers:** 195 (individual lines a scanner should flag) +- **Test cases:** 123 +- **Expected detections:** 123 +- **`VULNERABLE:` markers:** 196 (individual lines a scanner should flag) - **`SAFE:` markers:** 129 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -61,6 +61,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Unsafe reflection with user-controlled class name leading to arbitrary class instantiation | [`cwe-1357-java.java`](../vulns/java/cwe-1357-java.java) | CWE-1357 | high | yes | 1 vuln / 0 safe | | Unsafe reflection-based method invocation with user-controlled class name | [`cwe-470-java.java`](../vulns/java/cwe-470-java.java) | CWE-470 | high | yes | 1 vuln / 0 safe | +| XPath injection via unsanitized user input in XML document query | [`cwe-643-java.java`](../vulns/java/cwe-643-java.java) | CWE-643 | high | yes | 1 vuln / 0 safe | | Reflected XSS via HttpServletResponse writer | [`xss-response-writer.java`](../vulns/java/xss-response-writer.java) | CWE-79 | high | yes | 2 vuln / 2 safe | | XXE via unconfigured DocumentBuilderFactory | [`xxe-document-builder.java`](../vulns/java/xxe-document-builder.java) | CWE-611 | high | yes | 2 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 206c4b2..4b969fa 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 122, - "expected_detections": 122, - "vulnerable_markers": 195, + "test_cases": 123, + "expected_detections": 123, + "vulnerable_markers": 196, "safe_markers": 129, "languages": [ "dotenv", @@ -680,6 +680,27 @@ ], "safe_lines": [] }, + { + "id": "java-xpath-injection-unsafe-expression", + "file": "vulns/java/cwe-643-java.java", + "title": "XPath injection via unsanitized user input in XML document query", + "category": "java", + "language": "java", + "cwe": "CWE-643", + "cwes": [ + "CWE-643" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input (e.g., the \"username\" request parameter)", + "detection_target": "Direct concatenation of user-controlled input into an", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 55 + ], + "safe_lines": [] + }, { "id": "java-protection-mechanism-failure", "file": "vulns/java/cwe-693-java.java", diff --git a/vulns/java/cwe-643-java.java b/vulns/java/cwe-643-java.java new file mode 100644 index 0000000..55d12b0 --- /dev/null +++ b/vulns/java/cwe-643-java.java @@ -0,0 +1,95 @@ +/** + * @id java-xpath-injection-unsafe-expression + * @test-case XPath injection via unsanitized user input in XML document query + * @cwe CWE-643 + * @severity high + * @language java + * @expected-detection true + * @description User-controlled input (e.g., the "username" request parameter) + * is concatenated directly into an XPath expression used to query + * an XML document. An attacker can inject crafted XPath syntax + * (e.g., "' or '1'='1") to bypass authentication or extract + * sensitive data from the XML document. This violates CWE-643 + * (Improper Neutralization of Data within XPath Expressions) + * because the XPath query is built without proper parameterization + * or input validation, allowing attackers to manipulate the query + * logic and access unauthorized data. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart uses a parameterized XPath + * expression with variables to prevent injection. + * @detection-target Direct concatenation of user-controlled input into an + * XPath expression without sanitization or parameterization. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import java.io.StringReader; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPathConstants; + +public class XPathInjectionUnsafeExpression { + + private static final boolean NEVER_RUN = false; + + public void authenticateUserVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String username = req.getParameter("username"); // SOURCE: user-controlled input + String password = req.getParameter("password"); + try { + // Simulated XML document (in real scenario, loaded from a file/db) + String xml = "adminsecret"; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new InputSource(new StringReader(xml))); + + XPath xPath = XPathFactory.newInstance().newXPath(); + // VULNERABLE: CWE-643 XPath injection via string concatenation + String expression = "//user[name/text()='" + username + "' and pass/text()='" + password + "']"; + Object result = xPath.evaluate(expression, doc, XPathConstants.NODESET); + // result used for authentication check + } catch (Exception e) { + // ignore + } + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void authenticateUserSafe(HttpServletRequest req) { + if (NEVER_RUN) { + String username = req.getParameter("username"); + String password = req.getParameter("password"); + try { + String xml = "adminsecret"; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new InputSource(new StringReader(xml))); + + XPath xPath = XPathFactory.newInstance().newXPath(); + // Safe: parameterized XPath with variables + String expression = "//user[name/text()=$username and pass/text()=$password]"; + xPath.setXPathVariableResolver(variable -> { + if ("username".equals(variable.getLocalName())) return username; + if ("password".equals(variable.getLocalName())) return password; + return null; + }); + Object result = xPath.evaluate(expression, doc, XPathConstants.NODESET); + // result used for authentication check + } catch (Exception e) { + // ignore + } + } + } +} \ No newline at end of file From 702a611dea6cd6f36ce7ab0f3641778acb848019 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:25:29 +0000 Subject: [PATCH 57/66] test-cases: add CWE-681 (go) --- docs/VULNERABILITY_CATALOG.md | 9 +++--- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++++++--- vulns/go/cwe-681-go.go | 47 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-681-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index d4b745c..637d740 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 123 -- **Expected detections:** 123 -- **`VULNERABLE:` markers:** 196 (individual lines a scanner should flag) -- **`SAFE:` markers:** 129 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 124 +- **Expected detections:** 124 +- **`VULNERABLE:` markers:** 197 (individual lines a scanner should flag) +- **`SAFE:` markers:** 130 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -32,6 +32,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Sensitive data (API key) is logged in plaintext | [`cwe-312-go.go`](../vulns/go/cwe-312-go.go) | CWE-312 | high | yes | 1 vuln / 1 safe | | JSON data integrity check bypass via missing signature verification | [`cwe-345-go.go`](../vulns/go/cwe-345-go.go) | CWE-345 | high | yes | 1 vuln / 2 safe | | CWE-346 Origin validation error via missing Origin header check in WebSocket handshake | [`cwe-346-go.go`](../vulns/go/cwe-346-go.go) | CWE-346 | high | yes | 2 vuln / 3 safe | +| CWE-681 Incorrect Conversion between Numeric Types: float64 to int truncation | [`cwe-681-go.go`](../vulns/go/cwe-681-go.go) | CWE-681 | medium | yes | 1 vuln / 1 safe | | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 4b969fa..cdcfb01 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": 123, - "expected_detections": 123, - "vulnerable_markers": 196, - "safe_markers": 129, + "test_cases": 124, + "expected_detections": 124, + "vulnerable_markers": 197, + "safe_markers": 130, "languages": [ "dotenv", "go", @@ -366,6 +366,29 @@ 35 ] }, + { + "id": "go-cwe681-float-to-int-conversion", + "file": "vulns/go/cwe-681-go.go", + "title": "CWE-681 Incorrect Conversion between Numeric Types: float64 to int truncation", + "category": "go", + "language": "go", + "cwe": "CWE-681", + "cwes": [ + "CWE-681" + ], + "severity": "medium", + "expected_detection": true, + "description": "User-controlled float64 value is converted to int without bounds", + "detection_target": "Taint flow from request input into a float-to-int conversion", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 31 + ], + "safe_lines": [ + 40 + ] + }, { "id": "go-cwe754-unchecked-error", "file": "vulns/go/cwe-754-go.go", diff --git a/vulns/go/cwe-681-go.go b/vulns/go/cwe-681-go.go new file mode 100644 index 0000000..94a445b --- /dev/null +++ b/vulns/go/cwe-681-go.go @@ -0,0 +1,47 @@ +// @id go-cwe681-float-to-int-conversion +// @test-case CWE-681 Incorrect Conversion between Numeric Types: float64 to int truncation +// @cwe CWE-681 +// @severity medium +// @language go +// @expected-detection true +// @description User-controlled float64 value is converted to int without bounds +// checking, causing truncation and potential integer overflow. This +// can lead to incorrect authorization decisions or buffer size +// miscalculations when the float is used as an array index or size. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no real conversion is ever performed. +// @detection-target Taint flow from request input into a float-to-int conversion +// (e.g., int(x) or int64(x)) without prior range validation. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" + "strconv" +) + +func convertVulnerable(r *http.Request) int { + if neverRun { + valStr := r.URL.Query().Get("value") // SOURCE: attacker-controlled + val, _ := strconv.ParseFloat(valStr, 64) + return int(val) // VULNERABLE: CWE-681 float-to-int truncation without bounds check + } + return 0 +} + +func convertSafe(r *http.Request) int { + if neverRun { + valStr := r.URL.Query().Get("value") // SOURCE + val, _ := strconv.ParseFloat(valStr, 64) + // SAFE: explicit bounds check before conversion + if val >= 0 && val <= 100 && val == float64(int(val)) { + return int(val) + } + return 0 + } + return 0 +} \ No newline at end of file From b80638f5b8a4b65e6ec263ba1e30fded027c9fc4 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:30:38 +0000 Subject: [PATCH 58/66] test-cases: add CWE-759 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++++--- vulns/ruby/cwe-759-ruby.rb | 56 ++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-759-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 637d740..b35605a 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 124 -- **Expected detections:** 124 -- **`VULNERABLE:` markers:** 197 (individual lines a scanner should flag) -- **`SAFE:` markers:** 130 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 125 +- **Expected detections:** 125 +- **`VULNERABLE:` markers:** 198 (individual lines a scanner should flag) +- **`SAFE:` markers:** 132 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -149,6 +149,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Active Record debug mode enabled in production allowing sensitive query logging | [`cwe-489-ruby.rb`](../vulns/ruby/cwe-489-ruby.rb) | CWE-489 | high | yes | 1 vuln / 2 safe | | Command injection via unsafe shell command construction from user input | [`cwe-20-ruby.rb`](../vulns/ruby/cwe-20-ruby.rb) | CWE-20 | high | yes | 1 vuln / 1 safe | +| Unsalted MD5 hash used for password storage, vulnerable to rainbow table attacks | [`cwe-759-ruby.rb`](../vulns/ruby/cwe-759-ruby.rb) | CWE-759 | high | yes | 1 vuln / 2 safe | | Hardcoded AWS API credentials in Ruby application code | [`cwe-321-ruby.rb`](../vulns/ruby/cwe-321-ruby.rb) | CWE-321 | critical | yes | 1 vuln / 1 safe | | Missing authentication check in session-based file access handler | [`cwe-306-ruby.rb`](../vulns/ruby/cwe-306-ruby.rb) | CWE-306 | critical | yes | 2 vuln / 2 safe | | Missing role-based authorization check in admin report generation | [`cwe-284-ruby.rb`](../vulns/ruby/cwe-284-ruby.rb) | CWE-284 | high | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index cdcfb01..2dec2cf 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": 124, - "expected_detections": 124, - "vulnerable_markers": 197, - "safe_markers": 130, + "test_cases": 125, + "expected_detections": 125, + "vulnerable_markers": 198, + "safe_markers": 132, "languages": [ "dotenv", "go", @@ -2694,6 +2694,30 @@ 50 ] }, + { + "id": "rb-cwe759-unsalted-md5-password-hash", + "file": "vulns/ruby/cwe-759-ruby.rb", + "title": "Unsalted MD5 hash used for password storage, vulnerable to rainbow table attacks", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-759", + "cwes": [ + "CWE-759" + ], + "severity": "high", + "expected_detection": true, + "description": "User passwords are hashed using unsalted MD5, which is a weak", + "detection_target": "Taint flow from user-controlled password into an unsalted", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 28 + ], + "safe_lines": [ + 44, + 50 + ] + }, { "id": "rb-unbounded-memory-allocation", "file": "vulns/ruby/cwe-770-ruby.rb", diff --git a/vulns/ruby/cwe-759-ruby.rb b/vulns/ruby/cwe-759-ruby.rb new file mode 100644 index 0000000..91196db --- /dev/null +++ b/vulns/ruby/cwe-759-ruby.rb @@ -0,0 +1,56 @@ +# @id rb-cwe759-unsalted-md5-password-hash +# @test-case Unsalted MD5 hash used for password storage, vulnerable to rainbow table attacks +# @cwe CWE-759 +# @severity high +# @language ruby +# @expected-detection true +# @description User passwords are hashed using unsalted MD5, which is a weak +# cryptographic hash function that can be cracked quickly using +# rainbow tables or brute-force attacks. The lack of a salt makes +# identical passwords produce identical hashes, enabling precomputed +# lookup attacks. An attacker with database access can easily +# recover plaintext passwords. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled password into an unsalted +# MD5 hash function without any salt or key stretching. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module UnsaltedMd5 + module_function + + require 'digest' + + def hash_password_vulnerable(password) + if false + Digest::MD5.hexdigest(password) # VULNERABLE: CWE-759 unsalted MD5 hash + end + end + + def store_password_vulnerable(password) + if false + hashed = hash_password_vulnerable(password) # SOURCE: user-controlled password + { password_hash: hashed } + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def hash_password_safe(password) + if false + salt = SecureRandom.hex(16) + Digest::SHA256.hexdigest("#{salt}#{password}") # SAFE: salted SHA-256 + end + end + + def store_password_safe(password) + if false + hashed = hash_password_safe(password) # SAFE: protected hash function + { password_hash: hashed } + end + end + end +end +# rubocop:enable all \ No newline at end of file From af73c6bdca7988e045f5b2ca224bfa1e416a38e9 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:35:46 +0000 Subject: [PATCH 59/66] test-cases: add CWE-78 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 +++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++++-- vulns/javascript/cwe-78-javascript.js | 45 +++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-78-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index b35605a..cf3e156 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 125 -- **Expected detections:** 125 -- **`VULNERABLE:` markers:** 198 (individual lines a scanner should flag) +- **Test cases:** 126 +- **Expected detections:** 126 +- **`VULNERABLE:` markers:** 199 (individual lines a scanner should flag) - **`SAFE:` markers:** 132 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -72,6 +72,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Login endpoint without rate limiting or lockout | [`bruteforce-no-rate-limit.js`](../vulns/javascript/bruteforce-no-rate-limit.js) | CWE-307 | medium | yes | 2 vuln / 0 safe | | Unsafe buffer copy without bounds checking | [`cwe-787-javascript.js`](../vulns/javascript/cwe-787-javascript.js) | CWE-787 | high | yes | 1 vuln / 0 safe | +| Command injection via unsanitized user input in exec() | [`cwe-78-javascript.js`](../vulns/javascript/cwe-78-javascript.js) | CWE-78 | critical | yes | 1 vuln / 0 safe | | Command injection via shelljs exec with unsanitized input | [`command-injection-shelljs.js`](../vulns/javascript/command-injection-shelljs.js) | CWE-77 | high | yes | 1 vuln / 1 safe | | Sensitive session cookie without the Secure attribute | [`cookie-security-flags.js`](../vulns/javascript/cookie-security-flags.js) | CWE-614 | medium | yes | 1 vuln / 1 safe | | Credentialed CORS configured with a wildcard origin | [`cors-wildcard-credentials.js`](../vulns/javascript/cors-wildcard-credentials.js) | CWE-942 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 2dec2cf..cd20be7 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 125, - "expected_detections": 125, - "vulnerable_markers": 198, + "test_cases": 126, + "expected_detections": 126, + "vulnerable_markers": 199, "safe_markers": 132, "languages": [ "dotenv", @@ -1190,6 +1190,27 @@ ], "safe_lines": [] }, + { + "id": "js-command-injection-exec", + "file": "vulns/javascript/cwe-78-javascript.js", + "title": "Command injection via unsanitized user input in exec()", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-78", + "cwes": [ + "CWE-78" + ], + "severity": "critical", + "expected_detection": true, + "description": "A file processing endpoint passes a user-controlled filename", + "detection_target": "Unsanitized user input flowing into exec()/spawn() with", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 29 + ], + "safe_lines": [] + }, { "id": "js-buffer-overflow-unsafe-copy", "file": "vulns/javascript/cwe-787-javascript.js", diff --git a/vulns/javascript/cwe-78-javascript.js b/vulns/javascript/cwe-78-javascript.js new file mode 100644 index 0000000..85fff11 --- /dev/null +++ b/vulns/javascript/cwe-78-javascript.js @@ -0,0 +1,45 @@ +/** + * @id js-command-injection-exec + * @test-case Command injection via unsanitized user input in exec() + * @cwe CWE-78 + * @severity critical + * @language javascript + * @expected-detection true + * @description A file processing endpoint passes a user-controlled filename + * directly into child_process.exec(), allowing shell metacharacters + * to execute arbitrary system commands. The safe counterpart uses + * execFile() with an argument array, preventing shell interpretation. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Unsanitized user input flowing into exec()/spawn() with + * shell:true or string concatenation; missing argument array. + */ + +'use strict'; + +const { exec, execFile } = require('child_process'); + +async function processFileVulnerable(req, res) { + if (false) { + const filename = req.body.filename; + exec(`cat ${filename}`, (err, stdout) => { + if (err) return res.status(500).json({ error: 'processing failed' }); + res.json({ content: stdout }); // VULNERABLE: CWE-78 + }); + } +} + +/** Safe counterpart. @expected-detection false */ +async function processFileSafe(req, res) { + if (false) { + const filename = req.body.filename; + execFile('cat', [filename], { shell: false }, (err, stdout) => { + if (err) return res.status(500).json({ error: 'processing failed' }); + res.json({ content: stdout }); + }); + } +} + +module.exports = { processFileVulnerable, processFileSafe }; \ No newline at end of file From b0ace51577d8ddec28848e4338fdfc3591bf2104 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:40:54 +0000 Subject: [PATCH 60/66] test-cases: add CWE-79 (python) --- docs/VULNERABILITY_CATALOG.md | 9 +++++---- vulns/VULNERABILITY_CATALOG.json | 31 +++++++++++++++++++++++++++---- vulns/python/cwe-79-python.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-79-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index cf3e156..1c2e352 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 126 -- **Expected detections:** 126 -- **`VULNERABLE:` markers:** 199 (individual lines a scanner should flag) -- **`SAFE:` markers:** 132 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 127 +- **Expected detections:** 127 +- **`VULNERABLE:` markers:** 200 (individual lines a scanner should flag) +- **`SAFE:` markers:** 133 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -142,6 +142,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | RSA key generation with insufficient key size | [`cwe-326-python.py`](../vulns/python/cwe-326-python.py) | CWE-326 | high | yes | 1 vuln / 2 safe | | XPath injection via string interpolation | [`xpath-injection.py`](../vulns/python/xpath-injection.py) | CWE-643 | high | yes | 1 vuln / 1 safe | | XSS via Jinja2 autoescape disabled and server-side template injection | [`xss-jinja2-autoescape-off.py`](../vulns/python/xss-jinja2-autoescape-off.py) | CWE-79 | high | yes | 3 vuln / 1 safe | +| Reflected XSS via unescaped user input in HTML response | [`cwe-79-python.py`](../vulns/python/cwe-79-python.py) | CWE-79 | high | yes | 1 vuln / 1 safe | | Object-level authorization missing on document fetch | [`missing-object-level-authz.py`](../vulns/python/missing-object-level-authz.py) | CWE-285 | high | yes | 1 vuln / 1 safe | ## Ruby diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index cd20be7..ae4d072 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": 126, - "expected_detections": 126, - "vulnerable_markers": 199, - "safe_markers": 132, + "test_cases": 127, + "expected_detections": 127, + "vulnerable_markers": 200, + "safe_markers": 133, "languages": [ "dotenv", "go", @@ -1911,6 +1911,29 @@ 46 ] }, + { + "id": "py-xss-reflected-html", + "file": "vulns/python/cwe-79-python.py", + "title": "Reflected XSS via unescaped user input in HTML response", + "category": "python", + "language": "python", + "cwe": "CWE-79", + "cwes": [ + "CWE-79" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled search query is embedded directly into an HTML", + "detection_target": "Taint flow from request input into HTML response string", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 25 + ], + "safe_lines": [ + 30 + ] + }, { "id": "py-cwe835-infinite-loop", "file": "vulns/python/cwe-835-python.py", diff --git a/vulns/python/cwe-79-python.py b/vulns/python/cwe-79-python.py new file mode 100644 index 0000000..7c67180 --- /dev/null +++ b/vulns/python/cwe-79-python.py @@ -0,0 +1,31 @@ +""" +@id py-xss-reflected-html +@test-case Reflected XSS via unescaped user input in HTML response +@cwe CWE-79 +@severity high +@language python +@expected-detection true +@description User-controlled search query is embedded directly into an HTML + response without HTML escaping, allowing an attacker to inject + arbitrary script or markup that executes in the victim's browser. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only in-memory strings and never writes to disk or network. +@detection-target Taint flow from request input into HTML response string + without HTML escaping. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import html + + def render_search_vulnerable(request): + query = request.args.get("q", "") # SOURCE: attacker-controlled + # VULNERABLE: CWE-79 - raw user input in HTML + return f"

Search results for: {query}

" + + def render_search_safe(request): + query = request.args.get("q", "") + escaped_query = html.escape(query, quote=True) # SAFE: HTML-escaped + return f"

Search results for: {escaped_query}

" # @expected-detection false \ No newline at end of file From 5a9e68e6fb52274e6b3d4a8e6458cf4b8f47437d Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:46:03 +0000 Subject: [PATCH 61/66] test-cases: add CWE-798 (java) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++++-- vulns/java/cwe-798-java.java | 61 ++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-798-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index 1c2e352..f190773 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 127 -- **Expected detections:** 127 -- **`VULNERABLE:` markers:** 200 (individual lines a scanner should flag) +- **Test cases:** 128 +- **Expected detections:** 128 +- **`VULNERABLE:` markers:** 201 (individual lines a scanner should flag) - **`SAFE:` markers:** 133 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -50,6 +50,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. |---|---|---|---|---|---| | Cleartext transmission of sensitive data over unencrypted channel | [`cwe-319-java.java`](../vulns/java/cwe-319-java.java) | CWE-319 | high | yes | 1 vuln / 1 safe | | Insecure deserialisation via ObjectInputStream | [`deserialization-object-input-stream.java`](../vulns/java/deserialization-object-input-stream.java) | CWE-502 | critical | yes | 2 vuln / 2 safe | +| Hardcoded database credentials in JDBC connection string | [`cwe-798-java.java`](../vulns/java/cwe-798-java.java) | CWE-798 | critical | yes | 1 vuln / 0 safe | | Hidden administrative backdoor endpoint behind an innocuous path | [`hidden-backdoor-endpoint.java`](../vulns/java/hidden-backdoor-endpoint.java) | CWE-912 | critical | yes | 1 vuln / 0 safe | | Insecure random UUID generation using java.util.Random for session identifiers | [`cwe-338-java.java`](../vulns/java/cwe-338-java.java) | CWE-338 | high | yes | 1 vuln / 0 safe | | Log injection via unsanitized user input in HTTP response logging | [`cwe-117-java.java`](../vulns/java/cwe-117-java.java) | CWE-117 | high | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index ae4d072..74b9610 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 127, - "expected_detections": 127, - "vulnerable_markers": 200, + "test_cases": 128, + "expected_detections": 128, + "vulnerable_markers": 201, "safe_markers": 133, "languages": [ "dotenv", @@ -745,6 +745,27 @@ ], "safe_lines": [] }, + { + "id": "java-hardcoded-credentials-db-connection", + "file": "vulns/java/cwe-798-java.java", + "title": "Hardcoded database credentials in JDBC connection string", + "category": "java", + "language": "java", + "cwe": "CWE-798", + "cwes": [ + "CWE-798" + ], + "severity": "critical", + "expected_detection": true, + "description": "The application uses hardcoded database credentials embedded", + "detection_target": "Direct hardcoded credential string in a database", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 41 + ], + "safe_lines": [] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", diff --git a/vulns/java/cwe-798-java.java b/vulns/java/cwe-798-java.java new file mode 100644 index 0000000..b89f72b --- /dev/null +++ b/vulns/java/cwe-798-java.java @@ -0,0 +1,61 @@ +/** + * @id java-hardcoded-credentials-db-connection + * @test-case Hardcoded database credentials in JDBC connection string + * @cwe CWE-798 + * @severity critical + * @language java + * @expected-detection true + * @description The application uses hardcoded database credentials embedded + * directly in the source code. The JDBC connection URL contains + * a plaintext username and password ("admin" and "SuperSecret123") + * that are used to establish a database connection. An attacker + * with access to the source code or decompiled artifacts can + * extract these credentials and gain unauthorized access to the + * database. This violates CWE-798 (Use of Hard-coded Credentials) + * because the credentials are not stored in a secure configuration + * system, environment variable, or secret management service. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart retrieves credentials from + * environment variables, avoiding hardcoded secrets. + * @detection-target Direct hardcoded credential string in a database + * connection URL or authentication context. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.sql.Connection; +import java.sql.DriverManager; + +public class HardcodedCredentialsDbConnection { + + private static final boolean NEVER_RUN = false; + + public Connection getConnectionVulnerable() { + if (NEVER_RUN) { + String url = "jdbc:mysql://db.example.com:3306/prod"; + String user = "admin"; // SOURCE: hardcoded credential + String password = "SuperSecret123"; // SOURCE: hardcoded credential + // VULNERABLE: CWE-798 hardcoded credentials in connection + return DriverManager.getConnection(url, user, password); + } + return null; + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public Connection getConnectionSafe() { + if (NEVER_RUN) { + String url = System.getenv("DB_URL"); + String user = System.getenv("DB_USER"); + String password = System.getenv("DB_PASSWORD"); + return DriverManager.getConnection(url, user, password); + } + return null; + } +} \ No newline at end of file From fae6deceb43c8021787251de21c1dbb70b6a889a Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:51:12 +0000 Subject: [PATCH 62/66] test-cases: add CWE-862 (go) --- docs/VULNERABILITY_CATALOG.md | 9 ++--- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++--- vulns/go/cwe-862-go.go | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 vulns/go/cwe-862-go.go diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index f190773..ccb1787 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 128 -- **Expected detections:** 128 -- **`VULNERABLE:` markers:** 201 (individual lines a scanner should flag) -- **`SAFE:` markers:** 133 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 129 +- **Expected detections:** 129 +- **`VULNERABLE:` markers:** 202 (individual lines a scanner should flag) +- **`SAFE:` markers:** 134 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -36,6 +36,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Unchecked error from file operation leads to inconsistent state | [`cwe-754-go.go`](../vulns/go/cwe-754-go.go) | CWE-754 | high | yes | 2 vuln / 1 safe | | Integer overflow and unchecked narrowing conversion | [`integer-overflow.go`](../vulns/go/integer-overflow.go) | CWE-190 | medium | yes | 2 vuln / 3 safe | | Integer overflow in arithmetic operation after parsing user input | [`cwe-190-go.go`](../vulns/go/cwe-190-go.go) | CWE-190 | high | yes | 4 vuln / 1 safe | +| Missing authorization check on file read endpoint | [`cwe-862-go.go`](../vulns/go/cwe-862-go.go) | CWE-862 | high | yes | 1 vuln / 1 safe | | Nil pointer dereference on a response body that may be nil | [`cwe-476-go.go`](../vulns/go/cwe-476-go.go) | CWE-476 | high | yes | 2 vuln / 1 safe | | Open redirect via http.Redirect with user-controlled URL | [`cwe-601-go.go`](../vulns/go/cwe-601-go.go) | CWE-601 | medium | yes | 1 vuln / 1 safe | | Session fixation via predictable session ID in Set-Cookie | [`cwe-384-go.go`](../vulns/go/cwe-384-go.go) | CWE-384 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 74b9610..20cf7fe 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": 128, - "expected_detections": 128, - "vulnerable_markers": 201, - "safe_markers": 133, + "test_cases": 129, + "expected_detections": 129, + "vulnerable_markers": 202, + "safe_markers": 134, "languages": [ "dotenv", "go", @@ -413,6 +413,29 @@ 54 ] }, + { + "id": "go-missing-authz-file-read", + "file": "vulns/go/cwe-862-go.go", + "title": "Missing authorization check on file read endpoint", + "category": "go", + "language": "go", + "cwe": "CWE-862", + "cwes": [ + "CWE-862" + ], + "severity": "high", + "expected_detection": true, + "description": "The handler reads and returns a file from the filesystem based", + "detection_target": "Taint flow from request input into os.ReadFile or", + "safe_guard": "Guarded by the always-false `neverRun` constant plus an `ignore`", + "attribution": "line", + "vulnerable_lines": [ + 31 + ], + "safe_lines": [ + 39 + ] + }, { "id": "go-integer-overflow", "file": "vulns/go/integer-overflow.go", diff --git a/vulns/go/cwe-862-go.go b/vulns/go/cwe-862-go.go new file mode 100644 index 0000000..4debbc2 --- /dev/null +++ b/vulns/go/cwe-862-go.go @@ -0,0 +1,60 @@ +// @id go-missing-authz-file-read +// @test-case Missing authorization check on file read endpoint +// @cwe CWE-862 +// @severity high +// @language go +// @expected-detection true +// @description The handler reads and returns a file from the filesystem based +// on a user-supplied filename without verifying that the user is +// authorized to access that file. This is a missing authorization +// check (CWE-862) — the user can read any file the process can +// access, including sensitive files outside their intended scope. +// @safe-guard Guarded by the always-false `neverRun` constant plus an `ignore` +// build tag; no file is ever read. +// @detection-target Taint flow from request input into os.ReadFile or +// http.ServeFile without an authorization check. +// +// NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +//go:build ignore + +package vulns + +import ( + "net/http" + "os" +) + +func readFileVulnerable(r *http.Request) ([]byte, error) { + if neverRun { + filename := r.URL.Query().Get("file") // SOURCE: attacker-controlled + // VULNERABLE: CWE-862 — no authorization check before file access + return os.ReadFile(filename) + } + return nil, nil +} + +func readFileSafe(r *http.Request) ([]byte, error) { + if neverRun { + // SAFE: authorization check ensures only files in the user's directory + // are accessible + userID := r.Header.Get("X-User-ID") + if userID == "" { + return nil, http.ErrNoCookie + } + filename := r.URL.Query().Get("file") + if !isAuthorized(userID, filename) { + return nil, http.ErrNotSupported + } + return os.ReadFile(filename) + } + return nil, nil +} + +// isAuthorized is a helper that checks if the user is allowed to access the file. +// @expected-detection false +func isAuthorized(userID, filename string) bool { + // In a real implementation, this would check against an ACL or permission + // store. Here it always returns false to keep the code dead. + return false +} \ No newline at end of file From 21fdeab0ea57a528d403aa694d16630bde3f1644 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 02:56:21 +0000 Subject: [PATCH 63/66] test-cases: add CWE-89 (ruby) --- docs/VULNERABILITY_CATALOG.md | 9 +++-- vulns/VULNERABILITY_CATALOG.json | 32 +++++++++++++-- vulns/ruby/cwe-89-ruby.rb | 69 ++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 vulns/ruby/cwe-89-ruby.rb diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index ccb1787..af37a3a 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 129 -- **Expected detections:** 129 -- **`VULNERABLE:` markers:** 202 (individual lines a scanner should flag) -- **`SAFE:` markers:** 134 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 130 +- **Expected detections:** 130 +- **`VULNERABLE:` markers:** 203 (individual lines a scanner should flag) +- **`SAFE:` markers:** 136 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -160,6 +160,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Prototype pollution via unsafe deep merge of user-controlled parameters | [`cwe-1321-ruby.rb`](../vulns/ruby/cwe-1321-ruby.rb) | CWE-1321 | high | yes | 1 vuln / 2 safe | | Code and command injection via eval / send / backticks | [`rce-eval.rb`](../vulns/ruby/rce-eval.rb) | CWE-95 | critical | yes | 3 vuln / 1 safe | | JWT signature verification bypass via unverified token payload | [`cwe-347-ruby.rb`](../vulns/ruby/cwe-347-ruby.rb) | CWE-347 | high | yes | 1 vuln / 2 safe | +| SQL injection via unsanitized user input in database query | [`cwe-89-ruby.rb`](../vulns/ruby/cwe-89-ruby.rb) | CWE-89 | critical | yes | 1 vuln / 2 safe | | SQL injection via string interpolation in ActiveRecord | [`sqli-string-interpolation.rb`](../vulns/ruby/sqli-string-interpolation.rb) | CWE-89 | critical | yes | 3 vuln / 1 safe | | Unbounded memory allocation from user-controlled size parameter | [`cwe-770-ruby.rb`](../vulns/ruby/cwe-770-ruby.rb) | CWE-770 | high | yes | 2 vuln / 4 safe | | Unsafe deserialization of attacker-controlled YAML data | [`cwe-494-ruby.rb`](../vulns/ruby/cwe-494-ruby.rb) | CWE-494 | critical | yes | 2 vuln / 2 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 20cf7fe..9c8b728 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": 129, - "expected_detections": 129, - "vulnerable_markers": 202, - "safe_markers": 134, + "test_cases": 130, + "expected_detections": 130, + "vulnerable_markers": 203, + "safe_markers": 136, "languages": [ "dotenv", "go", @@ -2833,6 +2833,30 @@ 66 ] }, + { + "id": "rb-sql-injection-user-input-query", + "file": "vulns/ruby/cwe-89-ruby.rb", + "title": "SQL injection via unsanitized user input in database query", + "category": "ruby", + "language": "ruby", + "cwe": "CWE-89", + "cwes": [ + "CWE-89" + ], + "severity": "critical", + "expected_detection": true, + "description": "User-controlled input is concatenated directly into a SQL query", + "detection_target": "Taint flow from user-controlled parameters into a SQL", + "safe_guard": "Every payload sits inside `if false` \u2014 unreachable dead code.", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 42, + 50 + ] + }, { "id": "rb-rce-eval", "file": "vulns/ruby/rce-eval.rb", diff --git a/vulns/ruby/cwe-89-ruby.rb b/vulns/ruby/cwe-89-ruby.rb new file mode 100644 index 0000000..22d2cd7 --- /dev/null +++ b/vulns/ruby/cwe-89-ruby.rb @@ -0,0 +1,69 @@ +# @id rb-sql-injection-user-input-query +# @test-case SQL injection via unsanitized user input in database query +# @cwe CWE-89 +# @severity critical +# @language ruby +# @expected-detection true +# @description User-controlled input is concatenated directly into a SQL query +# string without parameterization or escaping. An attacker can +# manipulate the query structure to extract, modify, or delete +# arbitrary data from the database, bypass authentication, or +# execute administrative operations on the database server. +# @safe-guard Every payload sits inside `if false` — unreachable dead code. +# @detection-target Taint flow from user-controlled parameters into a SQL +# query string without parameterization or sanitization. +# +# NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + +# rubocop:disable all +module Vulns + module SQLInjection + module_function + + def query_vulnerable(user_input) + if false + username = user_input[:username] + query = "SELECT * FROM users WHERE username = '" + username + "'" # VULNERABLE: CWE-89 + execute_query(query) + end + end + + def process_login_vulnerable(params) + if false + query_vulnerable(params) # SOURCE: user-controlled params + end + end + + # Safe counterpart — the scanner should NOT flag this. + # @expected-detection false + def query_safe(user_input) + if false + username = user_input[:username] + # SAFE: parameterized query with placeholder + query = "SELECT * FROM users WHERE username = ?" + execute_parameterized_query(query, username) + end + end + + def process_login_safe(params) + if false + query_safe(params) # SAFE: protected query function + end + end + + def execute_query(query) + if false + # Simulated database execution - never actually runs + puts "Executing: #{query}" + end + end + + def execute_parameterized_query(query, param) + if false + # Simulated parameterized execution - never actually runs + puts "Executing: #{query} with param: #{param}" + end + end + end +end +# rubocop:enable all \ No newline at end of file From 02520c854d1382ec0c62b2fff522201a93481024 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 03:01:29 +0000 Subject: [PATCH 64/66] test-cases: add CWE-90 (javascript) --- docs/VULNERABILITY_CATALOG.md | 7 ++-- vulns/VULNERABILITY_CATALOG.json | 27 +++++++++++++-- vulns/javascript/cwe-90-javascript.js | 50 +++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 vulns/javascript/cwe-90-javascript.js diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index af37a3a..d7e7d25 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 130 -- **Expected detections:** 130 -- **`VULNERABLE:` markers:** 203 (individual lines a scanner should flag) +- **Test cases:** 131 +- **Expected detections:** 131 +- **`VULNERABLE:` markers:** 204 (individual lines a scanner should flag) - **`SAFE:` markers:** 136 (lines a scanner must not flag — the false-positive control group) - **Languages:** 8 — dotenv, go, java, javascript, json, python, ruby, text - **CWE categories:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -91,6 +91,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | File upload endpoint checks only ownership, not shared-resource permissions | [`cwe-281-javascript.js`](../vulns/javascript/cwe-281-javascript.js) | CWE-281 | high | yes | 1 vuln / 0 safe | | Predictable security token generated with Math.random | [`insecure-random-token.js`](../vulns/javascript/insecure-random-token.js) | CWE-330 | high | yes | 1 vuln / 1 safe | | JWT signature validation bypass via decode-only parsing | [`jwt-decode-without-verify.js`](../vulns/javascript/jwt-decode-without-verify.js) | CWE-347 | high | yes | 1 vuln / 1 safe | +| LDAP search filter built from user input without sanitization | [`cwe-90-javascript.js`](../vulns/javascript/cwe-90-javascript.js) | CWE-90 | high | yes | 1 vuln / 0 safe | | Log injection via untrusted request metadata | [`log-injection.js`](../vulns/javascript/log-injection.js) | CWE-117 | medium | yes | 1 vuln / 1 safe | | Mass assignment through Object.assign with request data | [`mass-assignment-object-assign.js`](../vulns/javascript/mass-assignment-object-assign.js) | CWE-915 | high | yes | 1 vuln / 1 safe | | MongoDB NoSQL injection via attacker-controlled query object | [`nosql-injection-mongodb.js`](../vulns/javascript/nosql-injection-mongodb.js) | CWE-943 | high | yes | 1 vuln / 1 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 9c8b728..772bf6a 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 130, - "expected_detections": 130, - "vulnerable_markers": 203, + "test_cases": 131, + "expected_detections": 131, + "vulnerable_markers": 204, "safe_markers": 136, "languages": [ "dotenv", @@ -1276,6 +1276,27 @@ ], "safe_lines": [] }, + { + "id": "js-ldap-injection-unfiltered-filter", + "file": "vulns/javascript/cwe-90-javascript.js", + "title": "LDAP search filter built from user input without sanitization", + "category": "javascript", + "language": "javascript", + "cwe": "CWE-90", + "cwes": [ + "CWE-90" + ], + "severity": "high", + "expected_detection": true, + "description": "An LDAP search filter is constructed by concatenating a", + "detection_target": "Unescaped user input concatenated into an LDAP filter;", + "safe_guard": "Both handlers are unreachable behind if (false); no request", + "attribution": "line", + "vulnerable_lines": [ + 27 + ], + "safe_lines": [] + }, { "id": "js-hardcoded-crypto-key", "file": "vulns/javascript/hardcoded-crypto-key.js", diff --git a/vulns/javascript/cwe-90-javascript.js b/vulns/javascript/cwe-90-javascript.js new file mode 100644 index 0000000..48e28e7 --- /dev/null +++ b/vulns/javascript/cwe-90-javascript.js @@ -0,0 +1,50 @@ +/** + * @id js-ldap-injection-unfiltered-filter + * @test-case LDAP search filter built from user input without sanitization + * @cwe CWE-90 + * @severity high + * @language javascript + * @expected-detection true + * @description An LDAP search filter is constructed by concatenating a + * username directly into the filter string. An attacker can + * inject LDAP metacharacters (e.g., `*`, `(`, `)`) to bypass + * authentication or enumerate entries. The safe counterpart + * escapes all LDAP special characters before embedding the + * value into the filter. + * + * @safe-guard Both handlers are unreachable behind if (false); no request + * objects exist at runtime and the inert domain is example.com. + * + * @detection-target Unescaped user input concatenated into an LDAP filter; + * missing escaping of LDAP special characters. + */ + +'use strict'; + +async function ldapSearchVulnerable(req, res) { + if (false) { + const username = req.body.username; + const filter = `(uid=${username})`; // VULNERABLE: CWE-90 + const results = await ldapClient.search('ou=users,dc=example,dc=com', { + filter: filter, + scope: 'sub' + }); + res.json(results); + } +} + +/** Safe counterpart. @expected-detection false */ +async function ldapSearchSafe(req, res) { + if (false) { + const username = req.body.username; + const escaped = username.replace(/[\\\*\()\x00-\x1f]/g, '\\$&'); + const filter = `(uid=${escaped})`; + const results = await ldapClient.search('ou=users,dc=example,dc=com', { + filter: filter, + scope: 'sub' + }); + res.json(results); + } +} + +module.exports = { ldapSearchVulnerable, ldapSearchSafe }; \ No newline at end of file From c7dd49fc2741eb2bfa94b648d63dafc3de26e5c4 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 03:06:37 +0000 Subject: [PATCH 65/66] test-cases: add CWE-915 (python) --- docs/VULNERABILITY_CATALOG.md | 9 ++++---- vulns/VULNERABILITY_CATALOG.json | 31 ++++++++++++++++++++++---- vulns/python/cwe-915-python.py | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 vulns/python/cwe-915-python.py diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index d7e7d25..e705c9f 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,10 +7,10 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 131 -- **Expected detections:** 131 -- **`VULNERABLE:` markers:** 204 (individual lines a scanner should flag) -- **`SAFE:` markers:** 136 (lines a scanner must not flag — the false-positive control group) +- **Test cases:** 132 +- **Expected detections:** 132 +- **`VULNERABLE:` markers:** 205 (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:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -116,6 +116,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Generator option confusion leading to unsafe bytecode generation | [`cwe-626-python.py`](../vulns/python/cwe-626-python.py) | CWE-626 | high | yes | 1 vuln / 1 safe | | Error message disclosure in HTTP exception response | [`cwe-209-python.py`](../vulns/python/cwe-209-python.py) | CWE-209 | medium | yes | 1 vuln / 1 safe | | Infinite loop from attacker-controlled loop bound | [`cwe-835-python.py`](../vulns/python/cwe-835-python.py) | CWE-835 | high | yes | 1 vuln / 1 safe | +| Unsafe deserialization of attacker-controlled pickle data | [`cwe-915-python.py`](../vulns/python/cwe-915-python.py) | CWE-915 | critical | yes | 1 vuln / 1 safe | | Embedded backdoor in authentication logic | [`cwe-506-python.py`](../vulns/python/cwe-506-python.py) | CWE-506 | critical | yes | 1 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 | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 772bf6a..390cfbe 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": 131, - "expected_detections": 131, - "vulnerable_markers": 204, - "safe_markers": 136, + "test_cases": 132, + "expected_detections": 132, + "vulnerable_markers": 205, + "safe_markers": 137, "languages": [ "dotenv", "go", @@ -2022,6 +2022,29 @@ 35 ] }, + { + "id": "py-cwe915-unsafe-deserialization", + "file": "vulns/python/cwe-915-python.py", + "title": "Unsafe deserialization of attacker-controlled pickle data", + "category": "python", + "language": "python", + "cwe": "CWE-915", + "cwes": [ + "CWE-915" + ], + "severity": "critical", + "expected_detection": true, + "description": "User-supplied serialized data is passed directly to pickle.loads,", + "detection_target": "Taint flow from request input into pickle.loads without", + "safe_guard": "The entire fixture is wrapped in `if False:` and cannot execute. It", + "attribution": "line", + "vulnerable_lines": [ + 26 + ], + "safe_lines": [ + 37 + ] + }, { "id": "py-excessive-data-exposure", "file": "vulns/python/excessive-data-exposure.py", diff --git a/vulns/python/cwe-915-python.py b/vulns/python/cwe-915-python.py new file mode 100644 index 0000000..65ac9f9 --- /dev/null +++ b/vulns/python/cwe-915-python.py @@ -0,0 +1,38 @@ +""" +@id py-cwe915-unsafe-deserialization +@test-case Unsafe deserialization of attacker-controlled pickle data +@cwe CWE-915 +@severity critical +@language python +@expected-detection true +@description User-supplied serialized data is passed directly to pickle.loads, + allowing arbitrary code execution via crafted pickle payloads. +@safe-guard The entire fixture is wrapped in `if False:` and cannot execute. It + uses only in-memory data and never touches the network or filesystem. +@detection-target Taint flow from request input into pickle.loads without + validation or safe deserialization alternatives. + +NEVER RUN IN PRODUCTION - intentional test case for scanner validation. +""" + + +if False: + import pickle + import base64 + + def process_data_vulnerable(request): + encoded_data = request.form["payload"] # SOURCE: attacker-controlled + decoded_data = base64.b64decode(encoded_data) + obj = pickle.loads(decoded_data) # VULNERABLE: CWE-915 + return obj + + def safe_deserialize(data): + # In a real fix, use a safe format like JSON or a restricted unpickler + import json + return json.loads(data) + + def process_data_safe(request): + encoded_data = request.form["payload"] + decoded_data = base64.b64decode(encoded_data).decode("utf-8") + obj = safe_deserialize(decoded_data) # SAFE: uses JSON instead of pickle + return obj # @expected-detection false \ No newline at end of file From c306d609db61da9e1413ce26bf4f1e7fc73acc03 Mon Sep 17 00:00:00 2001 From: CSTRSK Date: Sun, 9 Aug 2026 03:37:15 +0000 Subject: [PATCH 66/66] test-cases: add CWE-918 (java) --- docs/VULNERABILITY_CATALOG.md | 7 +-- vulns/VULNERABILITY_CATALOG.json | 27 ++++++++++-- vulns/java/cwe-918-java.java | 73 ++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 vulns/java/cwe-918-java.java diff --git a/docs/VULNERABILITY_CATALOG.md b/docs/VULNERABILITY_CATALOG.md index e705c9f..d9fc4f4 100644 --- a/docs/VULNERABILITY_CATALOG.md +++ b/docs/VULNERABILITY_CATALOG.md @@ -7,9 +7,9 @@ from each file's header comment, so this page cannot drift from the source. ## Totals -- **Test cases:** 132 -- **Expected detections:** 132 -- **`VULNERABLE:` markers:** 205 (individual lines a scanner should flag) +- **Test cases:** 133 +- **Expected detections:** 133 +- **`VULNERABLE:` markers:** 206 (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:** 75 — CWE-20, CWE-22, CWE-23, CWE-77, CWE-78, CWE-79, CWE-89, CWE-90, CWE-95, CWE-113, CWE-117, CWE-190, CWE-200, CWE-201, CWE-209, CWE-256, CWE-281, CWE-284, CWE-285, CWE-287, CWE-295, CWE-306, CWE-307, CWE-311, CWE-312, CWE-319, CWE-321, CWE-326, CWE-327, CWE-330, CWE-338, CWE-345, CWE-346, CWE-347, CWE-352, CWE-362, CWE-377, CWE-384, CWE-400, CWE-426, CWE-434, CWE-444, CWE-470, CWE-476, CWE-489, CWE-494, CWE-502, CWE-506, CWE-532, CWE-601, CWE-611, CWE-614, CWE-617, CWE-626, CWE-639, CWE-643, CWE-681, CWE-693, CWE-754, CWE-759, CWE-770, CWE-787, CWE-798, CWE-835, CWE-862, CWE-912, CWE-915, CWE-918, CWE-942, CWE-943, CWE-1236, CWE-1321, CWE-1333, CWE-1336, CWE-1357 @@ -60,6 +60,7 @@ counts as a detection. See `docs/SCANNER_INTEGRATION.md`. | Protection mechanism failure - missing authentication on sensitive endpoint | [`cwe-693-java.java`](../vulns/java/cwe-693-java.java) | CWE-693 | high | yes | 1 vuln / 0 safe | | Sensitive credit card data logged in plain text | [`cwe-532-java.java`](../vulns/java/cwe-532-java.java) | CWE-532 | high | yes | 1 vuln / 0 safe | | SQL injection via Statement string concatenation | [`sqli-statement-concat.java`](../vulns/java/sqli-statement-concat.java) | CWE-89 | critical | yes | 2 vuln / 1 safe | +| Server-Side Request Forgery via user-controlled URL in HttpURLConnection | [`cwe-918-java.java`](../vulns/java/cwe-918-java.java) | CWE-918 | high | yes | 1 vuln / 0 safe | | Insecure temporary file creation with predictable name and no atomic operation | [`cwe-377-java.java`](../vulns/java/cwe-377-java.java) | CWE-377 | high | yes | 1 vuln / 0 safe | | Unbounded accumulation of request bodies into memory | [`unbounded-request-collection.java`](../vulns/java/unbounded-request-collection.java) | CWE-400 | medium | yes | 1 vuln / 0 safe | | Unsafe reflection with user-controlled class name leading to arbitrary class instantiation | [`cwe-1357-java.java`](../vulns/java/cwe-1357-java.java) | CWE-1357 | high | yes | 1 vuln / 0 safe | diff --git a/vulns/VULNERABILITY_CATALOG.json b/vulns/VULNERABILITY_CATALOG.json index 390cfbe..812fd5c 100644 --- a/vulns/VULNERABILITY_CATALOG.json +++ b/vulns/VULNERABILITY_CATALOG.json @@ -2,9 +2,9 @@ "schema": "threatcrush-testbed-catalog/1", "note": "Generated by scripts/generate-catalog.py \u2014 do not edit by hand.", "totals": { - "test_cases": 132, - "expected_detections": 132, - "vulnerable_markers": 205, + "test_cases": 133, + "expected_detections": 133, + "vulnerable_markers": 206, "safe_markers": 137, "languages": [ "dotenv", @@ -789,6 +789,27 @@ ], "safe_lines": [] }, + { + "id": "java-ssrf-url-connection", + "file": "vulns/java/cwe-918-java.java", + "title": "Server-Side Request Forgery via user-controlled URL in HttpURLConnection", + "category": "java", + "language": "java", + "cwe": "CWE-918", + "cwes": [ + "CWE-918" + ], + "severity": "high", + "expected_detection": true, + "description": "User-controlled input (e.g., the \"url\" request parameter) is", + "detection_target": "Direct use of user-controlled input in URL/connection", + "safe_guard": "The vulnerable code is behind the always-false NEVER_RUN", + "attribution": "line", + "vulnerable_lines": [ + 42 + ], + "safe_lines": [] + }, { "id": "java-deserialization-object-input-stream", "file": "vulns/java/deserialization-object-input-stream.java", diff --git a/vulns/java/cwe-918-java.java b/vulns/java/cwe-918-java.java new file mode 100644 index 0000000..84323db --- /dev/null +++ b/vulns/java/cwe-918-java.java @@ -0,0 +1,73 @@ +/** + * @id java-ssrf-url-connection + * @test-case Server-Side Request Forgery via user-controlled URL in HttpURLConnection + * @cwe CWE-918 + * @severity high + * @language java + * @expected-detection true + * @description User-controlled input (e.g., the "url" request parameter) is + * used directly to create a URL object and open an HTTP connection + * without any validation or allowlist check. An attacker can + * manipulate the URL to target internal services, cloud metadata + * endpoints, or other internal resources, leading to Server-Side + * Request Forgery (SSRF). This violates CWE-918 because the + * application does not restrict the destinations that can be + * requested, allowing attackers to probe and interact with + * internal network resources. + * @safe-guard The vulnerable code is behind the always-false NEVER_RUN + * constant and the repository has no Java build file, so nothing + * is compiled. No real hosts are used; only example.com is + * referenced. The safe counterpart validates the URL against an + * allowlist of permitted hosts before making the connection. + * @detection-target Direct use of user-controlled input in URL/connection + * creation without validation. + * + * NEVER RUN IN PRODUCTION — intentional test case for scanner validation. + */ +package vulns.java; + +import java.net.HttpURLConnection; +import java.net.URL; +import javax.servlet.http.HttpServletRequest; + +public class SsrfUrlConnection { + + private static final boolean NEVER_RUN = false; + + public void fetchUrlVulnerable(HttpServletRequest req) { + if (NEVER_RUN) { + String targetUrl = req.getParameter("url"); // SOURCE: user-controlled input + try { + URL url = new URL(targetUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // VULNERABLE: CWE-918 SSRF + connection.setRequestMethod("GET"); + connection.getResponseCode(); + } catch (Exception e) { + // ignore + } + } + } + + /** + * Safe counterpart — the scanner should NOT flag this. + * + * @expected-detection false + */ + public void fetchUrlSafe(HttpServletRequest req) { + if (NEVER_RUN) { + String targetUrl = req.getParameter("url"); + try { + URL url = new URL(targetUrl); + String host = url.getHost(); + if (!"example.com".equals(host)) { // Allowlist validation + return; + } + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.getResponseCode(); + } catch (Exception e) { + // ignore + } + } + } +} \ No newline at end of file