@hoanghainh/komagu 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +1 -1
- package/assess/lsa/examples/eval-run-4/ground-truth.json +823 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/ai-run-stats.json +58 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/coverage.json +85 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings/priv-privilege-001.json +822 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings/priv-privilege-002.json +393 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings.json +4477 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/score.json +120 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/ai-run-stats.json +55 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/coverage.json +50 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings/priv-privilege-001.json +613 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings/priv-privilege-002.json +287 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings.json +4870 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/score.json +107 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/ai-run-stats.json +58 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/coverage.json +92 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings/priv-privilege-001.json +645 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings/priv-privilege-002.json +222 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings.json +4859 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/score.json +121 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/coverage.json +111 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings/priv-privilege-001.json +6 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings/priv-privilege-002.json +344 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings.json +3544 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/score.json +123 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/ai-run-stats.json +50 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/coverage.json +42 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings/priv-privilege-001.json +540 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings/priv-privilege-002.json +238 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings.json +4383 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings.sarif +8729 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/report.ja.md +1911 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/report.md +1911 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/score.json +101 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/stack-profile.json +226 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/ai-run-stats.json +54 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/coverage.json +66 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings/priv-privilege-001.json +440 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings/priv-privilege-002.json +229 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings.json +3424 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/score.json +120 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/ai-run-stats.json +88 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/coverage.json +36 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/findings/priv-privilege-001.json +530 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/findings/priv-privilege-002.json +248 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/findings.json +4766 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/findings.sarif +9326 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/report.ja.md +2011 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/report.md +2011 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/score.json +80 -0
- package/assess/lsa/examples/eval-run-5/gptoss-a/stack-profile.json +226 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/ai-run-stats.json +83 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/coverage.json +44 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/findings/priv-privilege-001.json +579 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/findings/priv-privilege-002.json +268 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/findings.json +3913 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-5/gptoss-b/score.json +94 -0
- package/assess/lsa/examples/eval-run-5/ground-truth.json +823 -0
- package/assess/lsa/knowledge/injection-patterns.md +8 -1
- package/assess/lsa/knowledge/stacks/nextjs.md +62 -0
- package/assess/lsa/prompts/35-privilege-auditor.md +3 -1
- package/assess/lsa/prompts/_shared-rules.md +1 -0
- package/assess/lsa/scripts/detect_stack.py +5 -1
- package/assess/lsa/scripts/find_injection.py +34 -5
- package/assess/lsa/scripts/lsa_common.py +9 -2
- package/assess/lsa/scripts/make_batches.py +2 -1
- package/assess/lsa/scripts/map_routes.py +10 -2
- package/assess/lsa/scripts/nextjs_routes.py +236 -0
- package/assess/lsa/templates/audit-config.json +1 -1
- package/assess/lsa/tests/EVAL-RESULTS.md +156 -0
- package/assess/lsa/tests/score_findings.py +58 -0
- package/assess/lsa/tests/test_default_scope.py +86 -0
- package/assess/lsa/tests/test_eval_run_4.py +73 -0
- package/assess/lsa/tests/test_eval_run_5.py +73 -0
- package/assess/lsa/tests/test_js_tagged_sql.py +112 -0
- package/assess/lsa/tests/test_nextjs.py +198 -0
- package/assess/lsa/tests/test_privilege_tier2.py +30 -0
- package/operate/ai/anchoring.py +130 -0
- package/operate/ai/client.py +13 -0
- package/operate/ai/context.py +105 -0
- package/operate/ai/runner.py +197 -69
- package/operate/cli/__init__.py +1 -1
- package/operate/cli/commands/scan.py +1 -1
- package/operate/tests/test_ai_anchoring.py +184 -0
- package/operate/tests/test_headless_ai.py +148 -1
- package/package.json +1 -1
|
@@ -0,0 +1,3424 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generated_by": "lsa merge_findings.py 0.3.1",
|
|
3
|
+
"summary": {
|
|
4
|
+
"total_reported": 76,
|
|
5
|
+
"active": 75,
|
|
6
|
+
"rejected_by_verifier": 1,
|
|
7
|
+
"by_severity": {
|
|
8
|
+
"critical": 48,
|
|
9
|
+
"high": 27,
|
|
10
|
+
"medium": 0,
|
|
11
|
+
"low": 0,
|
|
12
|
+
"info": 0
|
|
13
|
+
},
|
|
14
|
+
"by_category": {
|
|
15
|
+
"bola": 26,
|
|
16
|
+
"sql_injection": 32,
|
|
17
|
+
"nosql_injection": 0,
|
|
18
|
+
"bfla": 10,
|
|
19
|
+
"mass_assignment": 7
|
|
20
|
+
},
|
|
21
|
+
"by_status": {
|
|
22
|
+
"unverified": 0,
|
|
23
|
+
"confirmed": 41,
|
|
24
|
+
"likely": 34,
|
|
25
|
+
"rejected": 1,
|
|
26
|
+
"needs_review": 0
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"findings": [
|
|
30
|
+
{
|
|
31
|
+
"finding_id": "BFLA-R-0007-1",
|
|
32
|
+
"category": "bfla",
|
|
33
|
+
"subtype": "missing_role_check",
|
|
34
|
+
"title": "Authenticated users can delete any user",
|
|
35
|
+
"route_id": "R-0007",
|
|
36
|
+
"location": {
|
|
37
|
+
"file": "dotnet-mvc/Controllers/AdminController.cs",
|
|
38
|
+
"start_line": 11
|
|
39
|
+
},
|
|
40
|
+
"evidence": [
|
|
41
|
+
{
|
|
42
|
+
"file": "dotnet-mvc/Controllers/AdminController.cs",
|
|
43
|
+
"line": 12,
|
|
44
|
+
"why": "DeleteUser action has no role check; only [Authorize] allows any authenticated user"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"impact": "Delete any user account",
|
|
48
|
+
"severity": "critical",
|
|
49
|
+
"confidence": "medium",
|
|
50
|
+
"cwe": [
|
|
51
|
+
"CWE-285"
|
|
52
|
+
],
|
|
53
|
+
"recommendation": "Add [Authorize(Roles=\"Admin\")] to DeleteUser",
|
|
54
|
+
"status": "likely",
|
|
55
|
+
"verification": {
|
|
56
|
+
"verdict": "likely",
|
|
57
|
+
"reason_code": "code_not_visible",
|
|
58
|
+
"checked": [
|
|
59
|
+
"dotnet-mvc/Controllers/AdminController.cs: file not found"
|
|
60
|
+
],
|
|
61
|
+
"control_found": null,
|
|
62
|
+
"notes": "The file containing the DeleteUser action is not present in the provided code context, so the presence or absence of a role check or global filter cannot be verified.",
|
|
63
|
+
"suggested_subtype": null,
|
|
64
|
+
"suggested_cwe": null
|
|
65
|
+
},
|
|
66
|
+
"fingerprint": "kfp1:b52a00e684b8937065a717719055ce932593e6e26d6aef650a5b837e2ab923b2",
|
|
67
|
+
"baseline_state": "new"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"finding_id": "BFLA-R-0009-1",
|
|
71
|
+
"category": "bfla",
|
|
72
|
+
"subtype": "missing_role_check",
|
|
73
|
+
"title": "Export users without role check",
|
|
74
|
+
"route_id": "R-0009",
|
|
75
|
+
"location": {
|
|
76
|
+
"file": "dotnet-mvc/Controllers/AdminController.cs",
|
|
77
|
+
"start_line": 30
|
|
78
|
+
},
|
|
79
|
+
"evidence": [
|
|
80
|
+
{
|
|
81
|
+
"file": "dotnet-mvc/Controllers/AdminController.cs",
|
|
82
|
+
"line": 32,
|
|
83
|
+
"why": "Export action uses Request.QueryString[\"isAdmin\"] to allow export; no role check"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"impact": "Export all user data",
|
|
87
|
+
"severity": "critical",
|
|
88
|
+
"confidence": "medium",
|
|
89
|
+
"cwe": [
|
|
90
|
+
"CWE-285"
|
|
91
|
+
],
|
|
92
|
+
"recommendation": "Add role check before exporting data",
|
|
93
|
+
"status": "likely",
|
|
94
|
+
"verification": {
|
|
95
|
+
"verdict": "likely",
|
|
96
|
+
"reason_code": "code_not_visible",
|
|
97
|
+
"checked": [
|
|
98
|
+
"dotnet-mvc/Controllers/AdminController.cs: file not found"
|
|
99
|
+
],
|
|
100
|
+
"control_found": null,
|
|
101
|
+
"notes": "The file containing the Export action is missing from the code context; therefore, it is impossible to confirm whether a role check or other authorization guard is applied.",
|
|
102
|
+
"suggested_subtype": null,
|
|
103
|
+
"suggested_cwe": null
|
|
104
|
+
},
|
|
105
|
+
"fingerprint": "kfp1:58b1f4b0d83443a8d643d8cca8efcfc8799f0d17828379a4ba3ac681785a425f",
|
|
106
|
+
"baseline_state": "new"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"finding_id": "BFLA-R-0023-1",
|
|
110
|
+
"category": "bfla",
|
|
111
|
+
"subtype": "missing_role_check",
|
|
112
|
+
"title": "Delete user without admin check",
|
|
113
|
+
"route_id": "R-0023",
|
|
114
|
+
"location": {
|
|
115
|
+
"file": "java-spring/Controllers/AdminUserController.java",
|
|
116
|
+
"start_line": 13
|
|
117
|
+
},
|
|
118
|
+
"evidence": [
|
|
119
|
+
{
|
|
120
|
+
"file": "java-spring/Controllers/AdminUserController.java",
|
|
121
|
+
"line": 13,
|
|
122
|
+
"why": "Delete mapping has no @PreAuthorize; any authenticated user can delete"
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"impact": "Delete any user account",
|
|
126
|
+
"severity": "critical",
|
|
127
|
+
"confidence": "medium",
|
|
128
|
+
"cwe": [
|
|
129
|
+
"CWE-285"
|
|
130
|
+
],
|
|
131
|
+
"recommendation": "Add @PreAuthorize(\"hasRole('ADMIN')\") to delete method",
|
|
132
|
+
"status": "likely",
|
|
133
|
+
"verification": {
|
|
134
|
+
"verdict": "likely",
|
|
135
|
+
"reason_code": "code_not_visible",
|
|
136
|
+
"checked": [
|
|
137
|
+
"file not found: java-spring/Controllers/AdminUserController.java"
|
|
138
|
+
],
|
|
139
|
+
"control_found": null,
|
|
140
|
+
"notes": "The source file is not present in the provided code context, so the presence or absence of a @PreAuthorize annotation cannot be verified.",
|
|
141
|
+
"suggested_subtype": null,
|
|
142
|
+
"suggested_cwe": null
|
|
143
|
+
},
|
|
144
|
+
"fingerprint": "kfp1:67fe69709bdaa8979de1cf89c1beacb15290f4c76432496e7955d99b05ef6867",
|
|
145
|
+
"baseline_state": "new"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"finding_id": "BFLA-R-0030-1",
|
|
149
|
+
"category": "bfla",
|
|
150
|
+
"subtype": "missing_role_check",
|
|
151
|
+
"title": "Delete user without admin check",
|
|
152
|
+
"route_id": "R-0030",
|
|
153
|
+
"location": {
|
|
154
|
+
"file": "node-express/routes.js",
|
|
155
|
+
"start_line": 8
|
|
156
|
+
},
|
|
157
|
+
"evidence": [
|
|
158
|
+
{
|
|
159
|
+
"file": "node-express/routes.js",
|
|
160
|
+
"line": 8,
|
|
161
|
+
"why": "Route uses ensureLoggedIn but no requireAdmin; any logged‑in user can delete"
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
"impact": "Delete any user account",
|
|
165
|
+
"severity": "critical",
|
|
166
|
+
"confidence": "medium",
|
|
167
|
+
"cwe": [
|
|
168
|
+
"CWE-285"
|
|
169
|
+
],
|
|
170
|
+
"recommendation": "Add requireAdmin middleware to delete route",
|
|
171
|
+
"status": "likely",
|
|
172
|
+
"verification": {
|
|
173
|
+
"verdict": "likely",
|
|
174
|
+
"reason_code": "code_not_visible",
|
|
175
|
+
"checked": [
|
|
176
|
+
"file not found: node-express/routes.js"
|
|
177
|
+
],
|
|
178
|
+
"control_found": null,
|
|
179
|
+
"notes": "The route definition is not included in the code context; therefore it is impossible to confirm whether a requireAdmin middleware is applied.",
|
|
180
|
+
"suggested_subtype": null,
|
|
181
|
+
"suggested_cwe": null
|
|
182
|
+
},
|
|
183
|
+
"fingerprint": "kfp1:7e345776f9dfd2f6d4ea769220e25a1c43c4320f55eb66eb03c9dcbb0452d6d5",
|
|
184
|
+
"baseline_state": "new"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"finding_id": "BFLA-R-0032-1",
|
|
188
|
+
"category": "bfla",
|
|
189
|
+
"subtype": "missing_role_check",
|
|
190
|
+
"title": "Export reports without admin check",
|
|
191
|
+
"route_id": "R-0032",
|
|
192
|
+
"location": {
|
|
193
|
+
"file": "node-express/routes.js",
|
|
194
|
+
"start_line": 16
|
|
195
|
+
},
|
|
196
|
+
"evidence": [
|
|
197
|
+
{
|
|
198
|
+
"file": "node-express/routes.js",
|
|
199
|
+
"line": 16,
|
|
200
|
+
"why": "Export route uses ensureLoggedIn but no requireAdmin; any logged‑in user can export"
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
"impact": "Export all report data",
|
|
204
|
+
"severity": "critical",
|
|
205
|
+
"confidence": "medium",
|
|
206
|
+
"cwe": [
|
|
207
|
+
"CWE-285"
|
|
208
|
+
],
|
|
209
|
+
"recommendation": "Add requireAdmin middleware to export route",
|
|
210
|
+
"status": "likely",
|
|
211
|
+
"verification": {
|
|
212
|
+
"verdict": "likely",
|
|
213
|
+
"reason_code": "code_not_visible",
|
|
214
|
+
"checked": [
|
|
215
|
+
"file not found: node-express/routes.js"
|
|
216
|
+
],
|
|
217
|
+
"control_found": null,
|
|
218
|
+
"notes": "The export route is not present in the provided context, so the absence of an admin guard cannot be verified.",
|
|
219
|
+
"suggested_subtype": null,
|
|
220
|
+
"suggested_cwe": null
|
|
221
|
+
},
|
|
222
|
+
"fingerprint": "kfp1:2d335b1c4cd2c98c6c58c4e4e3b4f8bf693d1e494e830c4c8db778c639cded3e",
|
|
223
|
+
"baseline_state": "new"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"finding_id": "BFLA-R-0057-1",
|
|
227
|
+
"category": "bfla",
|
|
228
|
+
"subtype": "missing_role_check",
|
|
229
|
+
"title": "View user data without admin check",
|
|
230
|
+
"route_id": "R-0057",
|
|
231
|
+
"location": {
|
|
232
|
+
"file": "php-plain/admin.php",
|
|
233
|
+
"start_line": 6
|
|
234
|
+
},
|
|
235
|
+
"evidence": [
|
|
236
|
+
{
|
|
237
|
+
"file": "php-plain/admin.php",
|
|
238
|
+
"line": 6,
|
|
239
|
+
"why": "Case 'view' executes without any role check; any logged‑in user can view any user"
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
"impact": "View any user record",
|
|
243
|
+
"severity": "critical",
|
|
244
|
+
"confidence": "medium",
|
|
245
|
+
"cwe": [
|
|
246
|
+
"CWE-285"
|
|
247
|
+
],
|
|
248
|
+
"recommendation": "Add checkRole('admin') before executing view logic",
|
|
249
|
+
"status": "likely",
|
|
250
|
+
"verification": {
|
|
251
|
+
"verdict": "likely",
|
|
252
|
+
"reason_code": "control_found",
|
|
253
|
+
"checked": [
|
|
254
|
+
"php-plain/admin.php lines 5-14",
|
|
255
|
+
"php-plain/inc/auth.php lines 1-7"
|
|
256
|
+
],
|
|
257
|
+
"control_found": {
|
|
258
|
+
"file": "php-plain/inc/auth.php",
|
|
259
|
+
"line": 3,
|
|
260
|
+
"code": "session_start();"
|
|
261
|
+
},
|
|
262
|
+
"notes": "The included auth file only performs a login check and does not enforce a role check. No role guard is visible before the 'view' case, so the missing role check is likely.",
|
|
263
|
+
"suggested_subtype": null,
|
|
264
|
+
"suggested_cwe": null
|
|
265
|
+
},
|
|
266
|
+
"fingerprint": "kfp1:d49176fe451bbe3c61de25550631bf23a5b4b79949df949f18698aa7183f6e10",
|
|
267
|
+
"baseline_state": "new"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"finding_id": "BFLA-R-0058-1",
|
|
271
|
+
"category": "bfla",
|
|
272
|
+
"subtype": "missing_role_check",
|
|
273
|
+
"title": "Delete user without admin check",
|
|
274
|
+
"route_id": "R-0058",
|
|
275
|
+
"location": {
|
|
276
|
+
"file": "php-plain/admin.php",
|
|
277
|
+
"start_line": 10
|
|
278
|
+
},
|
|
279
|
+
"evidence": [
|
|
280
|
+
{
|
|
281
|
+
"file": "php-plain/admin.php",
|
|
282
|
+
"line": 10,
|
|
283
|
+
"why": "Case 'delete' executes without any role check; any logged‑in user can delete any user"
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
"impact": "Delete any user account",
|
|
287
|
+
"severity": "critical",
|
|
288
|
+
"confidence": "medium",
|
|
289
|
+
"cwe": [
|
|
290
|
+
"CWE-285"
|
|
291
|
+
],
|
|
292
|
+
"recommendation": "Add checkRole('admin') before executing delete logic",
|
|
293
|
+
"status": "likely",
|
|
294
|
+
"verification": {
|
|
295
|
+
"verdict": "likely",
|
|
296
|
+
"reason_code": "control_found",
|
|
297
|
+
"checked": [
|
|
298
|
+
"php-plain/admin.php lines 5-14",
|
|
299
|
+
"php-plain/inc/auth.php lines 1-7"
|
|
300
|
+
],
|
|
301
|
+
"control_found": {
|
|
302
|
+
"file": "php-plain/inc/auth.php",
|
|
303
|
+
"line": 3,
|
|
304
|
+
"code": "session_start();"
|
|
305
|
+
},
|
|
306
|
+
"notes": "Similar to the view case, the delete case lacks any role verification. The auth file does not provide a role guard, so the missing role check is likely.",
|
|
307
|
+
"suggested_subtype": null,
|
|
308
|
+
"suggested_cwe": null
|
|
309
|
+
},
|
|
310
|
+
"fingerprint": "kfp1:781c6244908fea9052bbe7da28e222368d76d6420cac232e23403ef72b9d0f96",
|
|
311
|
+
"baseline_state": "new"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"finding_id": "BFLA-R-0059-1",
|
|
315
|
+
"category": "bfla",
|
|
316
|
+
"subtype": "missing_role_check",
|
|
317
|
+
"title": "Delete user without admin check",
|
|
318
|
+
"route_id": "R-0059",
|
|
319
|
+
"location": {
|
|
320
|
+
"file": "php-plain/manage_users.php",
|
|
321
|
+
"start_line": 5
|
|
322
|
+
},
|
|
323
|
+
"evidence": [
|
|
324
|
+
{
|
|
325
|
+
"file": "php-plain/manage_users.php",
|
|
326
|
+
"line": 5,
|
|
327
|
+
"why": "POST handler deletes user without any role check; any logged‑in user can delete any user"
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
"impact": "Delete any user account",
|
|
331
|
+
"severity": "critical",
|
|
332
|
+
"confidence": "medium",
|
|
333
|
+
"cwe": [
|
|
334
|
+
"CWE-285"
|
|
335
|
+
],
|
|
336
|
+
"recommendation": "Add checkRole('admin') before executing delete logic",
|
|
337
|
+
"status": "likely",
|
|
338
|
+
"verification": {
|
|
339
|
+
"verdict": "likely",
|
|
340
|
+
"reason_code": "code_not_visible",
|
|
341
|
+
"checked": [
|
|
342
|
+
"php-plain/manage_users.php",
|
|
343
|
+
"php-plain/inc/auth.php",
|
|
344
|
+
"php-plain/inc/db.php"
|
|
345
|
+
],
|
|
346
|
+
"control_found": null,
|
|
347
|
+
"notes": "The POST handler deletes a user without any role check. The role check in the HTML is only for rendering the link, not for authorization.",
|
|
348
|
+
"suggested_subtype": null,
|
|
349
|
+
"suggested_cwe": null
|
|
350
|
+
},
|
|
351
|
+
"fingerprint": "kfp1:87e92ef40927e74117d6d388e36bb9f58b621cb76c149805ce9d6cdb06c949d3",
|
|
352
|
+
"baseline_state": "new"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
"finding_id": "BFLA-R-0066-1",
|
|
356
|
+
"category": "bfla",
|
|
357
|
+
"subtype": "missing_role_check",
|
|
358
|
+
"title": "Delete user without admin check",
|
|
359
|
+
"route_id": "R-0066",
|
|
360
|
+
"location": {
|
|
361
|
+
"file": "php-plain/admin/delete_user.php",
|
|
362
|
+
"start_line": 1
|
|
363
|
+
},
|
|
364
|
+
"evidence": [
|
|
365
|
+
{
|
|
366
|
+
"file": "php-plain/admin/delete_user.php",
|
|
367
|
+
"line": 5,
|
|
368
|
+
"why": "Delete logic runs without any role check; any logged‑in user can delete any user"
|
|
369
|
+
}
|
|
370
|
+
],
|
|
371
|
+
"impact": "Delete any user account",
|
|
372
|
+
"severity": "critical",
|
|
373
|
+
"confidence": "medium",
|
|
374
|
+
"cwe": [
|
|
375
|
+
"CWE-285"
|
|
376
|
+
],
|
|
377
|
+
"recommendation": "Add checkRole('admin') before executing delete logic",
|
|
378
|
+
"status": "likely",
|
|
379
|
+
"verification": {
|
|
380
|
+
"verdict": "likely",
|
|
381
|
+
"reason_code": "code_not_visible",
|
|
382
|
+
"checked": [
|
|
383
|
+
"php-plain/admin/delete_user.php",
|
|
384
|
+
"php-plain/inc/auth.php",
|
|
385
|
+
"php-plain/inc/db.php"
|
|
386
|
+
],
|
|
387
|
+
"control_found": null,
|
|
388
|
+
"notes": "No role or ownership check is visible in the delete_user.php file or its included files. The delete operation is executed directly after a cast of the POST id.",
|
|
389
|
+
"suggested_subtype": null,
|
|
390
|
+
"suggested_cwe": null
|
|
391
|
+
},
|
|
392
|
+
"fingerprint": "kfp1:ac5acea0a998815d202206c2242aa04d68020c74c2b9bf604fd6e9620c81190d",
|
|
393
|
+
"baseline_state": "new"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"finding_id": "BFLA-R-0067-1",
|
|
397
|
+
"category": "bfla",
|
|
398
|
+
"subtype": "missing_role_check",
|
|
399
|
+
"title": "Promote user without admin check",
|
|
400
|
+
"route_id": "R-0067",
|
|
401
|
+
"location": {
|
|
402
|
+
"file": "php-plain/admin/promote.php",
|
|
403
|
+
"start_line": 1
|
|
404
|
+
},
|
|
405
|
+
"evidence": [
|
|
406
|
+
{
|
|
407
|
+
"file": "php-plain/admin/promote.php",
|
|
408
|
+
"line": 5,
|
|
409
|
+
"why": "Role promotion runs without any role check; any logged‑in user can promote themselves"
|
|
410
|
+
}
|
|
411
|
+
],
|
|
412
|
+
"impact": "Promote any user to admin",
|
|
413
|
+
"severity": "critical",
|
|
414
|
+
"confidence": "medium",
|
|
415
|
+
"cwe": [
|
|
416
|
+
"CWE-285"
|
|
417
|
+
],
|
|
418
|
+
"recommendation": "Add checkRole('admin') before executing promotion logic",
|
|
419
|
+
"status": "likely",
|
|
420
|
+
"verification": {
|
|
421
|
+
"verdict": "likely",
|
|
422
|
+
"reason_code": "code_not_visible",
|
|
423
|
+
"checked": [
|
|
424
|
+
"php-plain/admin/promote.php",
|
|
425
|
+
"php-plain/inc/auth.php",
|
|
426
|
+
"php-plain/inc/db.php"
|
|
427
|
+
],
|
|
428
|
+
"control_found": null,
|
|
429
|
+
"notes": "The promotion logic runs without any role check. The included auth file only verifies a session exists.",
|
|
430
|
+
"suggested_subtype": null,
|
|
431
|
+
"suggested_cwe": null
|
|
432
|
+
},
|
|
433
|
+
"fingerprint": "kfp1:9e62ffadab57311e100d17a047cbe239b641729275551deca79956c05c0dbbee",
|
|
434
|
+
"baseline_state": "new"
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
"finding_id": "INJ-I-0001",
|
|
438
|
+
"category": "sql_injection",
|
|
439
|
+
"subtype": "string_concatenation",
|
|
440
|
+
"title": "SQL Injection in classic-asp/shop/member.asp:6",
|
|
441
|
+
"candidate_id": "I-0001",
|
|
442
|
+
"location": {
|
|
443
|
+
"file": "classic-asp/shop/member.asp",
|
|
444
|
+
"start_line": 6
|
|
445
|
+
},
|
|
446
|
+
"evidence": [
|
|
447
|
+
{
|
|
448
|
+
"file": "classic-asp/shop/member.asp",
|
|
449
|
+
"start_line": 6,
|
|
450
|
+
"code": "sql = \"UPDATE members SET name = '\" & Replace(Request.Form(\"name\"), \"'\", \"''\") & \"'\"",
|
|
451
|
+
"why": "Unsanitized member_id concatenated into query",
|
|
452
|
+
"line": 6
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"file": "classic-asp/shop/member.asp",
|
|
456
|
+
"start_line": 7,
|
|
457
|
+
"code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
|
|
458
|
+
"why": "member_id from form is concatenated without sanitization",
|
|
459
|
+
"line": 7
|
|
460
|
+
}
|
|
461
|
+
],
|
|
462
|
+
"severity": "critical",
|
|
463
|
+
"confidence": "high",
|
|
464
|
+
"cwe": [
|
|
465
|
+
"CWE-89"
|
|
466
|
+
],
|
|
467
|
+
"recommendation": "Use parameterized queries",
|
|
468
|
+
"status": "confirmed",
|
|
469
|
+
"verification": {
|
|
470
|
+
"verdict": "confirmed",
|
|
471
|
+
"reason_code": "traced",
|
|
472
|
+
"checked": [
|
|
473
|
+
"classic-asp/shop/member.asp:6-8",
|
|
474
|
+
"classic-asp/shop/inc/auth.asp:1-3",
|
|
475
|
+
"classic-asp/shop/inc/conn.asp:1-4"
|
|
476
|
+
],
|
|
477
|
+
"control_found": null,
|
|
478
|
+
"notes": "The SQL UPDATE statement concatenates user-supplied 'name' and 'member_id' directly into the query. No sanitization, parameterization, or ownership check is present.",
|
|
479
|
+
"suggested_subtype": null,
|
|
480
|
+
"suggested_cwe": null
|
|
481
|
+
},
|
|
482
|
+
"fingerprint": "kfp1:52c63ccaf583de3933acccb3eff1f79314c58ac311cdeecdfc26c798403a7c89",
|
|
483
|
+
"baseline_state": "new"
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
"finding_id": "INJ-I-0002",
|
|
487
|
+
"category": "sql_injection",
|
|
488
|
+
"subtype": "string_concatenation",
|
|
489
|
+
"title": "SQL Injection in classic-asp/shop/member.asp:7",
|
|
490
|
+
"candidate_id": "I-0002",
|
|
491
|
+
"location": {
|
|
492
|
+
"file": "classic-asp/shop/member.asp",
|
|
493
|
+
"start_line": 7
|
|
494
|
+
},
|
|
495
|
+
"evidence": [
|
|
496
|
+
{
|
|
497
|
+
"file": "classic-asp/shop/member.asp",
|
|
498
|
+
"start_line": 7,
|
|
499
|
+
"code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
|
|
500
|
+
"why": "member_id from form is concatenated without sanitization",
|
|
501
|
+
"line": 7
|
|
502
|
+
}
|
|
503
|
+
],
|
|
504
|
+
"severity": "critical",
|
|
505
|
+
"confidence": "high",
|
|
506
|
+
"cwe": [
|
|
507
|
+
"CWE-89"
|
|
508
|
+
],
|
|
509
|
+
"recommendation": "Use parameterized queries",
|
|
510
|
+
"status": "confirmed",
|
|
511
|
+
"verification": {
|
|
512
|
+
"verdict": "confirmed",
|
|
513
|
+
"reason_code": "traced",
|
|
514
|
+
"checked": [
|
|
515
|
+
"classic-asp/shop/member.asp:7",
|
|
516
|
+
"classic-asp/shop/inc/auth.asp:1-3",
|
|
517
|
+
"classic-asp/shop/inc/conn.asp:1-4"
|
|
518
|
+
],
|
|
519
|
+
"control_found": null,
|
|
520
|
+
"notes": "The 'member_id' from the form is concatenated into the WHERE clause without sanitization. No ownership or role check is present.",
|
|
521
|
+
"suggested_subtype": null,
|
|
522
|
+
"suggested_cwe": null
|
|
523
|
+
},
|
|
524
|
+
"fingerprint": "kfp1:a425457aee9a3c9db04caa44ddba7d35ecadd834bf5a0100207b9fce90ea85dd",
|
|
525
|
+
"baseline_state": "new"
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"finding_id": "INJ-I-0003",
|
|
529
|
+
"category": "sql_injection",
|
|
530
|
+
"subtype": "string_concatenation",
|
|
531
|
+
"title": "SQL Injection in classic-asp/shop/member.asp:10",
|
|
532
|
+
"candidate_id": "I-0003",
|
|
533
|
+
"location": {
|
|
534
|
+
"file": "classic-asp/shop/member.asp",
|
|
535
|
+
"start_line": 10
|
|
536
|
+
},
|
|
537
|
+
"evidence": [
|
|
538
|
+
{
|
|
539
|
+
"file": "classic-asp/shop/member.asp",
|
|
540
|
+
"start_line": 10,
|
|
541
|
+
"code": "conn.Execute \"DELETE FROM members WHERE member_id = \" & Request.QueryString(\"member_id\")",
|
|
542
|
+
"why": "member_id from query string concatenated without sanitization",
|
|
543
|
+
"line": 10
|
|
544
|
+
}
|
|
545
|
+
],
|
|
546
|
+
"severity": "critical",
|
|
547
|
+
"confidence": "high",
|
|
548
|
+
"cwe": [
|
|
549
|
+
"CWE-89"
|
|
550
|
+
],
|
|
551
|
+
"recommendation": "Use parameterized queries",
|
|
552
|
+
"status": "confirmed",
|
|
553
|
+
"verification": {
|
|
554
|
+
"verdict": "confirmed",
|
|
555
|
+
"reason_code": "traced",
|
|
556
|
+
"checked": [
|
|
557
|
+
"classic-asp/shop/member.asp:10",
|
|
558
|
+
"classic-asp/shop/inc/auth.asp:1-3",
|
|
559
|
+
"classic-asp/shop/inc/conn.asp:1-4"
|
|
560
|
+
],
|
|
561
|
+
"control_found": null,
|
|
562
|
+
"notes": "The DELETE statement concatenates the 'member_id' from the query string directly into the SQL. No sanitization or ownership check is present.",
|
|
563
|
+
"suggested_subtype": null,
|
|
564
|
+
"suggested_cwe": null
|
|
565
|
+
},
|
|
566
|
+
"fingerprint": "kfp1:f1fb34f9c39374bc339b3dc230f5ac6b00731c69bf6cd1399b983ba2d2833525",
|
|
567
|
+
"baseline_state": "new"
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
"finding_id": "INJ-I-0004",
|
|
571
|
+
"category": "sql_injection",
|
|
572
|
+
"subtype": "string_concatenation",
|
|
573
|
+
"title": "SQL Injection in classic-asp/shop/order.asp:6",
|
|
574
|
+
"candidate_id": "I-0004",
|
|
575
|
+
"location": {
|
|
576
|
+
"file": "classic-asp/shop/order.asp",
|
|
577
|
+
"start_line": 6
|
|
578
|
+
},
|
|
579
|
+
"evidence": [
|
|
580
|
+
{
|
|
581
|
+
"file": "classic-asp/shop/order.asp",
|
|
582
|
+
"start_line": 6,
|
|
583
|
+
"code": "Set rs = conn.Execute(\"SELECT * FROM orders WHERE id = \" & id)",
|
|
584
|
+
"why": "id from Request(\"id\") concatenated without sanitization",
|
|
585
|
+
"line": 6
|
|
586
|
+
}
|
|
587
|
+
],
|
|
588
|
+
"severity": "critical",
|
|
589
|
+
"confidence": "high",
|
|
590
|
+
"cwe": [
|
|
591
|
+
"CWE-89"
|
|
592
|
+
],
|
|
593
|
+
"recommendation": "Use parameterized queries",
|
|
594
|
+
"status": "confirmed",
|
|
595
|
+
"verification": {
|
|
596
|
+
"verdict": "confirmed",
|
|
597
|
+
"reason_code": "traced",
|
|
598
|
+
"checked": [
|
|
599
|
+
"classic-asp/shop/order.asp:5-7",
|
|
600
|
+
"classic-asp/shop/inc/auth.asp:1-3",
|
|
601
|
+
"classic-asp/shop/inc/conn.asp:1-4"
|
|
602
|
+
],
|
|
603
|
+
"control_found": null,
|
|
604
|
+
"notes": "The SELECT query concatenates the 'id' parameter from the request directly into the SQL. No integer cast or sanitization is applied, making the query vulnerable to injection.",
|
|
605
|
+
"suggested_subtype": null,
|
|
606
|
+
"suggested_cwe": null
|
|
607
|
+
},
|
|
608
|
+
"fingerprint": "kfp1:07b1c914202a928e4156e6b6e9e5ab32fe7a75cdceda182d55d68051eeb61ac9",
|
|
609
|
+
"baseline_state": "new"
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
"finding_id": "INJ-I-0006",
|
|
613
|
+
"category": "sql_injection",
|
|
614
|
+
"subtype": "string_interpolation",
|
|
615
|
+
"title": "SQL Injection in coldfusion/app/OrderService.cfc:5",
|
|
616
|
+
"candidate_id": "I-0006",
|
|
617
|
+
"location": {
|
|
618
|
+
"file": "coldfusion/app/OrderService.cfc",
|
|
619
|
+
"start_line": 5
|
|
620
|
+
},
|
|
621
|
+
"evidence": [
|
|
622
|
+
{
|
|
623
|
+
"file": "coldfusion/app/OrderService.cfc",
|
|
624
|
+
"start_line": 5,
|
|
625
|
+
"code": "SELECT * FROM orders WHERE id = #arguments.orderId#",
|
|
626
|
+
"why": "Unescaped interpolation of user-supplied orderId",
|
|
627
|
+
"line": 5
|
|
628
|
+
}
|
|
629
|
+
],
|
|
630
|
+
"severity": "critical",
|
|
631
|
+
"confidence": "high",
|
|
632
|
+
"cwe": [
|
|
633
|
+
"CWE-89"
|
|
634
|
+
],
|
|
635
|
+
"recommendation": "Use cfqueryparam",
|
|
636
|
+
"status": "confirmed",
|
|
637
|
+
"verification": {
|
|
638
|
+
"verdict": "confirmed",
|
|
639
|
+
"reason_code": "traced",
|
|
640
|
+
"checked": [
|
|
641
|
+
"coldfusion/app/OrderService.cfc line 5 (unparameterized query)"
|
|
642
|
+
],
|
|
643
|
+
"control_found": null,
|
|
644
|
+
"notes": "No sanitization, casting, or ownership check is present in the provided code.",
|
|
645
|
+
"suggested_subtype": null,
|
|
646
|
+
"suggested_cwe": null
|
|
647
|
+
},
|
|
648
|
+
"fingerprint": "kfp1:cdc37b4cfc82f91bd79f6bdbab5d909d9e226c0f5c25e6d0d21e5a9f63feafcb",
|
|
649
|
+
"baseline_state": "new"
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
"finding_id": "INJ-I-0007",
|
|
653
|
+
"category": "sql_injection",
|
|
654
|
+
"subtype": "string_interpolation",
|
|
655
|
+
"title": "SQL Injection in coldfusion/app/order.cfm:3",
|
|
656
|
+
"candidate_id": "I-0007",
|
|
657
|
+
"location": {
|
|
658
|
+
"file": "coldfusion/app/order.cfm",
|
|
659
|
+
"start_line": 3
|
|
660
|
+
},
|
|
661
|
+
"evidence": [
|
|
662
|
+
{
|
|
663
|
+
"file": "coldfusion/app/order.cfm",
|
|
664
|
+
"start_line": 3,
|
|
665
|
+
"code": "SELECT * FROM orders WHERE id = #url.id#",
|
|
666
|
+
"why": "Unescaped interpolation of user-supplied id",
|
|
667
|
+
"line": 3
|
|
668
|
+
}
|
|
669
|
+
],
|
|
670
|
+
"severity": "critical",
|
|
671
|
+
"confidence": "high",
|
|
672
|
+
"cwe": [
|
|
673
|
+
"CWE-89"
|
|
674
|
+
],
|
|
675
|
+
"recommendation": "Use cfqueryparam",
|
|
676
|
+
"status": "confirmed",
|
|
677
|
+
"verification": {
|
|
678
|
+
"verdict": "confirmed",
|
|
679
|
+
"reason_code": "traced",
|
|
680
|
+
"checked": [
|
|
681
|
+
"coldfusion/app/order.cfm line 3 (unparameterized query)",
|
|
682
|
+
"coldfusion/app/order.cfm line 5-9 (parameterized query for ownership)"
|
|
683
|
+
],
|
|
684
|
+
"control_found": null,
|
|
685
|
+
"notes": "The first query uses raw interpolation of #url.id#, exposing the endpoint to SQL injection.",
|
|
686
|
+
"suggested_subtype": null,
|
|
687
|
+
"suggested_cwe": null
|
|
688
|
+
},
|
|
689
|
+
"fingerprint": "kfp1:46d854073fe8435e0c3698ca3af916cc7be7175dc0862be97b44ff0db21f1689",
|
|
690
|
+
"baseline_state": "new"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"finding_id": "INJ-I-0008",
|
|
694
|
+
"category": "sql_injection",
|
|
695
|
+
"subtype": "string_concatenation",
|
|
696
|
+
"title": "SQL Injection in dotnet-legacy/Web/Controllers/InvoiceController.cs:28",
|
|
697
|
+
"candidate_id": "I-0008",
|
|
698
|
+
"location": {
|
|
699
|
+
"file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
|
|
700
|
+
"start_line": 28
|
|
701
|
+
},
|
|
702
|
+
"evidence": [
|
|
703
|
+
{
|
|
704
|
+
"file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
|
|
705
|
+
"start_line": 28,
|
|
706
|
+
"code": "var list = db.Database.SqlQuery<Invoice>(\"SELECT * FROM Invoices WHERE Customer = '\" + customer + \"'\").ToList();",
|
|
707
|
+
"why": "User-controlled POST value concatenated into query",
|
|
708
|
+
"line": 28
|
|
709
|
+
}
|
|
710
|
+
],
|
|
711
|
+
"severity": "critical",
|
|
712
|
+
"confidence": "high",
|
|
713
|
+
"cwe": [
|
|
714
|
+
"CWE-89"
|
|
715
|
+
],
|
|
716
|
+
"recommendation": "Use parameterized queries",
|
|
717
|
+
"status": "confirmed",
|
|
718
|
+
"verification": {
|
|
719
|
+
"verdict": "confirmed",
|
|
720
|
+
"reason_code": "traced",
|
|
721
|
+
"checked": [
|
|
722
|
+
"dotnet-legacy/Web/Controllers/InvoiceController.cs: lines 25-28 (Search action)",
|
|
723
|
+
"dotnet-legacy/Web/Controllers/InvoiceController.cs: line 28 (string concatenation)"
|
|
724
|
+
],
|
|
725
|
+
"control_found": null,
|
|
726
|
+
"notes": "The `customer` parameter is concatenated directly into the SQL string. No parameter binding, casting, or role/ownership check is visible in the code_context.",
|
|
727
|
+
"suggested_subtype": null,
|
|
728
|
+
"suggested_cwe": null
|
|
729
|
+
},
|
|
730
|
+
"fingerprint": "kfp1:81106c3dfe7181ee5aad08bbd8e6c94143e8ebb6bf477a18828ca399339d1271",
|
|
731
|
+
"baseline_state": "new"
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
"finding_id": "INJ-I-0009",
|
|
735
|
+
"category": "sql_injection",
|
|
736
|
+
"subtype": "string_concatenation",
|
|
737
|
+
"title": "SQL Injection in dotnet-legacy/Web/Orders/EditOrder.aspx.vb:7",
|
|
738
|
+
"candidate_id": "I-0009",
|
|
739
|
+
"location": {
|
|
740
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
741
|
+
"start_line": 7
|
|
742
|
+
},
|
|
743
|
+
"evidence": [
|
|
744
|
+
{
|
|
745
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
746
|
+
"start_line": 7,
|
|
747
|
+
"code": "Dim sql As String = \"UPDATE Orders SET Note = '\" & txtNote.Text & \"'\"",
|
|
748
|
+
"why": "txtNote.Text concatenated into SQL without parameterization",
|
|
749
|
+
"line": 7
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
753
|
+
"start_line": 8,
|
|
754
|
+
"code": "sql &= \" WHERE OrderId = \" & hfOrderId.Value",
|
|
755
|
+
"why": "hfOrderId.Value concatenated without sanitization",
|
|
756
|
+
"line": 8
|
|
757
|
+
}
|
|
758
|
+
],
|
|
759
|
+
"severity": "critical",
|
|
760
|
+
"confidence": "high",
|
|
761
|
+
"cwe": [
|
|
762
|
+
"CWE-89"
|
|
763
|
+
],
|
|
764
|
+
"recommendation": "Use parameterized SqlCommand",
|
|
765
|
+
"status": "confirmed",
|
|
766
|
+
"verification": {
|
|
767
|
+
"verdict": "confirmed",
|
|
768
|
+
"reason_code": "traced",
|
|
769
|
+
"checked": [
|
|
770
|
+
"dotnet-legacy/Web/Orders/EditOrder.aspx.vb line 7-8 (string concatenation)"
|
|
771
|
+
],
|
|
772
|
+
"control_found": null,
|
|
773
|
+
"notes": "No parameterization or ownership check is visible in the code context.",
|
|
774
|
+
"suggested_subtype": null,
|
|
775
|
+
"suggested_cwe": null
|
|
776
|
+
},
|
|
777
|
+
"fingerprint": "kfp1:999e755f32c1edc6b46f7497ebdfd065d8afcc3518cab3211f45fc11a7342afd",
|
|
778
|
+
"baseline_state": "new"
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
"finding_id": "INJ-I-0010",
|
|
782
|
+
"category": "sql_injection",
|
|
783
|
+
"subtype": "string_concatenation",
|
|
784
|
+
"title": "SQL Injection in dotnet-legacy/Web/Orders/EditOrder.aspx.vb:8",
|
|
785
|
+
"candidate_id": "I-0010",
|
|
786
|
+
"location": {
|
|
787
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
788
|
+
"start_line": 8
|
|
789
|
+
},
|
|
790
|
+
"evidence": [
|
|
791
|
+
{
|
|
792
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
793
|
+
"start_line": 8,
|
|
794
|
+
"code": "sql &= \" WHERE OrderId = \" & hfOrderId.Value",
|
|
795
|
+
"why": "hfOrderId.Value concatenated without sanitization",
|
|
796
|
+
"line": 8
|
|
797
|
+
}
|
|
798
|
+
],
|
|
799
|
+
"severity": "critical",
|
|
800
|
+
"confidence": "high",
|
|
801
|
+
"cwe": [
|
|
802
|
+
"CWE-89"
|
|
803
|
+
],
|
|
804
|
+
"recommendation": "Use parameterized SqlCommand",
|
|
805
|
+
"status": "confirmed",
|
|
806
|
+
"verification": {
|
|
807
|
+
"verdict": "confirmed",
|
|
808
|
+
"reason_code": "traced",
|
|
809
|
+
"checked": [
|
|
810
|
+
"dotnet-legacy/Web/Orders/EditOrder.aspx.vb line 8 (string concatenation)"
|
|
811
|
+
],
|
|
812
|
+
"control_found": null,
|
|
813
|
+
"notes": "Same as INJ-I-0009; the query is built via string concatenation without safeguards.",
|
|
814
|
+
"suggested_subtype": null,
|
|
815
|
+
"suggested_cwe": null
|
|
816
|
+
},
|
|
817
|
+
"fingerprint": "kfp1:323eb8697c45d7b7466292d80a0763dd2310608e0975d837273bde14e3458f59",
|
|
818
|
+
"baseline_state": "new"
|
|
819
|
+
},
|
|
820
|
+
{
|
|
821
|
+
"finding_id": "INJ-I-0011",
|
|
822
|
+
"category": "sql_injection",
|
|
823
|
+
"subtype": "string_concatenation",
|
|
824
|
+
"title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:13",
|
|
825
|
+
"candidate_id": "I-0011",
|
|
826
|
+
"location": {
|
|
827
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
828
|
+
"start_line": 13
|
|
829
|
+
},
|
|
830
|
+
"evidence": [
|
|
831
|
+
{
|
|
832
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
833
|
+
"start_line": 13,
|
|
834
|
+
"code": "var cmd = new SqlCommand(\"SELECT * FROM Orders WHERE OrderId = \" + id, conn);",
|
|
835
|
+
"why": "id from Request.QueryString is concatenated without parameterization",
|
|
836
|
+
"line": 13
|
|
837
|
+
},
|
|
838
|
+
{
|
|
839
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
840
|
+
"start_line": 19,
|
|
841
|
+
"code": "string sql2 = string.Format(\"SELECT * FROM Logs WHERE Ref = '{0}'\", Request[\"ref\"]);",
|
|
842
|
+
"why": "Request[\"ref\"] concatenated into SQL string",
|
|
843
|
+
"line": 19
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
847
|
+
"start_line": 20,
|
|
848
|
+
"code": "string sql3 = $\"DELETE FROM Carts WHERE CartId = {Request.Form[\"cart\"]}\";",
|
|
849
|
+
"why": "Request.Form[\"cart\"] concatenated into SQL string",
|
|
850
|
+
"line": 20
|
|
851
|
+
}
|
|
852
|
+
],
|
|
853
|
+
"severity": "critical",
|
|
854
|
+
"confidence": "high",
|
|
855
|
+
"cwe": [
|
|
856
|
+
"CWE-89"
|
|
857
|
+
],
|
|
858
|
+
"recommendation": "Use parameterized SqlCommand for all queries",
|
|
859
|
+
"status": "confirmed",
|
|
860
|
+
"verification": {
|
|
861
|
+
"verdict": "confirmed",
|
|
862
|
+
"reason_code": "traced",
|
|
863
|
+
"checked": [
|
|
864
|
+
"dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:13-22"
|
|
865
|
+
],
|
|
866
|
+
"control_found": null,
|
|
867
|
+
"notes": "The vulnerable query at line 13 concatenates the request parameter directly into the SQL string. No ownership check, role guard, integer cast, or parameter binding is present in the visible code. The subsequent safe query is never used.",
|
|
868
|
+
"suggested_subtype": null,
|
|
869
|
+
"suggested_cwe": null
|
|
870
|
+
},
|
|
871
|
+
"fingerprint": "kfp1:c9aa426f72d032a9b0729b0905c9c25a6fb8844a92a91c45d72d3e26170bbae5",
|
|
872
|
+
"baseline_state": "new"
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
"finding_id": "INJ-I-0012",
|
|
876
|
+
"category": "sql_injection",
|
|
877
|
+
"subtype": "string_concatenation",
|
|
878
|
+
"title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:19",
|
|
879
|
+
"candidate_id": "I-0012",
|
|
880
|
+
"location": {
|
|
881
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
882
|
+
"start_line": 19
|
|
883
|
+
},
|
|
884
|
+
"evidence": [
|
|
885
|
+
{
|
|
886
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
887
|
+
"start_line": 19,
|
|
888
|
+
"code": "string sql2 = string.Format(\"SELECT * FROM Logs WHERE Ref = '{0}'\", Request[\"ref\"]);",
|
|
889
|
+
"why": "Request[\"ref\"] concatenated into SQL string",
|
|
890
|
+
"line": 19
|
|
891
|
+
}
|
|
892
|
+
],
|
|
893
|
+
"severity": "critical",
|
|
894
|
+
"confidence": "high",
|
|
895
|
+
"cwe": [
|
|
896
|
+
"CWE-89"
|
|
897
|
+
],
|
|
898
|
+
"recommendation": "Use parameterized SqlCommand",
|
|
899
|
+
"status": "confirmed",
|
|
900
|
+
"verification": {
|
|
901
|
+
"verdict": "confirmed",
|
|
902
|
+
"reason_code": "traced",
|
|
903
|
+
"checked": [
|
|
904
|
+
"dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:19-21"
|
|
905
|
+
],
|
|
906
|
+
"control_found": null,
|
|
907
|
+
"notes": "The query built with string.Format at line 19 directly injects the request value. No parameterization or ownership guard is visible.",
|
|
908
|
+
"suggested_subtype": null,
|
|
909
|
+
"suggested_cwe": null
|
|
910
|
+
},
|
|
911
|
+
"fingerprint": "kfp1:c0adff113329292a51bb7d2f2aa03dd242c6d767cee060a789ff750f3ab9b946",
|
|
912
|
+
"baseline_state": "new"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
"finding_id": "INJ-I-0013",
|
|
916
|
+
"category": "sql_injection",
|
|
917
|
+
"subtype": "string_concatenation",
|
|
918
|
+
"title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:20",
|
|
919
|
+
"candidate_id": "I-0013",
|
|
920
|
+
"location": {
|
|
921
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
922
|
+
"start_line": 20
|
|
923
|
+
},
|
|
924
|
+
"evidence": [
|
|
925
|
+
{
|
|
926
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
927
|
+
"start_line": 20,
|
|
928
|
+
"code": "string sql3 = $\"DELETE FROM Carts WHERE CartId = {Request.Form[\"cart\"]}\";",
|
|
929
|
+
"why": "Request.Form[\"cart\"] concatenated into SQL string",
|
|
930
|
+
"line": 20
|
|
931
|
+
}
|
|
932
|
+
],
|
|
933
|
+
"severity": "critical",
|
|
934
|
+
"confidence": "high",
|
|
935
|
+
"cwe": [
|
|
936
|
+
"CWE-89"
|
|
937
|
+
],
|
|
938
|
+
"recommendation": "Use parameterized SqlCommand",
|
|
939
|
+
"status": "confirmed",
|
|
940
|
+
"verification": {
|
|
941
|
+
"verdict": "confirmed",
|
|
942
|
+
"reason_code": "traced",
|
|
943
|
+
"checked": [
|
|
944
|
+
"dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:20-22"
|
|
945
|
+
],
|
|
946
|
+
"control_found": null,
|
|
947
|
+
"notes": "The DELETE statement at line 20 concatenates form data. No parameter binding or ownership check is present.",
|
|
948
|
+
"suggested_subtype": null,
|
|
949
|
+
"suggested_cwe": null
|
|
950
|
+
},
|
|
951
|
+
"fingerprint": "kfp1:4dbfab5201fa4fb196296b8ea0e4be14bb1ae1e6d3136309f24af78eb9977441",
|
|
952
|
+
"baseline_state": "new"
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
"finding_id": "INJ-I-0014",
|
|
956
|
+
"category": "sql_injection",
|
|
957
|
+
"subtype": "string_concatenation",
|
|
958
|
+
"title": "SQL Injection in java-legacy/WebContent/order/detail.jsp:5",
|
|
959
|
+
"candidate_id": "I-0014",
|
|
960
|
+
"location": {
|
|
961
|
+
"file": "java-legacy/WebContent/order/detail.jsp",
|
|
962
|
+
"start_line": 5
|
|
963
|
+
},
|
|
964
|
+
"evidence": [
|
|
965
|
+
{
|
|
966
|
+
"file": "java-legacy/WebContent/order/detail.jsp",
|
|
967
|
+
"start_line": 5,
|
|
968
|
+
"code": "ResultSet rs = c.createStatement().executeQuery(\"SELECT * FROM orders WHERE order_no = '\" + no + \"'\");",
|
|
969
|
+
"why": "no from request.getParameter is concatenated without sanitization",
|
|
970
|
+
"line": 5
|
|
971
|
+
}
|
|
972
|
+
],
|
|
973
|
+
"severity": "critical",
|
|
974
|
+
"confidence": "high",
|
|
975
|
+
"cwe": [
|
|
976
|
+
"CWE-89"
|
|
977
|
+
],
|
|
978
|
+
"recommendation": "Use PreparedStatement with parameters",
|
|
979
|
+
"status": "confirmed",
|
|
980
|
+
"verification": {
|
|
981
|
+
"verdict": "confirmed",
|
|
982
|
+
"reason_code": "traced",
|
|
983
|
+
"checked": [
|
|
984
|
+
"java-legacy/WebContent/order/detail.jsp:5-6"
|
|
985
|
+
],
|
|
986
|
+
"control_found": null,
|
|
987
|
+
"notes": "The query at line 5 concatenates a request parameter without any sanitization or parameterization. No ownership guard is shown.",
|
|
988
|
+
"suggested_subtype": null,
|
|
989
|
+
"suggested_cwe": null
|
|
990
|
+
},
|
|
991
|
+
"fingerprint": "kfp1:b8e7acb1ca7119156e96cf2bd42356b53bb6107a0a904b492534714730ac45f8",
|
|
992
|
+
"baseline_state": "new"
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
"finding_id": "INJ-I-0015",
|
|
996
|
+
"category": "sql_injection",
|
|
997
|
+
"subtype": "dynamic_identifier",
|
|
998
|
+
"title": "SQL Injection in java-legacy/src/com/acme/mapper/OrderMapper.xml:9",
|
|
999
|
+
"candidate_id": "I-0015",
|
|
1000
|
+
"location": {
|
|
1001
|
+
"file": "java-legacy/src/com/acme/mapper/OrderMapper.xml",
|
|
1002
|
+
"start_line": 9
|
|
1003
|
+
},
|
|
1004
|
+
"evidence": [
|
|
1005
|
+
{
|
|
1006
|
+
"file": "java-legacy/src/com/acme/mapper/OrderMapper.xml",
|
|
1007
|
+
"start_line": 9,
|
|
1008
|
+
"code": "ORDER BY ${orderBy}",
|
|
1009
|
+
"why": "Raw string substitution of an identifier",
|
|
1010
|
+
"line": 9
|
|
1011
|
+
}
|
|
1012
|
+
],
|
|
1013
|
+
"severity": "critical",
|
|
1014
|
+
"confidence": "high",
|
|
1015
|
+
"cwe": [
|
|
1016
|
+
"CWE-89"
|
|
1017
|
+
],
|
|
1018
|
+
"recommendation": "Validate ORDER BY value against an allow‑list or use a parameterized placeholder",
|
|
1019
|
+
"status": "confirmed",
|
|
1020
|
+
"verification": {
|
|
1021
|
+
"verdict": "confirmed",
|
|
1022
|
+
"reason_code": "traced",
|
|
1023
|
+
"checked": [
|
|
1024
|
+
"java-legacy/src/com/acme/mapper/OrderMapper.xml: lines 7-9 (list select)",
|
|
1025
|
+
"java-legacy/src/com/acme/mapper/OrderMapper.xml: line 9 (ORDER BY ${orderBy})"
|
|
1026
|
+
],
|
|
1027
|
+
"control_found": null,
|
|
1028
|
+
"notes": "The `${orderBy}` placeholder is substituted directly with the caller’s value. No allow‑list, enum mapping, or parameter binding is present in the code_context.",
|
|
1029
|
+
"suggested_subtype": null,
|
|
1030
|
+
"suggested_cwe": null
|
|
1031
|
+
},
|
|
1032
|
+
"fingerprint": "kfp1:a0212ab67bd8e95a9fa71520fd15ba101852184637a1a60ec1bb91525308964f",
|
|
1033
|
+
"baseline_state": "new"
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
"finding_id": "INJ-I-0016",
|
|
1037
|
+
"category": "sql_injection",
|
|
1038
|
+
"subtype": "string_concatenation",
|
|
1039
|
+
"title": "SQL Injection in java-legacy/src/com/acme/struts/EditUserAction.java:13",
|
|
1040
|
+
"candidate_id": "I-0016",
|
|
1041
|
+
"location": {
|
|
1042
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1043
|
+
"start_line": 13
|
|
1044
|
+
},
|
|
1045
|
+
"evidence": [
|
|
1046
|
+
{
|
|
1047
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1048
|
+
"start_line": 13,
|
|
1049
|
+
"code": "PreparedStatement ps = conn.prepareStatement(\"UPDATE users SET email = '\" + email + \"' WHERE id = \" + userId);",
|
|
1050
|
+
"why": "email and userId concatenated into SQL string without parameters",
|
|
1051
|
+
"line": 13
|
|
1052
|
+
}
|
|
1053
|
+
],
|
|
1054
|
+
"severity": "critical",
|
|
1055
|
+
"confidence": "high",
|
|
1056
|
+
"cwe": [
|
|
1057
|
+
"CWE-89"
|
|
1058
|
+
],
|
|
1059
|
+
"recommendation": "Use PreparedStatement with parameters",
|
|
1060
|
+
"status": "confirmed",
|
|
1061
|
+
"verification": {
|
|
1062
|
+
"verdict": "confirmed",
|
|
1063
|
+
"reason_code": "traced",
|
|
1064
|
+
"checked": [
|
|
1065
|
+
"java-legacy/src/com/acme/struts/EditUserAction.java:13-15"
|
|
1066
|
+
],
|
|
1067
|
+
"control_found": null,
|
|
1068
|
+
"notes": "The UPDATE statement at line 13 concatenates user-supplied values. No parameter binding or ownership check is visible.",
|
|
1069
|
+
"suggested_subtype": null,
|
|
1070
|
+
"suggested_cwe": null
|
|
1071
|
+
},
|
|
1072
|
+
"fingerprint": "kfp1:2976fb21c23c927d1de0f3af7dc883d9b66a1d051ec67bb9ec1b44396f6479fc",
|
|
1073
|
+
"baseline_state": "new"
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
"finding_id": "INJ-I-0017",
|
|
1077
|
+
"category": "sql_injection",
|
|
1078
|
+
"subtype": "string_concatenation",
|
|
1079
|
+
"title": "SQL Injection in java-legacy/src/com/acme/web/InvoiceController.java:29",
|
|
1080
|
+
"candidate_id": "I-0017",
|
|
1081
|
+
"location": {
|
|
1082
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
1083
|
+
"start_line": 29
|
|
1084
|
+
},
|
|
1085
|
+
"evidence": [
|
|
1086
|
+
{
|
|
1087
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
1088
|
+
"start_line": 29,
|
|
1089
|
+
"code": "model.addAttribute(\"list\", session.createQuery(\"from Invoice i where i.customer = '\" + customer + \"'\").list());",
|
|
1090
|
+
"why": "customer from request parameter concatenated into HQL string",
|
|
1091
|
+
"line": 29
|
|
1092
|
+
}
|
|
1093
|
+
],
|
|
1094
|
+
"severity": "critical",
|
|
1095
|
+
"confidence": "high",
|
|
1096
|
+
"cwe": [
|
|
1097
|
+
"CWE-89"
|
|
1098
|
+
],
|
|
1099
|
+
"recommendation": "Use parameterized HQL/JPQL",
|
|
1100
|
+
"status": "confirmed",
|
|
1101
|
+
"verification": {
|
|
1102
|
+
"verdict": "confirmed",
|
|
1103
|
+
"reason_code": "traced",
|
|
1104
|
+
"checked": [
|
|
1105
|
+
"java-legacy/src/com/acme/web/InvoiceController.java:27-29"
|
|
1106
|
+
],
|
|
1107
|
+
"control_found": null,
|
|
1108
|
+
"notes": "The HQL query is built by string concatenation with the request parameter 'customer'. No parameter binding, no integer cast, no allow‑list, and no ownership check is visible in the controller or DAO. The query is executed directly, so the vulnerability is confirmed.",
|
|
1109
|
+
"suggested_subtype": null,
|
|
1110
|
+
"suggested_cwe": null
|
|
1111
|
+
},
|
|
1112
|
+
"fingerprint": "kfp1:7796f734194bfe71dc7268f597efd6338a4e967a788e0220edb61b8e1c198b16",
|
|
1113
|
+
"baseline_state": "new"
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
"finding_id": "INJ-I-0018",
|
|
1117
|
+
"category": "sql_injection",
|
|
1118
|
+
"subtype": "string_concatenation",
|
|
1119
|
+
"title": "SQL Injection in java-legacy/src/com/acme/web/OrderServlet.java:15",
|
|
1120
|
+
"candidate_id": "I-0018",
|
|
1121
|
+
"location": {
|
|
1122
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1123
|
+
"start_line": 15
|
|
1124
|
+
},
|
|
1125
|
+
"evidence": [
|
|
1126
|
+
{
|
|
1127
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1128
|
+
"start_line": 11,
|
|
1129
|
+
"code": "String id = request.getParameter(\"orderId\");",
|
|
1130
|
+
"why": "User-controlled request parameter",
|
|
1131
|
+
"line": 11
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1135
|
+
"start_line": 15,
|
|
1136
|
+
"code": "ResultSet rs = stmt.executeQuery(\"SELECT * FROM orders WHERE id = '\" + id + \"'\");",
|
|
1137
|
+
"why": "Unsanitized string concatenation into query",
|
|
1138
|
+
"line": 15
|
|
1139
|
+
}
|
|
1140
|
+
],
|
|
1141
|
+
"severity": "critical",
|
|
1142
|
+
"confidence": "high",
|
|
1143
|
+
"cwe": [
|
|
1144
|
+
"CWE-89"
|
|
1145
|
+
],
|
|
1146
|
+
"recommendation": "Use PreparedStatement with bound parameters",
|
|
1147
|
+
"status": "confirmed",
|
|
1148
|
+
"verification": {
|
|
1149
|
+
"verdict": "confirmed",
|
|
1150
|
+
"reason_code": "traced",
|
|
1151
|
+
"checked": [
|
|
1152
|
+
"java-legacy/src/com/acme/web/OrderServlet.java: lines 11-15 (doGet method)",
|
|
1153
|
+
"java-legacy/src/com/acme/web/OrderServlet.java: line 15 (string concatenation)"
|
|
1154
|
+
],
|
|
1155
|
+
"control_found": null,
|
|
1156
|
+
"notes": "The `id` request parameter is concatenated into the SQL query without any sanitization, casting, or ownership check. No authentication guard is visible in the code_context.",
|
|
1157
|
+
"suggested_subtype": null,
|
|
1158
|
+
"suggested_cwe": null
|
|
1159
|
+
},
|
|
1160
|
+
"fingerprint": "kfp1:eed713c040fe4b03f16a649b4da2fa326995fd074ad3ba46bbbb4958486b6b8d",
|
|
1161
|
+
"baseline_state": "new"
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
"finding_id": "INJ-I-0019",
|
|
1165
|
+
"category": "sql_injection",
|
|
1166
|
+
"subtype": "string_concatenation",
|
|
1167
|
+
"title": "SQL Injection in java-legacy/src/com/acme/web/OrderServlet.java:17",
|
|
1168
|
+
"candidate_id": "I-0019",
|
|
1169
|
+
"location": {
|
|
1170
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1171
|
+
"start_line": 17
|
|
1172
|
+
},
|
|
1173
|
+
"evidence": [
|
|
1174
|
+
{
|
|
1175
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1176
|
+
"start_line": 11,
|
|
1177
|
+
"code": "String id = request.getParameter(\"orderId\");",
|
|
1178
|
+
"why": "User-controlled request parameter",
|
|
1179
|
+
"line": 11
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
1183
|
+
"start_line": 17,
|
|
1184
|
+
"code": "sb.append(\" AND order_id = \").append(id);",
|
|
1185
|
+
"why": "Unsanitized concatenation into query string",
|
|
1186
|
+
"line": 17
|
|
1187
|
+
}
|
|
1188
|
+
],
|
|
1189
|
+
"severity": "critical",
|
|
1190
|
+
"confidence": "high",
|
|
1191
|
+
"cwe": [
|
|
1192
|
+
"CWE-89"
|
|
1193
|
+
],
|
|
1194
|
+
"recommendation": "Use PreparedStatement or bind parameters",
|
|
1195
|
+
"status": "confirmed",
|
|
1196
|
+
"verification": {
|
|
1197
|
+
"verdict": "confirmed",
|
|
1198
|
+
"reason_code": "traced",
|
|
1199
|
+
"checked": [
|
|
1200
|
+
"java-legacy/src/com/acme/web/OrderServlet.java: lines 16-18 (items query)",
|
|
1201
|
+
"java-legacy/src/com/acme/web/OrderServlet.java: line 17 (string concatenation)"
|
|
1202
|
+
],
|
|
1203
|
+
"control_found": null,
|
|
1204
|
+
"notes": "The `id` value is appended directly to the SQL string for the items query. No parameter binding, casting, or ownership check is present in the code_context.",
|
|
1205
|
+
"suggested_subtype": null,
|
|
1206
|
+
"suggested_cwe": null
|
|
1207
|
+
},
|
|
1208
|
+
"fingerprint": "kfp1:22951bde3fee457a15c0237a8c8b4af2558c7f1e2ce5d391ee825918057e7480",
|
|
1209
|
+
"baseline_state": "new"
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
"finding_id": "INJ-I-0020",
|
|
1213
|
+
"category": "sql_injection",
|
|
1214
|
+
"subtype": "string_concatenation",
|
|
1215
|
+
"title": "SQL Injection in node-express/routes/orders.js:17",
|
|
1216
|
+
"candidate_id": "I-0020",
|
|
1217
|
+
"location": {
|
|
1218
|
+
"file": "node-express/routes/orders.js",
|
|
1219
|
+
"start_line": 17
|
|
1220
|
+
},
|
|
1221
|
+
"evidence": [
|
|
1222
|
+
{
|
|
1223
|
+
"file": "node-express/routes/orders.js",
|
|
1224
|
+
"start_line": 17,
|
|
1225
|
+
"code": "db.query(\"SELECT * FROM reports WHERE month = '\" + req.query.month + \"'\", function (e, rows) { res.json(rows); });",
|
|
1226
|
+
"why": "req.query.month concatenated into SQL string",
|
|
1227
|
+
"line": 17
|
|
1228
|
+
},
|
|
1229
|
+
{
|
|
1230
|
+
"file": "node-express/routes/orders.js",
|
|
1231
|
+
"start_line": 29,
|
|
1232
|
+
"code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
|
|
1233
|
+
"why": "req.query.shop concatenated into SQL string",
|
|
1234
|
+
"line": 29
|
|
1235
|
+
}
|
|
1236
|
+
],
|
|
1237
|
+
"severity": "critical",
|
|
1238
|
+
"confidence": "high",
|
|
1239
|
+
"cwe": [
|
|
1240
|
+
"CWE-89"
|
|
1241
|
+
],
|
|
1242
|
+
"recommendation": "Use parameterized queries",
|
|
1243
|
+
"status": "confirmed",
|
|
1244
|
+
"verification": {
|
|
1245
|
+
"verdict": "confirmed",
|
|
1246
|
+
"reason_code": "traced",
|
|
1247
|
+
"checked": [
|
|
1248
|
+
"node-express/routes/orders.js:16-18"
|
|
1249
|
+
],
|
|
1250
|
+
"control_found": null,
|
|
1251
|
+
"notes": "The route '/reports' uses ensureLoggedIn, but the SQL query selects all reports by month without any user or ownership filter. The query string is concatenated with req.query.month, and no parameter binding or cast is present. The vulnerability is confirmed.",
|
|
1252
|
+
"suggested_subtype": null,
|
|
1253
|
+
"suggested_cwe": null
|
|
1254
|
+
},
|
|
1255
|
+
"fingerprint": "kfp1:fc0f31011ca4510d026845f7fb0dcd77812ef24f6ea5329ad24fbc08a15b58ff",
|
|
1256
|
+
"baseline_state": "new"
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
"finding_id": "INJ-I-0021",
|
|
1260
|
+
"category": "sql_injection",
|
|
1261
|
+
"subtype": "string_concatenation",
|
|
1262
|
+
"title": "SQL Injection in node-express/routes/orders.js:29",
|
|
1263
|
+
"candidate_id": "I-0021",
|
|
1264
|
+
"location": {
|
|
1265
|
+
"file": "node-express/routes/orders.js",
|
|
1266
|
+
"start_line": 29
|
|
1267
|
+
},
|
|
1268
|
+
"evidence": [
|
|
1269
|
+
{
|
|
1270
|
+
"file": "node-express/routes/orders.js",
|
|
1271
|
+
"start_line": 29,
|
|
1272
|
+
"code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
|
|
1273
|
+
"why": "req.query.shop concatenated into SQL string",
|
|
1274
|
+
"line": 29
|
|
1275
|
+
}
|
|
1276
|
+
],
|
|
1277
|
+
"severity": "critical",
|
|
1278
|
+
"confidence": "high",
|
|
1279
|
+
"cwe": [
|
|
1280
|
+
"CWE-89"
|
|
1281
|
+
],
|
|
1282
|
+
"recommendation": "Use parameterized queries",
|
|
1283
|
+
"status": "confirmed",
|
|
1284
|
+
"verification": {
|
|
1285
|
+
"verdict": "confirmed",
|
|
1286
|
+
"reason_code": "traced",
|
|
1287
|
+
"checked": [
|
|
1288
|
+
"node-express/routes/orders.js:28-30"
|
|
1289
|
+
],
|
|
1290
|
+
"control_found": null,
|
|
1291
|
+
"notes": "The '/stats' route is not protected by ensureLoggedIn. The SQL query concatenates req.query.shop directly into the statement. No cast, allow‑list, or ownership check is visible. The vulnerability is confirmed.",
|
|
1292
|
+
"suggested_subtype": null,
|
|
1293
|
+
"suggested_cwe": null
|
|
1294
|
+
},
|
|
1295
|
+
"fingerprint": "kfp1:5fef20fe2b97718add08c2ce704c057931ba2f5b5f9277493213205e35d8fde8",
|
|
1296
|
+
"baseline_state": "new"
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
"finding_id": "INJ-I-0024",
|
|
1300
|
+
"category": "sql_injection",
|
|
1301
|
+
"subtype": "string_concatenation",
|
|
1302
|
+
"title": "SQL Injection in perl-cgi/cgi-bin/order.cgi:13",
|
|
1303
|
+
"candidate_id": "I-0024",
|
|
1304
|
+
"location": {
|
|
1305
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1306
|
+
"start_line": 13
|
|
1307
|
+
},
|
|
1308
|
+
"evidence": [
|
|
1309
|
+
{
|
|
1310
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1311
|
+
"start_line": 13,
|
|
1312
|
+
"code": "my $sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");",
|
|
1313
|
+
"why": "id from CGI param concatenated into SQL string",
|
|
1314
|
+
"line": 13
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1318
|
+
"start_line": 19,
|
|
1319
|
+
"code": "$dbh->do(\"DELETE FROM carts WHERE cart_id = \" . $q->param('cart'));",
|
|
1320
|
+
"why": "cart param concatenated into SQL string",
|
|
1321
|
+
"line": 19
|
|
1322
|
+
}
|
|
1323
|
+
],
|
|
1324
|
+
"severity": "critical",
|
|
1325
|
+
"confidence": "high",
|
|
1326
|
+
"cwe": [
|
|
1327
|
+
"CWE-89"
|
|
1328
|
+
],
|
|
1329
|
+
"recommendation": "Use placeholders in prepare statements",
|
|
1330
|
+
"status": "confirmed",
|
|
1331
|
+
"verification": {
|
|
1332
|
+
"verdict": "confirmed",
|
|
1333
|
+
"reason_code": "traced",
|
|
1334
|
+
"checked": [
|
|
1335
|
+
"perl-cgi/cgi-bin/order.cgi:13-14",
|
|
1336
|
+
"perl-cgi/cgi-bin/order.cgi:16-17"
|
|
1337
|
+
],
|
|
1338
|
+
"control_found": null,
|
|
1339
|
+
"notes": "The query concatenates the unsanitized CGI parameter $id directly into the SQL string. No integer cast, allow‑list, or ownership check is present in the visible code.",
|
|
1340
|
+
"suggested_subtype": null,
|
|
1341
|
+
"suggested_cwe": null
|
|
1342
|
+
},
|
|
1343
|
+
"fingerprint": "kfp1:0594761f603533b7391a9b7a8464e6865b71c1b61b71fdcd10991d861f51b5fb",
|
|
1344
|
+
"baseline_state": "new"
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
"finding_id": "INJ-I-0025",
|
|
1348
|
+
"category": "sql_injection",
|
|
1349
|
+
"subtype": "string_concatenation",
|
|
1350
|
+
"title": "SQL Injection in perl-cgi/cgi-bin/order.cgi:19",
|
|
1351
|
+
"candidate_id": "I-0025",
|
|
1352
|
+
"location": {
|
|
1353
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1354
|
+
"start_line": 19
|
|
1355
|
+
},
|
|
1356
|
+
"evidence": [
|
|
1357
|
+
{
|
|
1358
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1359
|
+
"start_line": 19,
|
|
1360
|
+
"code": "$dbh->do(\"DELETE FROM carts WHERE cart_id = \" . $q->param('cart'));",
|
|
1361
|
+
"why": "cart param concatenated into SQL string",
|
|
1362
|
+
"line": 19
|
|
1363
|
+
}
|
|
1364
|
+
],
|
|
1365
|
+
"severity": "critical",
|
|
1366
|
+
"confidence": "high",
|
|
1367
|
+
"cwe": [
|
|
1368
|
+
"CWE-89"
|
|
1369
|
+
],
|
|
1370
|
+
"recommendation": "Use placeholders in prepare statements",
|
|
1371
|
+
"status": "confirmed",
|
|
1372
|
+
"verification": {
|
|
1373
|
+
"verdict": "confirmed",
|
|
1374
|
+
"reason_code": "traced",
|
|
1375
|
+
"checked": [
|
|
1376
|
+
"perl-cgi/cgi-bin/order.cgi:19"
|
|
1377
|
+
],
|
|
1378
|
+
"control_found": null,
|
|
1379
|
+
"notes": "The DELETE statement concatenates the unsanitized CGI parameter cart into the SQL string. No sanitization or parameter binding is used.",
|
|
1380
|
+
"suggested_subtype": null,
|
|
1381
|
+
"suggested_cwe": null
|
|
1382
|
+
},
|
|
1383
|
+
"fingerprint": "kfp1:c7206e5510c18d43418b9ed9a4d20047783ea5263cfdc395a138b735b613debc",
|
|
1384
|
+
"baseline_state": "new"
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
"finding_id": "INJ-I-0026",
|
|
1388
|
+
"category": "sql_injection",
|
|
1389
|
+
"subtype": "string_concatenation",
|
|
1390
|
+
"title": "SQL Injection in php-codeigniter/application/controllers/Invoice.php:10",
|
|
1391
|
+
"candidate_id": "I-0026",
|
|
1392
|
+
"location": {
|
|
1393
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
1394
|
+
"start_line": 10
|
|
1395
|
+
},
|
|
1396
|
+
"evidence": [
|
|
1397
|
+
{
|
|
1398
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
1399
|
+
"start_line": 10,
|
|
1400
|
+
"code": "$q = $this->db->query(\"SELECT * FROM invoices WHERE id = $id\");",
|
|
1401
|
+
"why": "User-controlled value concatenated without quotes or binding",
|
|
1402
|
+
"line": 10
|
|
1403
|
+
}
|
|
1404
|
+
],
|
|
1405
|
+
"severity": "critical",
|
|
1406
|
+
"confidence": "high",
|
|
1407
|
+
"cwe": [
|
|
1408
|
+
"CWE-89"
|
|
1409
|
+
],
|
|
1410
|
+
"recommendation": "Use query binding",
|
|
1411
|
+
"status": "confirmed",
|
|
1412
|
+
"verification": {
|
|
1413
|
+
"verdict": "confirmed",
|
|
1414
|
+
"reason_code": "traced",
|
|
1415
|
+
"checked": [
|
|
1416
|
+
"php-codeigniter/application/controllers/Invoice.php:10"
|
|
1417
|
+
],
|
|
1418
|
+
"control_found": null,
|
|
1419
|
+
"notes": "The query concatenates the user‑controlled $id directly into the SQL string without quotes, binding, casting, or an allow‑list. No ownership or sanitization control is visible.",
|
|
1420
|
+
"suggested_subtype": null,
|
|
1421
|
+
"suggested_cwe": null
|
|
1422
|
+
},
|
|
1423
|
+
"fingerprint": "kfp1:cab7179a42b52f77a862191152d4b0ebc8511c6c77b956503f7c53525c9390b0",
|
|
1424
|
+
"baseline_state": "new"
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
"finding_id": "INJ-I-0027",
|
|
1428
|
+
"category": "sql_injection",
|
|
1429
|
+
"subtype": "string_concatenation",
|
|
1430
|
+
"title": "SQL Injection in php-plain/admin.php:12",
|
|
1431
|
+
"candidate_id": "I-0027",
|
|
1432
|
+
"location": {
|
|
1433
|
+
"file": "php-plain/admin.php",
|
|
1434
|
+
"start_line": 12
|
|
1435
|
+
},
|
|
1436
|
+
"evidence": [
|
|
1437
|
+
{
|
|
1438
|
+
"file": "php-plain/admin.php",
|
|
1439
|
+
"start_line": 12,
|
|
1440
|
+
"code": "mysql_query(\"DELETE FROM users WHERE id = $id\");",
|
|
1441
|
+
"why": "id from POST concatenated without sanitization",
|
|
1442
|
+
"line": 12
|
|
1443
|
+
}
|
|
1444
|
+
],
|
|
1445
|
+
"severity": "critical",
|
|
1446
|
+
"confidence": "high",
|
|
1447
|
+
"cwe": [
|
|
1448
|
+
"CWE-89"
|
|
1449
|
+
],
|
|
1450
|
+
"recommendation": "Use prepared statements",
|
|
1451
|
+
"status": "confirmed",
|
|
1452
|
+
"verification": {
|
|
1453
|
+
"verdict": "confirmed",
|
|
1454
|
+
"reason_code": "traced",
|
|
1455
|
+
"checked": [
|
|
1456
|
+
"php-plain/admin.php:11-13",
|
|
1457
|
+
"php-plain/inc/auth.php:1-7"
|
|
1458
|
+
],
|
|
1459
|
+
"control_found": null,
|
|
1460
|
+
"notes": "The DELETE query uses the raw POST value $id without casting or sanitization. The included auth file only checks for a logged‑in user, not for an admin role or ownership.",
|
|
1461
|
+
"suggested_subtype": null,
|
|
1462
|
+
"suggested_cwe": null
|
|
1463
|
+
},
|
|
1464
|
+
"fingerprint": "kfp1:59fca8cd0dedd8f70d286a5d3808292d9eddcf084148a63a448b7043b69c7948",
|
|
1465
|
+
"baseline_state": "new"
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
"finding_id": "INJ-I-0029",
|
|
1469
|
+
"category": "sql_injection",
|
|
1470
|
+
"subtype": "operator_injection",
|
|
1471
|
+
"title": "NoSQL Injection in php-plain/mongo_find.php:6",
|
|
1472
|
+
"candidate_id": "I-0029",
|
|
1473
|
+
"location": {
|
|
1474
|
+
"file": "php-plain/mongo_find.php",
|
|
1475
|
+
"start_line": 6
|
|
1476
|
+
},
|
|
1477
|
+
"evidence": [
|
|
1478
|
+
{
|
|
1479
|
+
"file": "php-plain/mongo_find.php",
|
|
1480
|
+
"start_line": 6,
|
|
1481
|
+
"code": "$docs = $coll->find(array('$where' => \"this.name == '\" . $_GET['n'] . \"'\"));",
|
|
1482
|
+
"why": "User input concatenated into $where string, enabling JavaScript injection",
|
|
1483
|
+
"line": 6
|
|
1484
|
+
}
|
|
1485
|
+
],
|
|
1486
|
+
"severity": "critical",
|
|
1487
|
+
"confidence": "high",
|
|
1488
|
+
"cwe": [
|
|
1489
|
+
"CWE-89"
|
|
1490
|
+
],
|
|
1491
|
+
"recommendation": "Avoid $where; use query operators or parameterized filters",
|
|
1492
|
+
"status": "confirmed",
|
|
1493
|
+
"verification": {
|
|
1494
|
+
"verdict": "confirmed",
|
|
1495
|
+
"reason_code": "traced",
|
|
1496
|
+
"checked": [
|
|
1497
|
+
"php-plain/mongo_find.php:6",
|
|
1498
|
+
"php-plain/inc/auth.php:1-7"
|
|
1499
|
+
],
|
|
1500
|
+
"control_found": null,
|
|
1501
|
+
"notes": "The $where clause concatenates user input directly, enabling JavaScript injection. No sanitization or role check is present in the visible code.",
|
|
1502
|
+
"suggested_subtype": null,
|
|
1503
|
+
"suggested_cwe": null
|
|
1504
|
+
},
|
|
1505
|
+
"fingerprint": "kfp1:c00da5eade29da19cd3a2748fe31b7779bdc4fb7084502d0a108f2bd593e87ad",
|
|
1506
|
+
"baseline_state": "new"
|
|
1507
|
+
},
|
|
1508
|
+
{
|
|
1509
|
+
"finding_id": "INJ-I-0031",
|
|
1510
|
+
"category": "sql_injection",
|
|
1511
|
+
"subtype": "string_concatenation",
|
|
1512
|
+
"title": "SQL Injection in php-plain/order_detail.php:6",
|
|
1513
|
+
"candidate_id": "I-0031",
|
|
1514
|
+
"location": {
|
|
1515
|
+
"file": "php-plain/order_detail.php",
|
|
1516
|
+
"start_line": 6
|
|
1517
|
+
},
|
|
1518
|
+
"evidence": [
|
|
1519
|
+
{
|
|
1520
|
+
"file": "php-plain/order_detail.php",
|
|
1521
|
+
"start_line": 5,
|
|
1522
|
+
"code": "$id = $_GET['id'];",
|
|
1523
|
+
"why": "User-controlled GET parameter",
|
|
1524
|
+
"line": 5
|
|
1525
|
+
},
|
|
1526
|
+
{
|
|
1527
|
+
"file": "php-plain/order_detail.php",
|
|
1528
|
+
"start_line": 6,
|
|
1529
|
+
"code": "$res = mysql_query(\"SELECT * FROM orders WHERE id = \" . $id);",
|
|
1530
|
+
"why": "Unsanitized input concatenated into query",
|
|
1531
|
+
"line": 6
|
|
1532
|
+
}
|
|
1533
|
+
],
|
|
1534
|
+
"severity": "critical",
|
|
1535
|
+
"confidence": "high",
|
|
1536
|
+
"cwe": [
|
|
1537
|
+
"CWE-89"
|
|
1538
|
+
],
|
|
1539
|
+
"recommendation": "Use parameterized queries",
|
|
1540
|
+
"status": "confirmed",
|
|
1541
|
+
"verification": {
|
|
1542
|
+
"verdict": "confirmed",
|
|
1543
|
+
"reason_code": "traced",
|
|
1544
|
+
"checked": [
|
|
1545
|
+
"php-plain/order_detail.php:5-6",
|
|
1546
|
+
"php-plain/inc/auth.php:3-7",
|
|
1547
|
+
"php-plain/inc/db.php:1-4"
|
|
1548
|
+
],
|
|
1549
|
+
"control_found": null,
|
|
1550
|
+
"notes": "The order id is taken from $_GET and concatenated into a raw SQL string without any integer cast or prepared statement. No ownership check is present in the visible code.",
|
|
1551
|
+
"suggested_subtype": null,
|
|
1552
|
+
"suggested_cwe": null
|
|
1553
|
+
},
|
|
1554
|
+
"fingerprint": "kfp1:3065614ddeff53f64ce73f2bd0210f5b36a2249f4d2561f69219095ad867ac9f",
|
|
1555
|
+
"baseline_state": "new"
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
"finding_id": "INJ-I-0032",
|
|
1559
|
+
"category": "sql_injection",
|
|
1560
|
+
"subtype": "string_concatenation",
|
|
1561
|
+
"title": "SQL Injection in php-plain/search.php:8",
|
|
1562
|
+
"candidate_id": "I-0032",
|
|
1563
|
+
"location": {
|
|
1564
|
+
"file": "php-plain/search.php",
|
|
1565
|
+
"start_line": 8
|
|
1566
|
+
},
|
|
1567
|
+
"evidence": [
|
|
1568
|
+
{
|
|
1569
|
+
"file": "php-plain/search.php",
|
|
1570
|
+
"start_line": 5,
|
|
1571
|
+
"code": "$kw = addslashes($_GET['q']);",
|
|
1572
|
+
"why": "User-controlled query string, addslashes is insufficient",
|
|
1573
|
+
"line": 5
|
|
1574
|
+
},
|
|
1575
|
+
{
|
|
1576
|
+
"file": "php-plain/search.php",
|
|
1577
|
+
"start_line": 7,
|
|
1578
|
+
"code": "$sql = \"SELECT id, name FROM products WHERE 1=1\";",
|
|
1579
|
+
"why": "Base query",
|
|
1580
|
+
"line": 7
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
"file": "php-plain/search.php",
|
|
1584
|
+
"start_line": 8,
|
|
1585
|
+
"code": "$sql .= \" AND name LIKE '%\" . $kw . \"%'\";",
|
|
1586
|
+
"why": "Unsanitized LIKE pattern concatenated",
|
|
1587
|
+
"line": 8
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
"file": "php-plain/search.php",
|
|
1591
|
+
"start_line": 11,
|
|
1592
|
+
"code": "$res = mysql_query($sql);",
|
|
1593
|
+
"why": "Query executed without sanitization",
|
|
1594
|
+
"line": 11
|
|
1595
|
+
}
|
|
1596
|
+
],
|
|
1597
|
+
"severity": "critical",
|
|
1598
|
+
"confidence": "high",
|
|
1599
|
+
"cwe": [
|
|
1600
|
+
"CWE-89"
|
|
1601
|
+
],
|
|
1602
|
+
"recommendation": "Use prepared statements with bound parameters",
|
|
1603
|
+
"status": "confirmed",
|
|
1604
|
+
"verification": {
|
|
1605
|
+
"verdict": "confirmed",
|
|
1606
|
+
"reason_code": "traced",
|
|
1607
|
+
"checked": [
|
|
1608
|
+
"php-plain/search.php:5-11",
|
|
1609
|
+
"php-plain/inc/auth.php:3-7",
|
|
1610
|
+
"php-plain/inc/db.php:1-4"
|
|
1611
|
+
],
|
|
1612
|
+
"control_found": null,
|
|
1613
|
+
"notes": "The keyword is escaped with addslashes (insufficient) and concatenated into a LIKE clause. No parameter binding or sanitisation is used.",
|
|
1614
|
+
"suggested_subtype": null,
|
|
1615
|
+
"suggested_cwe": null
|
|
1616
|
+
},
|
|
1617
|
+
"fingerprint": "kfp1:7290ec7c22df15c86f213eb1e27320eaf80f4bafc68a9a6813fb0bd32771b6da",
|
|
1618
|
+
"baseline_state": "new"
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
"finding_id": "INJ-I-0033",
|
|
1622
|
+
"category": "sql_injection",
|
|
1623
|
+
"subtype": "dynamic_identifier",
|
|
1624
|
+
"title": "SQL Injection in php-plain/search.php:9",
|
|
1625
|
+
"candidate_id": "I-0033",
|
|
1626
|
+
"location": {
|
|
1627
|
+
"file": "php-plain/search.php",
|
|
1628
|
+
"start_line": 9
|
|
1629
|
+
},
|
|
1630
|
+
"evidence": [
|
|
1631
|
+
{
|
|
1632
|
+
"file": "php-plain/search.php",
|
|
1633
|
+
"start_line": 6,
|
|
1634
|
+
"code": "$sort = $_GET['sort'];",
|
|
1635
|
+
"why": "User-controlled ORDER BY value",
|
|
1636
|
+
"line": 6
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
"file": "php-plain/search.php",
|
|
1640
|
+
"start_line": 9,
|
|
1641
|
+
"code": "$sql .= \" ORDER BY \" . $sort;",
|
|
1642
|
+
"why": "Unsanitized identifier concatenated into query",
|
|
1643
|
+
"line": 9
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
"file": "php-plain/search.php",
|
|
1647
|
+
"start_line": 11,
|
|
1648
|
+
"code": "$res = mysql_query($sql);",
|
|
1649
|
+
"why": "Query executed without sanitization",
|
|
1650
|
+
"line": 11
|
|
1651
|
+
}
|
|
1652
|
+
],
|
|
1653
|
+
"severity": "critical",
|
|
1654
|
+
"confidence": "high",
|
|
1655
|
+
"cwe": [
|
|
1656
|
+
"CWE-89"
|
|
1657
|
+
],
|
|
1658
|
+
"recommendation": "Validate ORDER BY value against an allow‑list",
|
|
1659
|
+
"status": "confirmed",
|
|
1660
|
+
"verification": {
|
|
1661
|
+
"verdict": "confirmed",
|
|
1662
|
+
"reason_code": "traced",
|
|
1663
|
+
"checked": [
|
|
1664
|
+
"php-plain/search.php:6-9",
|
|
1665
|
+
"php-plain/search.php:11",
|
|
1666
|
+
"php-plain/inc/auth.php:3-7",
|
|
1667
|
+
"php-plain/inc/db.php:1-4"
|
|
1668
|
+
],
|
|
1669
|
+
"control_found": null,
|
|
1670
|
+
"notes": "The ORDER BY value is taken directly from $_GET and concatenated into the query with no allow‑list or validation. No ownership or role check is present.",
|
|
1671
|
+
"suggested_subtype": null,
|
|
1672
|
+
"suggested_cwe": null
|
|
1673
|
+
},
|
|
1674
|
+
"fingerprint": "kfp1:8871b7f21b190efe0d95ac0274808695c3b37ac2eb4a505a8916f71d8dfb8d80",
|
|
1675
|
+
"baseline_state": "new"
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
"finding_id": "INJ-I-0034",
|
|
1679
|
+
"category": "sql_injection",
|
|
1680
|
+
"subtype": "string_concatenation",
|
|
1681
|
+
"title": "SQL Injection in php-plain/search.php:14",
|
|
1682
|
+
"candidate_id": "I-0034",
|
|
1683
|
+
"location": {
|
|
1684
|
+
"file": "php-plain/search.php",
|
|
1685
|
+
"start_line": 14
|
|
1686
|
+
},
|
|
1687
|
+
"evidence": [
|
|
1688
|
+
{
|
|
1689
|
+
"file": "php-plain/search.php",
|
|
1690
|
+
"start_line": 14,
|
|
1691
|
+
"code": "WHERE category = '{$_GET['cat']}'",
|
|
1692
|
+
"why": "User-controlled value interpolated directly into query",
|
|
1693
|
+
"line": 14
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
"file": "php-plain/search.php",
|
|
1697
|
+
"start_line": 12,
|
|
1698
|
+
"code": "$q = <<<SQL\nSELECT * FROM products\nWHERE category = '{$_GET['cat']}'\nSQL;",
|
|
1699
|
+
"why": "Heredoc query built with unsanitized input",
|
|
1700
|
+
"line": 12
|
|
1701
|
+
},
|
|
1702
|
+
{
|
|
1703
|
+
"file": "php-plain/search.php",
|
|
1704
|
+
"start_line": 16,
|
|
1705
|
+
"code": "$res2 = mysql_query($q);",
|
|
1706
|
+
"why": "Query executed without sanitization",
|
|
1707
|
+
"line": 16
|
|
1708
|
+
}
|
|
1709
|
+
],
|
|
1710
|
+
"severity": "critical",
|
|
1711
|
+
"confidence": "high",
|
|
1712
|
+
"cwe": [
|
|
1713
|
+
"CWE-89"
|
|
1714
|
+
],
|
|
1715
|
+
"recommendation": "Use prepared statements with bound parameters",
|
|
1716
|
+
"status": "confirmed",
|
|
1717
|
+
"verification": {
|
|
1718
|
+
"verdict": "confirmed",
|
|
1719
|
+
"reason_code": "traced",
|
|
1720
|
+
"checked": [
|
|
1721
|
+
"php-plain/search.php:12-16",
|
|
1722
|
+
"php-plain/inc/auth.php:3-7",
|
|
1723
|
+
"php-plain/inc/db.php:1-4"
|
|
1724
|
+
],
|
|
1725
|
+
"control_found": null,
|
|
1726
|
+
"notes": "The category value is interpolated directly into a heredoc SQL string. No sanitisation, parameter binding, or ownership check is visible.",
|
|
1727
|
+
"suggested_subtype": null,
|
|
1728
|
+
"suggested_cwe": null
|
|
1729
|
+
},
|
|
1730
|
+
"fingerprint": "kfp1:59c91493f8e83065ed0bab7d82438a17443ae7ba9bc82c1659053686f63083d7",
|
|
1731
|
+
"baseline_state": "new"
|
|
1732
|
+
},
|
|
1733
|
+
{
|
|
1734
|
+
"finding_id": "INJ-I-0036",
|
|
1735
|
+
"category": "sql_injection",
|
|
1736
|
+
"subtype": "string_interpolation",
|
|
1737
|
+
"title": "SQL Injection in python-flask/app.py:29",
|
|
1738
|
+
"candidate_id": "I-0036",
|
|
1739
|
+
"location": {
|
|
1740
|
+
"file": "python-flask/app.py",
|
|
1741
|
+
"start_line": 29
|
|
1742
|
+
},
|
|
1743
|
+
"evidence": [
|
|
1744
|
+
{
|
|
1745
|
+
"file": "python-flask/app.py",
|
|
1746
|
+
"start_line": 27,
|
|
1747
|
+
"code": "q = request.args.get('q', '')",
|
|
1748
|
+
"why": "User-controlled query string",
|
|
1749
|
+
"line": 27
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
"file": "python-flask/app.py",
|
|
1753
|
+
"start_line": 29,
|
|
1754
|
+
"code": "cur.execute(f\"SELECT * FROM products WHERE name LIKE '%{q}%'\")",
|
|
1755
|
+
"why": "Unsanitized f-string interpolation",
|
|
1756
|
+
"line": 29
|
|
1757
|
+
}
|
|
1758
|
+
],
|
|
1759
|
+
"severity": "critical",
|
|
1760
|
+
"confidence": "high",
|
|
1761
|
+
"cwe": [
|
|
1762
|
+
"CWE-89"
|
|
1763
|
+
],
|
|
1764
|
+
"recommendation": "Use parameterized queries",
|
|
1765
|
+
"status": "confirmed",
|
|
1766
|
+
"verification": {
|
|
1767
|
+
"verdict": "confirmed",
|
|
1768
|
+
"reason_code": "traced",
|
|
1769
|
+
"checked": [
|
|
1770
|
+
"python-flask/app.py: lines 24-30 (search route)",
|
|
1771
|
+
"python-flask/app.py: line 29 (f-string query)"
|
|
1772
|
+
],
|
|
1773
|
+
"control_found": null,
|
|
1774
|
+
"notes": "The query interpolates the user‑controlled variable `q` directly into the SQL string without any parameter binding, casting, or allow‑list. The @login_required decorator only ensures authentication, not input sanitization.",
|
|
1775
|
+
"suggested_subtype": null,
|
|
1776
|
+
"suggested_cwe": null
|
|
1777
|
+
},
|
|
1778
|
+
"fingerprint": "kfp1:52c1a1b2beb4129f6fbbfa5c9bcc2f05de1cb6b4a835dcb6adfa7075c03edf79",
|
|
1779
|
+
"baseline_state": "new"
|
|
1780
|
+
},
|
|
1781
|
+
{
|
|
1782
|
+
"finding_id": "INJ-I-0037",
|
|
1783
|
+
"category": "sql_injection",
|
|
1784
|
+
"subtype": "stored_procedure_dynamic_sql",
|
|
1785
|
+
"title": "SQL Injection in sql-procs/sp_search_orders.sql:5",
|
|
1786
|
+
"candidate_id": "I-0037",
|
|
1787
|
+
"location": {
|
|
1788
|
+
"file": "sql-procs/sp_search_orders.sql",
|
|
1789
|
+
"start_line": 5
|
|
1790
|
+
},
|
|
1791
|
+
"evidence": [
|
|
1792
|
+
{
|
|
1793
|
+
"file": "sql-procs/sp_search_orders.sql",
|
|
1794
|
+
"start_line": 5,
|
|
1795
|
+
"code": "SET @sql = 'SELECT * FROM Orders WHERE Customer = ''' + @Customer + ''' ORDER BY ' + @Sort",
|
|
1796
|
+
"why": "Dynamic SQL built from user-supplied parameters",
|
|
1797
|
+
"line": 5
|
|
1798
|
+
}
|
|
1799
|
+
],
|
|
1800
|
+
"severity": "critical",
|
|
1801
|
+
"confidence": "high",
|
|
1802
|
+
"cwe": [
|
|
1803
|
+
"CWE-89"
|
|
1804
|
+
],
|
|
1805
|
+
"recommendation": "Validate @Sort against an allow‑list or use parameterized queries",
|
|
1806
|
+
"status": "confirmed",
|
|
1807
|
+
"verification": {
|
|
1808
|
+
"verdict": "confirmed",
|
|
1809
|
+
"reason_code": "traced",
|
|
1810
|
+
"checked": [
|
|
1811
|
+
"sql-procs/sp_search_orders.sql:5"
|
|
1812
|
+
],
|
|
1813
|
+
"control_found": null,
|
|
1814
|
+
"notes": "Dynamic SQL is built from @Customer and @Sort without any validation or allow‑list. The procedure does not enforce parameterization.",
|
|
1815
|
+
"suggested_subtype": null,
|
|
1816
|
+
"suggested_cwe": null
|
|
1817
|
+
},
|
|
1818
|
+
"fingerprint": "kfp1:dda6a5bb147b8aa741739e9da8799b0f942492567758d5d3209c1395a97c8f98",
|
|
1819
|
+
"baseline_state": "new"
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
"finding_id": "INJ-I-0038",
|
|
1823
|
+
"category": "sql_injection",
|
|
1824
|
+
"subtype": "stored_procedure_dynamic_sql",
|
|
1825
|
+
"title": "SQL Injection in sql-procs/sp_search_orders.sql:6",
|
|
1826
|
+
"candidate_id": "I-0038",
|
|
1827
|
+
"location": {
|
|
1828
|
+
"file": "sql-procs/sp_search_orders.sql",
|
|
1829
|
+
"start_line": 6
|
|
1830
|
+
},
|
|
1831
|
+
"evidence": [
|
|
1832
|
+
{
|
|
1833
|
+
"file": "sql-procs/sp_search_orders.sql",
|
|
1834
|
+
"start_line": 6,
|
|
1835
|
+
"code": "EXEC(@sql)",
|
|
1836
|
+
"why": "Execution of dynamically built SQL string",
|
|
1837
|
+
"line": 6
|
|
1838
|
+
}
|
|
1839
|
+
],
|
|
1840
|
+
"severity": "critical",
|
|
1841
|
+
"confidence": "high",
|
|
1842
|
+
"cwe": [
|
|
1843
|
+
"CWE-89"
|
|
1844
|
+
],
|
|
1845
|
+
"recommendation": "Avoid EXEC(@sql) with user-supplied data; use parameterized queries or validate input",
|
|
1846
|
+
"status": "confirmed",
|
|
1847
|
+
"verification": {
|
|
1848
|
+
"verdict": "confirmed",
|
|
1849
|
+
"reason_code": "traced",
|
|
1850
|
+
"checked": [
|
|
1851
|
+
"sql-procs/sp_search_orders.sql:6"
|
|
1852
|
+
],
|
|
1853
|
+
"control_found": null,
|
|
1854
|
+
"notes": "EXEC(@sql) executes the user‑supplied dynamic SQL string. No validation or parameterization is present.",
|
|
1855
|
+
"suggested_subtype": null,
|
|
1856
|
+
"suggested_cwe": null
|
|
1857
|
+
},
|
|
1858
|
+
"fingerprint": "kfp1:bc5a024fdb7c6ece9891fb3cce3e046b4627068fc198466fd6f98f71af5bea43",
|
|
1859
|
+
"baseline_state": "new"
|
|
1860
|
+
},
|
|
1861
|
+
{
|
|
1862
|
+
"finding_id": "MASS-M-0006-1",
|
|
1863
|
+
"category": "mass_assignment",
|
|
1864
|
+
"subtype": "whole_object_binding",
|
|
1865
|
+
"title": "Unfiltered request body bound to User model in /profile",
|
|
1866
|
+
"route_id": null,
|
|
1867
|
+
"candidate_id": "M-0006",
|
|
1868
|
+
"location": {
|
|
1869
|
+
"file": "routes/user.js",
|
|
1870
|
+
"start_line": 8
|
|
1871
|
+
},
|
|
1872
|
+
"evidence": [
|
|
1873
|
+
{
|
|
1874
|
+
"file": "routes/user.js",
|
|
1875
|
+
"line": 8,
|
|
1876
|
+
"why": "User.findByIdAndUpdate(req.user._id, req.body, ...) binds the entire request body to the User model without filtering privileged fields such as role."
|
|
1877
|
+
}
|
|
1878
|
+
],
|
|
1879
|
+
"impact": "Privilege escalation via the role field",
|
|
1880
|
+
"severity": "critical",
|
|
1881
|
+
"confidence": "medium",
|
|
1882
|
+
"cwe": [
|
|
1883
|
+
"CWE-915"
|
|
1884
|
+
],
|
|
1885
|
+
"recommendation": "Whitelist allowed fields or set privileged fields server‑side; do not bind the raw request body.",
|
|
1886
|
+
"status": "likely",
|
|
1887
|
+
"verification": {
|
|
1888
|
+
"verdict": "likely",
|
|
1889
|
+
"reason_code": "code_not_visible",
|
|
1890
|
+
"checked": [
|
|
1891
|
+
"routes/user.js:8"
|
|
1892
|
+
],
|
|
1893
|
+
"control_found": null,
|
|
1894
|
+
"notes": "The code_context indicates that the file routes/user.js is not available in the repository snapshot provided. Therefore, no evidence of a mass‑assignment guard (e.g., a whitelist, $fillable, or explicit field filtering) can be verified. The absence of visible code prevents confirmation of a compensating control.",
|
|
1895
|
+
"suggested_subtype": null,
|
|
1896
|
+
"suggested_cwe": null
|
|
1897
|
+
},
|
|
1898
|
+
"fingerprint": "kfp1:282f5e8be1631c7b03fed9bf57993ef10563c39925ef41f9be43c7a2213948c4",
|
|
1899
|
+
"baseline_state": "new"
|
|
1900
|
+
},
|
|
1901
|
+
{
|
|
1902
|
+
"finding_id": "MASS-M-0008-1",
|
|
1903
|
+
"category": "mass_assignment",
|
|
1904
|
+
"subtype": "whole_object_binding",
|
|
1905
|
+
"title": "Unfiltered request body bound to User model in register",
|
|
1906
|
+
"route_id": null,
|
|
1907
|
+
"candidate_id": "M-0008",
|
|
1908
|
+
"location": {
|
|
1909
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1910
|
+
"start_line": 13
|
|
1911
|
+
},
|
|
1912
|
+
"evidence": [
|
|
1913
|
+
{
|
|
1914
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1915
|
+
"line": 13,
|
|
1916
|
+
"why": "User::create($request->all()) binds all request fields to the User model, including privileged fields such as role."
|
|
1917
|
+
}
|
|
1918
|
+
],
|
|
1919
|
+
"impact": "Privilege escalation via the role field",
|
|
1920
|
+
"severity": "critical",
|
|
1921
|
+
"confidence": "medium",
|
|
1922
|
+
"cwe": [
|
|
1923
|
+
"CWE-915"
|
|
1924
|
+
],
|
|
1925
|
+
"recommendation": "Use a fillable/allowlist or explicitly set privileged fields server‑side.",
|
|
1926
|
+
"status": "likely",
|
|
1927
|
+
"verification": {
|
|
1928
|
+
"verdict": "likely",
|
|
1929
|
+
"reason_code": "code_not_visible",
|
|
1930
|
+
"checked": [
|
|
1931
|
+
"app/Http/Controllers/AccountController.php:13"
|
|
1932
|
+
],
|
|
1933
|
+
"control_found": null,
|
|
1934
|
+
"notes": "The file app/Http/Controllers/AccountController.php is not present in the code_context. Without visibility into the controller or the User model’s $fillable/$guarded properties, a compensating mass‑assignment guard cannot be confirmed.",
|
|
1935
|
+
"suggested_subtype": null,
|
|
1936
|
+
"suggested_cwe": null
|
|
1937
|
+
},
|
|
1938
|
+
"fingerprint": "kfp1:5ad56d30cbf69c227a69cbcbfcd26f42733998e980cae7d122d7bcec7ea73ebc",
|
|
1939
|
+
"baseline_state": "new"
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
"finding_id": "MASS-M-0009-1",
|
|
1943
|
+
"category": "mass_assignment",
|
|
1944
|
+
"subtype": "privileged_field_writable",
|
|
1945
|
+
"title": "Owner ID writable in Team creation",
|
|
1946
|
+
"route_id": null,
|
|
1947
|
+
"candidate_id": "M-0009",
|
|
1948
|
+
"location": {
|
|
1949
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1950
|
+
"start_line": 23
|
|
1951
|
+
},
|
|
1952
|
+
"evidence": [
|
|
1953
|
+
{
|
|
1954
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1955
|
+
"line": 23,
|
|
1956
|
+
"why": "Team::create($request->all()) allows the owner_id field to be set by the client."
|
|
1957
|
+
}
|
|
1958
|
+
],
|
|
1959
|
+
"impact": "Arbitrary ownership assignment via owner_id",
|
|
1960
|
+
"severity": "critical",
|
|
1961
|
+
"confidence": "medium",
|
|
1962
|
+
"cwe": [
|
|
1963
|
+
"CWE-915"
|
|
1964
|
+
],
|
|
1965
|
+
"recommendation": "Do not allow owner_id to be set by the client; set it server‑side based on the authenticated user.",
|
|
1966
|
+
"status": "likely",
|
|
1967
|
+
"verification": {
|
|
1968
|
+
"verdict": "likely",
|
|
1969
|
+
"reason_code": "code_not_visible",
|
|
1970
|
+
"checked": [
|
|
1971
|
+
"app/Http/Controllers/AccountController.php:23"
|
|
1972
|
+
],
|
|
1973
|
+
"control_found": null,
|
|
1974
|
+
"notes": "The referenced file is missing; therefore, there is no evidence of a server‑side restriction on the owner_id field or a fillable guard in the Team model.",
|
|
1975
|
+
"suggested_subtype": null,
|
|
1976
|
+
"suggested_cwe": null
|
|
1977
|
+
},
|
|
1978
|
+
"fingerprint": "kfp1:28b0be984e1eb817cca53b79b6014265eda827fcca1b7ec8b48937bc11d7576e",
|
|
1979
|
+
"baseline_state": "new"
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
"finding_id": "MASS-M-0010-1",
|
|
1983
|
+
"category": "mass_assignment",
|
|
1984
|
+
"subtype": "whole_object_binding",
|
|
1985
|
+
"title": "Unfiltered request body bound to Team model in team",
|
|
1986
|
+
"route_id": null,
|
|
1987
|
+
"candidate_id": "M-0010",
|
|
1988
|
+
"location": {
|
|
1989
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1990
|
+
"start_line": 23
|
|
1991
|
+
},
|
|
1992
|
+
"evidence": [
|
|
1993
|
+
{
|
|
1994
|
+
"file": "app/Http/Controllers/AccountController.php",
|
|
1995
|
+
"line": 23,
|
|
1996
|
+
"why": "Team::create($request->all()) binds all request fields, including privileged fields such as owner_id."
|
|
1997
|
+
}
|
|
1998
|
+
],
|
|
1999
|
+
"impact": "Privilege escalation via owner_id",
|
|
2000
|
+
"severity": "critical",
|
|
2001
|
+
"confidence": "medium",
|
|
2002
|
+
"cwe": [
|
|
2003
|
+
"CWE-915"
|
|
2004
|
+
],
|
|
2005
|
+
"recommendation": "Whitelist allowed fields or set privileged fields server‑side.",
|
|
2006
|
+
"status": "likely",
|
|
2007
|
+
"verification": {
|
|
2008
|
+
"verdict": "likely",
|
|
2009
|
+
"reason_code": "code_not_visible",
|
|
2010
|
+
"checked": [
|
|
2011
|
+
"app/Http/Controllers/AccountController.php:23"
|
|
2012
|
+
],
|
|
2013
|
+
"control_found": null,
|
|
2014
|
+
"notes": "Without access to the controller or the Team model definition, a compensating mass‑assignment control cannot be verified.",
|
|
2015
|
+
"suggested_subtype": null,
|
|
2016
|
+
"suggested_cwe": null
|
|
2017
|
+
},
|
|
2018
|
+
"fingerprint": "kfp1:48552e2b8335c4d317ae08fb6ccf64b0c0ed6080e49ab69113701ce1fd1314ce",
|
|
2019
|
+
"baseline_state": "new"
|
|
2020
|
+
},
|
|
2021
|
+
{
|
|
2022
|
+
"finding_id": "MASS-M-0014-1",
|
|
2023
|
+
"category": "mass_assignment",
|
|
2024
|
+
"subtype": "whole_object_binding",
|
|
2025
|
+
"title": "Unfiltered request body bound to User in POST /users",
|
|
2026
|
+
"route_id": null,
|
|
2027
|
+
"candidate_id": "M-0014",
|
|
2028
|
+
"location": {
|
|
2029
|
+
"file": "app.py",
|
|
2030
|
+
"start_line": 10
|
|
2031
|
+
},
|
|
2032
|
+
"evidence": [
|
|
2033
|
+
{
|
|
2034
|
+
"file": "app.py",
|
|
2035
|
+
"line": 10,
|
|
2036
|
+
"why": "User(**request.json) binds all request fields, including privileged ones such as role."
|
|
2037
|
+
}
|
|
2038
|
+
],
|
|
2039
|
+
"impact": "Privilege escalation via the role field",
|
|
2040
|
+
"severity": "critical",
|
|
2041
|
+
"confidence": "medium",
|
|
2042
|
+
"cwe": [
|
|
2043
|
+
"CWE-915"
|
|
2044
|
+
],
|
|
2045
|
+
"recommendation": "Whitelist allowed fields or set privileged fields server‑side.",
|
|
2046
|
+
"status": "likely",
|
|
2047
|
+
"verification": {
|
|
2048
|
+
"verdict": "likely",
|
|
2049
|
+
"reason_code": "code_not_visible",
|
|
2050
|
+
"checked": [
|
|
2051
|
+
"app.py line 10"
|
|
2052
|
+
],
|
|
2053
|
+
"control_found": null,
|
|
2054
|
+
"notes": "The code that performs the mass assignment is not present in the provided context; no compensating control is visible.",
|
|
2055
|
+
"suggested_subtype": null,
|
|
2056
|
+
"suggested_cwe": null
|
|
2057
|
+
},
|
|
2058
|
+
"fingerprint": "kfp1:ce4a5edbc11d47f0e7f1c8880eb0c744ee98ee0f2834696e9ac8642ee6281773",
|
|
2059
|
+
"baseline_state": "new"
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
"finding_id": "MASS-M-0015-1",
|
|
2063
|
+
"category": "mass_assignment",
|
|
2064
|
+
"subtype": "whole_object_binding",
|
|
2065
|
+
"title": "Unfiltered request body bound to User in PATCH /users/<uid>",
|
|
2066
|
+
"route_id": null,
|
|
2067
|
+
"candidate_id": "M-0015",
|
|
2068
|
+
"location": {
|
|
2069
|
+
"file": "app.py",
|
|
2070
|
+
"start_line": 27
|
|
2071
|
+
},
|
|
2072
|
+
"evidence": [
|
|
2073
|
+
{
|
|
2074
|
+
"file": "app.py",
|
|
2075
|
+
"line": 27,
|
|
2076
|
+
"why": "for key, value in request.json.items(): setattr(user, key, value) binds all fields, including privileged ones such as role."
|
|
2077
|
+
}
|
|
2078
|
+
],
|
|
2079
|
+
"impact": "Privilege escalation via the role field",
|
|
2080
|
+
"severity": "critical",
|
|
2081
|
+
"confidence": "medium",
|
|
2082
|
+
"cwe": [
|
|
2083
|
+
"CWE-915"
|
|
2084
|
+
],
|
|
2085
|
+
"recommendation": "Whitelist editable fields or set privileged fields server‑side.",
|
|
2086
|
+
"status": "likely",
|
|
2087
|
+
"verification": {
|
|
2088
|
+
"verdict": "likely",
|
|
2089
|
+
"reason_code": "code_not_visible",
|
|
2090
|
+
"checked": [
|
|
2091
|
+
"app.py line 27"
|
|
2092
|
+
],
|
|
2093
|
+
"control_found": null,
|
|
2094
|
+
"notes": "The code that performs the mass assignment is not present in the provided context; no compensating control is visible.",
|
|
2095
|
+
"suggested_subtype": null,
|
|
2096
|
+
"suggested_cwe": null
|
|
2097
|
+
},
|
|
2098
|
+
"fingerprint": "kfp1:2b45c26cb0e79c67cde4ca5fd3bda885bdbc5af1c02aab97781ca4656b950580",
|
|
2099
|
+
"baseline_state": "new"
|
|
2100
|
+
},
|
|
2101
|
+
{
|
|
2102
|
+
"finding_id": "BOLA-R-0010",
|
|
2103
|
+
"category": "bola",
|
|
2104
|
+
"subtype": "missing_ownership_check",
|
|
2105
|
+
"title": "BOLA in POST /Customer/Edit: missing owner verification",
|
|
2106
|
+
"route_id": "R-0010",
|
|
2107
|
+
"endpoint": {
|
|
2108
|
+
"method": "POST",
|
|
2109
|
+
"path": "/Customer/Edit"
|
|
2110
|
+
},
|
|
2111
|
+
"location": {
|
|
2112
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2113
|
+
"start_line": 12
|
|
2114
|
+
},
|
|
2115
|
+
"evidence": [
|
|
2116
|
+
{
|
|
2117
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2118
|
+
"start_line": 12,
|
|
2119
|
+
"code": "[HttpPost]\npublic ActionResult Edit(Customer customer)\n{\n db.Entry(customer).State = System.Data.Entity.EntityState.Modified;\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
|
|
2120
|
+
"why": "The Customer object is bound directly from the request and saved without checking that the customer belongs to the authenticated user.",
|
|
2121
|
+
"line": 12
|
|
2122
|
+
}
|
|
2123
|
+
],
|
|
2124
|
+
"severity": "high",
|
|
2125
|
+
"confidence": "medium",
|
|
2126
|
+
"cwe": [
|
|
2127
|
+
"CWE-284",
|
|
2128
|
+
"CWE-639"
|
|
2129
|
+
],
|
|
2130
|
+
"recommendation": "Verify ownership before saving.",
|
|
2131
|
+
"status": "likely",
|
|
2132
|
+
"verification": {
|
|
2133
|
+
"verdict": "likely",
|
|
2134
|
+
"reason_code": "code_not_visible",
|
|
2135
|
+
"checked": [
|
|
2136
|
+
"dotnet-legacy/Web/Controllers/CustomerController.cs: lines 11-16"
|
|
2137
|
+
],
|
|
2138
|
+
"control_found": null,
|
|
2139
|
+
"notes": "The Edit action binds a Customer object from the request and persists it without verifying that the customer belongs to the authenticated user. No ownership check is visible in the snippet.",
|
|
2140
|
+
"suggested_subtype": null,
|
|
2141
|
+
"suggested_cwe": null
|
|
2142
|
+
},
|
|
2143
|
+
"fingerprint": "kfp1:2ff50be6396a3261e2543aa3b955d99113acdc748a014446cb0b489407bafe90",
|
|
2144
|
+
"baseline_state": "new"
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
"finding_id": "BOLA-R-0011",
|
|
2148
|
+
"category": "bola",
|
|
2149
|
+
"subtype": "missing_ownership_check",
|
|
2150
|
+
"title": "BOLA in POST /Customer/EditName: missing owner verification",
|
|
2151
|
+
"route_id": "R-0011",
|
|
2152
|
+
"endpoint": {
|
|
2153
|
+
"method": "POST",
|
|
2154
|
+
"path": "/Customer/EditName"
|
|
2155
|
+
},
|
|
2156
|
+
"location": {
|
|
2157
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2158
|
+
"start_line": 20
|
|
2159
|
+
},
|
|
2160
|
+
"evidence": [
|
|
2161
|
+
{
|
|
2162
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2163
|
+
"start_line": 20,
|
|
2164
|
+
"code": "[HttpPost]\npublic ActionResult EditName([Bind(Include = \"Id,Name\")] Customer customer)\n{\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
|
|
2165
|
+
"why": "The customer ID is taken from the request and the record is updated without verifying that the customer belongs to the authenticated user.",
|
|
2166
|
+
"line": 20
|
|
2167
|
+
}
|
|
2168
|
+
],
|
|
2169
|
+
"severity": "high",
|
|
2170
|
+
"confidence": "medium",
|
|
2171
|
+
"cwe": [
|
|
2172
|
+
"CWE-284",
|
|
2173
|
+
"CWE-639"
|
|
2174
|
+
],
|
|
2175
|
+
"recommendation": "Check that the customer belongs to the current user before saving.",
|
|
2176
|
+
"status": "likely",
|
|
2177
|
+
"verification": {
|
|
2178
|
+
"verdict": "likely",
|
|
2179
|
+
"reason_code": "code_not_visible",
|
|
2180
|
+
"checked": [
|
|
2181
|
+
"dotnet-legacy/Web/Controllers/CustomerController.cs: lines 20-23"
|
|
2182
|
+
],
|
|
2183
|
+
"control_found": null,
|
|
2184
|
+
"notes": "EditName updates the customer record using a bound object without any ownership verification. The snippet shows no such check.",
|
|
2185
|
+
"suggested_subtype": null,
|
|
2186
|
+
"suggested_cwe": null
|
|
2187
|
+
},
|
|
2188
|
+
"fingerprint": "kfp1:f8f8312969722c53dc4fbfcebddf09bfc6ea44e77f308058c6f5a0a79916c6a1",
|
|
2189
|
+
"baseline_state": "new"
|
|
2190
|
+
},
|
|
2191
|
+
{
|
|
2192
|
+
"finding_id": "BOLA-R-0012",
|
|
2193
|
+
"category": "bola",
|
|
2194
|
+
"subtype": "missing_ownership_check",
|
|
2195
|
+
"title": "BOLA in POST /Customer/Refresh: missing owner verification",
|
|
2196
|
+
"route_id": "R-0012",
|
|
2197
|
+
"endpoint": {
|
|
2198
|
+
"method": "POST",
|
|
2199
|
+
"path": "/Customer/Refresh"
|
|
2200
|
+
},
|
|
2201
|
+
"location": {
|
|
2202
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2203
|
+
"start_line": 27
|
|
2204
|
+
},
|
|
2205
|
+
"evidence": [
|
|
2206
|
+
{
|
|
2207
|
+
"file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
|
|
2208
|
+
"start_line": 27,
|
|
2209
|
+
"code": "[HttpPost]\npublic ActionResult Refresh(int id)\n{\n var customer = db.Customers.Find(id);\n TryUpdateModel(customer);\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
|
|
2210
|
+
"why": "The customer ID is taken from the request and the record is updated without verifying that the customer belongs to the authenticated user.",
|
|
2211
|
+
"line": 27
|
|
2212
|
+
}
|
|
2213
|
+
],
|
|
2214
|
+
"severity": "high",
|
|
2215
|
+
"confidence": "medium",
|
|
2216
|
+
"cwe": [
|
|
2217
|
+
"CWE-284",
|
|
2218
|
+
"CWE-639"
|
|
2219
|
+
],
|
|
2220
|
+
"recommendation": "Validate ownership before updating.",
|
|
2221
|
+
"status": "likely",
|
|
2222
|
+
"verification": {
|
|
2223
|
+
"verdict": "likely",
|
|
2224
|
+
"reason_code": "code_not_visible",
|
|
2225
|
+
"checked": [
|
|
2226
|
+
"dotnet-legacy/Web/Controllers/CustomerController.cs: lines 27-32"
|
|
2227
|
+
],
|
|
2228
|
+
"control_found": null,
|
|
2229
|
+
"notes": "Refresh loads a customer by id and applies TryUpdateModel without confirming ownership. No ownership guard is present in the shown code.",
|
|
2230
|
+
"suggested_subtype": null,
|
|
2231
|
+
"suggested_cwe": null
|
|
2232
|
+
},
|
|
2233
|
+
"fingerprint": "kfp1:642d9e00b1146b80dc8724396082e7bf839dc74fdcc9224c6452557ed7b19ab7",
|
|
2234
|
+
"baseline_state": "new"
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
"finding_id": "BOLA-R-0016",
|
|
2238
|
+
"category": "bola",
|
|
2239
|
+
"subtype": "missing_ownership_check",
|
|
2240
|
+
"title": "BOLA in ANY /dotnet-legacy/Web/Handlers/GetFile.ashx: missing owner verification",
|
|
2241
|
+
"route_id": "R-0016",
|
|
2242
|
+
"endpoint": {
|
|
2243
|
+
"method": "ANY",
|
|
2244
|
+
"path": "/dotnet-legacy/Web/Handlers/GetFile.ashx"
|
|
2245
|
+
},
|
|
2246
|
+
"location": {
|
|
2247
|
+
"file": "dotnet-legacy/Web/Handlers/GetFile.ashx",
|
|
2248
|
+
"start_line": 8
|
|
2249
|
+
},
|
|
2250
|
+
"evidence": [
|
|
2251
|
+
{
|
|
2252
|
+
"file": "dotnet-legacy/Web/Handlers/GetFile.ashx",
|
|
2253
|
+
"start_line": 8,
|
|
2254
|
+
"code": "string fileId = context.Request.QueryString[\"file_id\"];\nstring path = DocStore.PathFor(fileId);\ncontext.Response.TransmitFile(path);",
|
|
2255
|
+
"why": "The file identifier is taken directly from the query string and the file is served without checking that the file belongs to the authenticated user.",
|
|
2256
|
+
"line": 8
|
|
2257
|
+
}
|
|
2258
|
+
],
|
|
2259
|
+
"severity": "high",
|
|
2260
|
+
"confidence": "medium",
|
|
2261
|
+
"cwe": [
|
|
2262
|
+
"CWE-284",
|
|
2263
|
+
"CWE-639"
|
|
2264
|
+
],
|
|
2265
|
+
"recommendation": "Restrict file access to the authenticated user.",
|
|
2266
|
+
"status": "likely",
|
|
2267
|
+
"verification": {
|
|
2268
|
+
"verdict": "likely",
|
|
2269
|
+
"reason_code": "code_not_visible",
|
|
2270
|
+
"checked": [
|
|
2271
|
+
"dotnet-legacy/Web/Handlers/GetFile.ashx: lines 8-10"
|
|
2272
|
+
],
|
|
2273
|
+
"control_found": null,
|
|
2274
|
+
"notes": "The handler retrieves a file path from the query string and transmits it without any ownership or role check. The snippet does not reveal any such guard.",
|
|
2275
|
+
"suggested_subtype": null,
|
|
2276
|
+
"suggested_cwe": null
|
|
2277
|
+
},
|
|
2278
|
+
"fingerprint": "kfp1:d642a15232edeffab2a15511431577f3f9ce893382573e1c45e203eec7bb0cad",
|
|
2279
|
+
"baseline_state": "new"
|
|
2280
|
+
},
|
|
2281
|
+
{
|
|
2282
|
+
"finding_id": "BOLA-R-0020",
|
|
2283
|
+
"category": "bola",
|
|
2284
|
+
"subtype": "missing_ownership_check",
|
|
2285
|
+
"title": "BOLA in POST /account/save: missing owner verification",
|
|
2286
|
+
"route_id": "R-0020",
|
|
2287
|
+
"endpoint": {
|
|
2288
|
+
"method": "POST",
|
|
2289
|
+
"path": "/account/save"
|
|
2290
|
+
},
|
|
2291
|
+
"location": {
|
|
2292
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2293
|
+
"start_line": 13
|
|
2294
|
+
},
|
|
2295
|
+
"evidence": [
|
|
2296
|
+
{
|
|
2297
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2298
|
+
"start_line": 13,
|
|
2299
|
+
"code": " @RequestMapping(value = \"/save\", method = RequestMethod.POST)\n public String save(@ModelAttribute Account account) {\n accountDao.save(account);\n return \"redirect:/account\";\n }",
|
|
2300
|
+
"why": "The account is saved without checking that the current user owns the account.",
|
|
2301
|
+
"line": 13
|
|
2302
|
+
}
|
|
2303
|
+
],
|
|
2304
|
+
"severity": "high",
|
|
2305
|
+
"confidence": "medium",
|
|
2306
|
+
"cwe": [
|
|
2307
|
+
"CWE-284",
|
|
2308
|
+
"CWE-639"
|
|
2309
|
+
],
|
|
2310
|
+
"recommendation": "Bind the save operation to the current session user.",
|
|
2311
|
+
"status": "likely",
|
|
2312
|
+
"verification": {
|
|
2313
|
+
"verdict": "likely",
|
|
2314
|
+
"reason_code": "code_not_visible",
|
|
2315
|
+
"checked": [
|
|
2316
|
+
"AccountController.save method (lines 13‑16)"
|
|
2317
|
+
],
|
|
2318
|
+
"control_found": null,
|
|
2319
|
+
"notes": "The method directly persists the supplied Account object without any ownership or role verification. No cast or allow‑list is present in the visible code.",
|
|
2320
|
+
"suggested_subtype": null,
|
|
2321
|
+
"suggested_cwe": null
|
|
2322
|
+
},
|
|
2323
|
+
"fingerprint": "kfp1:da6ba81e707bc9691e776f217be38c128a81b5a660f94e3a2778b25f874e1957",
|
|
2324
|
+
"baseline_state": "new"
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
"finding_id": "BOLA-R-0021",
|
|
2328
|
+
"category": "bola",
|
|
2329
|
+
"subtype": "missing_ownership_check",
|
|
2330
|
+
"title": "BOLA in POST /account/rename: missing owner verification",
|
|
2331
|
+
"route_id": "R-0021",
|
|
2332
|
+
"endpoint": {
|
|
2333
|
+
"method": "POST",
|
|
2334
|
+
"path": "/account/rename"
|
|
2335
|
+
},
|
|
2336
|
+
"location": {
|
|
2337
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2338
|
+
"start_line": 19
|
|
2339
|
+
},
|
|
2340
|
+
"evidence": [
|
|
2341
|
+
{
|
|
2342
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2343
|
+
"start_line": 19,
|
|
2344
|
+
"code": " @RequestMapping(value = \"/rename\", method = RequestMethod.POST)\n public String rename(@ModelAttribute RenameForm form) {\n accountDao.rename(form.getId(), form.getName());\n return \"redirect:/account\";\n }",
|
|
2345
|
+
"why": "The rename operation uses the supplied id without verifying ownership.",
|
|
2346
|
+
"line": 19
|
|
2347
|
+
}
|
|
2348
|
+
],
|
|
2349
|
+
"severity": "high",
|
|
2350
|
+
"confidence": "medium",
|
|
2351
|
+
"cwe": [
|
|
2352
|
+
"CWE-284",
|
|
2353
|
+
"CWE-639"
|
|
2354
|
+
],
|
|
2355
|
+
"recommendation": "Verify that the account belongs to the current user before renaming.",
|
|
2356
|
+
"status": "likely",
|
|
2357
|
+
"verification": {
|
|
2358
|
+
"verdict": "likely",
|
|
2359
|
+
"reason_code": "code_not_visible",
|
|
2360
|
+
"checked": [
|
|
2361
|
+
"AccountController.rename method (lines 19‑22)"
|
|
2362
|
+
],
|
|
2363
|
+
"control_found": null,
|
|
2364
|
+
"notes": "The rename operation uses the id from the form without checking that the current user owns the account. No ownership guard or role check is visible.",
|
|
2365
|
+
"suggested_subtype": null,
|
|
2366
|
+
"suggested_cwe": null
|
|
2367
|
+
},
|
|
2368
|
+
"fingerprint": "kfp1:436b1118118c6a11d9a08401ceb7e845c737fc510a1527be37b102622c97cf52",
|
|
2369
|
+
"baseline_state": "new"
|
|
2370
|
+
},
|
|
2371
|
+
{
|
|
2372
|
+
"finding_id": "BOLA-R-0022",
|
|
2373
|
+
"category": "bola",
|
|
2374
|
+
"subtype": "missing_ownership_check",
|
|
2375
|
+
"title": "BOLA in PUT /account/api: missing owner verification",
|
|
2376
|
+
"route_id": "R-0022",
|
|
2377
|
+
"endpoint": {
|
|
2378
|
+
"method": "PUT",
|
|
2379
|
+
"path": "/account/api"
|
|
2380
|
+
},
|
|
2381
|
+
"location": {
|
|
2382
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2383
|
+
"start_line": 25
|
|
2384
|
+
},
|
|
2385
|
+
"evidence": [
|
|
2386
|
+
{
|
|
2387
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
2388
|
+
"start_line": 25,
|
|
2389
|
+
"code": " @RequestMapping(value = \"/api\", method = RequestMethod.PUT)\n @ResponseBody\n public Account update(@RequestBody Account account) {\n return accountDao.save(account);\n }",
|
|
2390
|
+
"why": "The account is updated without checking that the current user owns it.",
|
|
2391
|
+
"line": 25
|
|
2392
|
+
}
|
|
2393
|
+
],
|
|
2394
|
+
"severity": "high",
|
|
2395
|
+
"confidence": "medium",
|
|
2396
|
+
"cwe": [
|
|
2397
|
+
"CWE-284",
|
|
2398
|
+
"CWE-639"
|
|
2399
|
+
],
|
|
2400
|
+
"recommendation": "Bind the update to the current session user.",
|
|
2401
|
+
"status": "likely",
|
|
2402
|
+
"verification": {
|
|
2403
|
+
"verdict": "likely",
|
|
2404
|
+
"reason_code": "code_not_visible",
|
|
2405
|
+
"checked": [
|
|
2406
|
+
"AccountController.update method (lines 25‑28)"
|
|
2407
|
+
],
|
|
2408
|
+
"control_found": null,
|
|
2409
|
+
"notes": "The update method persists the supplied Account object directly, with no ownership or role validation shown in the code.",
|
|
2410
|
+
"suggested_subtype": null,
|
|
2411
|
+
"suggested_cwe": null
|
|
2412
|
+
},
|
|
2413
|
+
"fingerprint": "kfp1:da398947b87b88d6858e1e8fbf762cd899ea7d68e9159b815743d29deef2a666",
|
|
2414
|
+
"baseline_state": "new"
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
"finding_id": "BOLA-R-0023",
|
|
2418
|
+
"category": "bola",
|
|
2419
|
+
"subtype": "missing_ownership_check",
|
|
2420
|
+
"title": "BOLA in POST /admin/users/{id}/delete: missing ownership and role check",
|
|
2421
|
+
"route_id": "R-0023",
|
|
2422
|
+
"endpoint": {
|
|
2423
|
+
"method": "POST",
|
|
2424
|
+
"path": "/admin/users/{id}/delete"
|
|
2425
|
+
},
|
|
2426
|
+
"location": {
|
|
2427
|
+
"file": "java-legacy/src/com/acme/web/AdminUserController.java",
|
|
2428
|
+
"start_line": 13
|
|
2429
|
+
},
|
|
2430
|
+
"evidence": [
|
|
2431
|
+
{
|
|
2432
|
+
"file": "java-legacy/src/com/acme/web/AdminUserController.java",
|
|
2433
|
+
"start_line": 13,
|
|
2434
|
+
"code": " @RequestMapping(value = \"/{id}/delete\", method = RequestMethod.POST)\n public String delete(@PathVariable(\"id\") Long id) {\n userDao.deleteById(id);\n return \"redirect:/admin/users\";\n }",
|
|
2435
|
+
"why": "Any authenticated user can delete any user because no role or ownership check is performed.",
|
|
2436
|
+
"line": 13
|
|
2437
|
+
}
|
|
2438
|
+
],
|
|
2439
|
+
"severity": "high",
|
|
2440
|
+
"confidence": "medium",
|
|
2441
|
+
"cwe": [
|
|
2442
|
+
"CWE-284",
|
|
2443
|
+
"CWE-639"
|
|
2444
|
+
],
|
|
2445
|
+
"recommendation": "Add an admin role guard and verify ownership if needed.",
|
|
2446
|
+
"status": "likely",
|
|
2447
|
+
"verification": {
|
|
2448
|
+
"verdict": "likely",
|
|
2449
|
+
"reason_code": "code_not_visible",
|
|
2450
|
+
"checked": [
|
|
2451
|
+
"AdminUserController.delete method (lines 13‑16)"
|
|
2452
|
+
],
|
|
2453
|
+
"control_found": null,
|
|
2454
|
+
"notes": "The delete endpoint calls userDao.deleteById without any role or ownership check. The @PreAuthorize annotation applies only to the subsequent method, not to delete.",
|
|
2455
|
+
"suggested_subtype": null,
|
|
2456
|
+
"suggested_cwe": null
|
|
2457
|
+
},
|
|
2458
|
+
"fingerprint": "kfp1:a4f576c3ecb678956e186f0ee7498af55e42a7b8632ed464b8eada05c59007b4",
|
|
2459
|
+
"baseline_state": "new"
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
"finding_id": "BOLA-R-0025",
|
|
2463
|
+
"category": "bola",
|
|
2464
|
+
"subtype": "missing_ownership_check",
|
|
2465
|
+
"title": "BOLA in GET /invoices/{id}: missing owner verification",
|
|
2466
|
+
"route_id": "R-0025",
|
|
2467
|
+
"endpoint": {
|
|
2468
|
+
"method": "GET",
|
|
2469
|
+
"path": "/invoices/{id}"
|
|
2470
|
+
},
|
|
2471
|
+
"location": {
|
|
2472
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
2473
|
+
"start_line": 15
|
|
2474
|
+
},
|
|
2475
|
+
"evidence": [
|
|
2476
|
+
{
|
|
2477
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
2478
|
+
"start_line": 15,
|
|
2479
|
+
"code": " @RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n public String show(@PathVariable(\"id\") Long id, Model model) {\n model.addAttribute(\"invoice\", invoiceDao.findById(id));\n return \"invoice/show\";\n }",
|
|
2480
|
+
"why": "The invoice is fetched by id without checking that the current user owns it.",
|
|
2481
|
+
"line": 15
|
|
2482
|
+
}
|
|
2483
|
+
],
|
|
2484
|
+
"severity": "high",
|
|
2485
|
+
"confidence": "medium",
|
|
2486
|
+
"cwe": [
|
|
2487
|
+
"CWE-284",
|
|
2488
|
+
"CWE-639"
|
|
2489
|
+
],
|
|
2490
|
+
"recommendation": "Bind the query to the current user.",
|
|
2491
|
+
"status": "likely",
|
|
2492
|
+
"verification": {
|
|
2493
|
+
"verdict": "likely",
|
|
2494
|
+
"reason_code": "code_not_visible",
|
|
2495
|
+
"checked": [
|
|
2496
|
+
"InvoiceController.show method (lines 15‑18)"
|
|
2497
|
+
],
|
|
2498
|
+
"control_found": null,
|
|
2499
|
+
"notes": "The show method retrieves an invoice by id without verifying that the current user owns it. No ownership guard or role check is present in the visible code.",
|
|
2500
|
+
"suggested_subtype": null,
|
|
2501
|
+
"suggested_cwe": null
|
|
2502
|
+
},
|
|
2503
|
+
"fingerprint": "kfp1:4213dd0e852a3473b5f77a0dd8c52fbbb9776802a6d4475b6edad70be330df73",
|
|
2504
|
+
"baseline_state": "new"
|
|
2505
|
+
},
|
|
2506
|
+
{
|
|
2507
|
+
"finding_id": "BOLA-R-0027",
|
|
2508
|
+
"category": "bola",
|
|
2509
|
+
"subtype": "missing_ownership_check",
|
|
2510
|
+
"title": "BOLA in GET /invoices/search: missing owner verification",
|
|
2511
|
+
"route_id": "R-0027",
|
|
2512
|
+
"endpoint": {
|
|
2513
|
+
"method": "GET",
|
|
2514
|
+
"path": "/invoices/search"
|
|
2515
|
+
},
|
|
2516
|
+
"location": {
|
|
2517
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
2518
|
+
"start_line": 27
|
|
2519
|
+
},
|
|
2520
|
+
"evidence": [
|
|
2521
|
+
{
|
|
2522
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
2523
|
+
"start_line": 27,
|
|
2524
|
+
"code": " @RequestMapping(value = \"/search\", method = RequestMethod.GET)\n public String search(@RequestParam(\"customer\") String customer, Model model) {\n model.addAttribute(\"list\", session.createQuery(\"from Invoice i where i.customer = '\" + customer + \"'\").list());\n return \"invoice/list\";\n }",
|
|
2525
|
+
"why": "The search query returns all invoices for the given customer without restricting to the current user.",
|
|
2526
|
+
"line": 27
|
|
2527
|
+
}
|
|
2528
|
+
],
|
|
2529
|
+
"severity": "high",
|
|
2530
|
+
"confidence": "medium",
|
|
2531
|
+
"cwe": [
|
|
2532
|
+
"CWE-284",
|
|
2533
|
+
"CWE-639"
|
|
2534
|
+
],
|
|
2535
|
+
"recommendation": "Add a user filter to the search query.",
|
|
2536
|
+
"status": "likely",
|
|
2537
|
+
"verification": {
|
|
2538
|
+
"verdict": "likely",
|
|
2539
|
+
"reason_code": "code_not_visible",
|
|
2540
|
+
"checked": [
|
|
2541
|
+
"InvoiceController.search method (lines 27‑30)"
|
|
2542
|
+
],
|
|
2543
|
+
"control_found": null,
|
|
2544
|
+
"notes": "The search query concatenates the customer parameter directly into the HQL string and does not include any user_id or role filter. No ownership or role guard is visible in the provided code context.",
|
|
2545
|
+
"suggested_subtype": null,
|
|
2546
|
+
"suggested_cwe": null
|
|
2547
|
+
},
|
|
2548
|
+
"fingerprint": "kfp1:b576c39e6469454d66f748f828a753ff3f9f250c5538a9c88b4a57760334d368",
|
|
2549
|
+
"baseline_state": "new"
|
|
2550
|
+
},
|
|
2551
|
+
{
|
|
2552
|
+
"finding_id": "BOLA-R-0028",
|
|
2553
|
+
"category": "bola",
|
|
2554
|
+
"subtype": "missing_ownership_check",
|
|
2555
|
+
"title": "BOLA in GET /order/view: missing owner verification",
|
|
2556
|
+
"route_id": "R-0028",
|
|
2557
|
+
"endpoint": {
|
|
2558
|
+
"method": "GET",
|
|
2559
|
+
"path": "/order/view"
|
|
2560
|
+
},
|
|
2561
|
+
"location": {
|
|
2562
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
2563
|
+
"start_line": 8
|
|
2564
|
+
},
|
|
2565
|
+
"evidence": [
|
|
2566
|
+
{
|
|
2567
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
2568
|
+
"start_line": 8,
|
|
2569
|
+
"code": " protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {\n HttpSession session = request.getSession();\n Object loginUser = session.getAttribute(\"loginUser\");\n String id = request.getParameter(\"orderId\");\n try {\n Connection conn = DataSourceHolder.get().getConnection();\n Statement stmt = conn.createStatement();\n ResultSet rs = stmt.executeQuery(\"SELECT * FROM orders WHERE id = '\" + id + \"'\");\n StringBuilder sb = new StringBuilder(\"SELECT * FROM items WHERE 1=1\");\n sb.append(\" AND order_id = \").append(id);\n ResultSet items = stmt.executeQuery(sb.toString());\n PreparedStatement ps = conn.prepareStatement(\"SELECT * FROM notes WHERE order_id = ?\");\n ps.setString(1, id);\n } catch (SQLException e) {\n throw new IOException(e);\n }",
|
|
2570
|
+
"why": "The order is retrieved solely by id, allowing any user to view any order.",
|
|
2571
|
+
"line": 8
|
|
2572
|
+
}
|
|
2573
|
+
],
|
|
2574
|
+
"severity": "high",
|
|
2575
|
+
"confidence": "medium",
|
|
2576
|
+
"cwe": [
|
|
2577
|
+
"CWE-284",
|
|
2578
|
+
"CWE-639"
|
|
2579
|
+
],
|
|
2580
|
+
"recommendation": "Add an ownership check to the order query.",
|
|
2581
|
+
"status": "likely",
|
|
2582
|
+
"verification": {
|
|
2583
|
+
"verdict": "likely",
|
|
2584
|
+
"reason_code": "code_not_visible",
|
|
2585
|
+
"checked": [
|
|
2586
|
+
"OrderServlet.doGet method (lines 8‑20)"
|
|
2587
|
+
],
|
|
2588
|
+
"control_found": null,
|
|
2589
|
+
"notes": "The order is retrieved by id using a raw SQL statement without any user_id filter or role check. No cast or allow‑list is present in the visible code.",
|
|
2590
|
+
"suggested_subtype": null,
|
|
2591
|
+
"suggested_cwe": null
|
|
2592
|
+
},
|
|
2593
|
+
"fingerprint": "kfp1:099a9a98e36374b37df8f56b6de8534fbd7feb621c3632bac20d1272028a36c7",
|
|
2594
|
+
"baseline_state": "new"
|
|
2595
|
+
},
|
|
2596
|
+
{
|
|
2597
|
+
"finding_id": "BOLA-R-0029",
|
|
2598
|
+
"category": "bola",
|
|
2599
|
+
"subtype": "missing_ownership_check",
|
|
2600
|
+
"title": "BOLA in POST <see web.xml servlet-mapping>: missing owner verification",
|
|
2601
|
+
"route_id": "R-0029",
|
|
2602
|
+
"endpoint": {
|
|
2603
|
+
"method": "POST",
|
|
2604
|
+
"path": "<see web.xml servlet-mapping>"
|
|
2605
|
+
},
|
|
2606
|
+
"location": {
|
|
2607
|
+
"file": "java-legacy/src/com/acme/web/ProfileServlet.java",
|
|
2608
|
+
"start_line": 9
|
|
2609
|
+
},
|
|
2610
|
+
"evidence": [
|
|
2611
|
+
{
|
|
2612
|
+
"file": "java-legacy/src/com/acme/web/ProfileServlet.java",
|
|
2613
|
+
"start_line": 9,
|
|
2614
|
+
"code": "protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {\n Account account = new Account();\n try {\n BeanUtils.populate(account, request.getParameterMap());\n } catch (Exception e) {\n throw new IOException(e);\n }\n}",
|
|
2615
|
+
"why": "The request parameters are bound directly to an Account object and persisted without verifying that the account belongs to the authenticated user.",
|
|
2616
|
+
"line": 9
|
|
2617
|
+
}
|
|
2618
|
+
],
|
|
2619
|
+
"severity": "high",
|
|
2620
|
+
"confidence": "medium",
|
|
2621
|
+
"cwe": [
|
|
2622
|
+
"CWE-284",
|
|
2623
|
+
"CWE-639"
|
|
2624
|
+
],
|
|
2625
|
+
"recommendation": "Validate that the account belongs to the current user before persisting.",
|
|
2626
|
+
"status": "likely",
|
|
2627
|
+
"verification": {
|
|
2628
|
+
"verdict": "likely",
|
|
2629
|
+
"reason_code": "code_not_visible",
|
|
2630
|
+
"checked": [
|
|
2631
|
+
"java-legacy/src/com/acme/web/ProfileServlet.java:9-16"
|
|
2632
|
+
],
|
|
2633
|
+
"control_found": null,
|
|
2634
|
+
"notes": "The code shown populates an Account object directly from request parameters and persists it without any ownership check. No DAO or global filter is visible in the provided context, so a compensating control cannot be confirmed.",
|
|
2635
|
+
"suggested_subtype": null,
|
|
2636
|
+
"suggested_cwe": null
|
|
2637
|
+
},
|
|
2638
|
+
"fingerprint": "kfp1:f8c53a1c11f4e356cd58bf22809c720589dfa46c38243f129f05d96341d8a333",
|
|
2639
|
+
"baseline_state": "new"
|
|
2640
|
+
},
|
|
2641
|
+
{
|
|
2642
|
+
"finding_id": "BOLA-R-0030",
|
|
2643
|
+
"category": "bola",
|
|
2644
|
+
"subtype": "missing_ownership_check",
|
|
2645
|
+
"title": "BOLA in POST /admin/users/:id/delete: missing ownership and role check",
|
|
2646
|
+
"route_id": "R-0030",
|
|
2647
|
+
"endpoint": {
|
|
2648
|
+
"method": "POST",
|
|
2649
|
+
"path": "/admin/users/:id/delete"
|
|
2650
|
+
},
|
|
2651
|
+
"location": {
|
|
2652
|
+
"file": "node-express/routes/admin.js",
|
|
2653
|
+
"start_line": 8
|
|
2654
|
+
},
|
|
2655
|
+
"evidence": [
|
|
2656
|
+
{
|
|
2657
|
+
"file": "node-express/routes/admin.js",
|
|
2658
|
+
"start_line": 8,
|
|
2659
|
+
"code": "router.post('/admin/users/:id/delete', ensureLoggedIn, function (req, res) {\n User.deleteOne({ _id: req.params.id }, function () { res.sendStatus(204); });\n});",
|
|
2660
|
+
"why": "Any authenticated user can delete any user because only a login guard is applied.",
|
|
2661
|
+
"line": 8
|
|
2662
|
+
}
|
|
2663
|
+
],
|
|
2664
|
+
"severity": "high",
|
|
2665
|
+
"confidence": "medium",
|
|
2666
|
+
"cwe": [
|
|
2667
|
+
"CWE-284",
|
|
2668
|
+
"CWE-639"
|
|
2669
|
+
],
|
|
2670
|
+
"recommendation": "Add an admin role guard and verify ownership if required.",
|
|
2671
|
+
"status": "likely",
|
|
2672
|
+
"verification": {
|
|
2673
|
+
"verdict": "likely",
|
|
2674
|
+
"reason_code": "code_not_visible",
|
|
2675
|
+
"checked": [
|
|
2676
|
+
"admin.js delete route (lines 8‑9)"
|
|
2677
|
+
],
|
|
2678
|
+
"control_found": null,
|
|
2679
|
+
"notes": "Only an authentication guard is applied; no admin role check or ownership verification is visible in the route handler.",
|
|
2680
|
+
"suggested_subtype": null,
|
|
2681
|
+
"suggested_cwe": null
|
|
2682
|
+
},
|
|
2683
|
+
"fingerprint": "kfp1:3dd2e6ecf2f0730978e0c2a05f31e2af3920a107cd2af0b5ea81c9ded7f6a100",
|
|
2684
|
+
"baseline_state": "new"
|
|
2685
|
+
},
|
|
2686
|
+
{
|
|
2687
|
+
"finding_id": "BOLA-R-0033-1",
|
|
2688
|
+
"category": "bola",
|
|
2689
|
+
"subtype": "missing_ownership_check",
|
|
2690
|
+
"title": "BOLA in GET /orders/:id: missing owner verification",
|
|
2691
|
+
"route_id": "R-0033",
|
|
2692
|
+
"endpoint": {
|
|
2693
|
+
"method": "GET",
|
|
2694
|
+
"path": "/orders/:id"
|
|
2695
|
+
},
|
|
2696
|
+
"location": {
|
|
2697
|
+
"file": "node-express/routes/orders.js",
|
|
2698
|
+
"start_line": 8
|
|
2699
|
+
},
|
|
2700
|
+
"evidence": [
|
|
2701
|
+
{
|
|
2702
|
+
"file": "node-express/routes/orders.js",
|
|
2703
|
+
"start_line": 8,
|
|
2704
|
+
"code": "Order.findById(req.params.id, function (err, order) { res.json(order); });",
|
|
2705
|
+
"why": "The query loads an order by id without filtering on the authenticated user, allowing any logged‑in user to retrieve another user's order.",
|
|
2706
|
+
"line": 8
|
|
2707
|
+
}
|
|
2708
|
+
],
|
|
2709
|
+
"severity": "high",
|
|
2710
|
+
"confidence": "medium",
|
|
2711
|
+
"cwe": [
|
|
2712
|
+
"CWE-284",
|
|
2713
|
+
"CWE-639"
|
|
2714
|
+
],
|
|
2715
|
+
"recommendation": "Bind the query to the current session user.",
|
|
2716
|
+
"status": "likely",
|
|
2717
|
+
"verification": {
|
|
2718
|
+
"verdict": "likely",
|
|
2719
|
+
"reason_code": "code_not_visible",
|
|
2720
|
+
"checked": [
|
|
2721
|
+
"orders.js get /orders/:id route (lines 8‑9)"
|
|
2722
|
+
],
|
|
2723
|
+
"control_found": null,
|
|
2724
|
+
"notes": "The handler calls Order.findById with the request id only, without filtering on req.user._id. No role or ownership guard is present in the shown code.",
|
|
2725
|
+
"suggested_subtype": null,
|
|
2726
|
+
"suggested_cwe": null
|
|
2727
|
+
},
|
|
2728
|
+
"fingerprint": "kfp1:3efb41972fd6c818041a922563d6a1e65eb9cdcd63b764b52ff4ffce238a6c8d",
|
|
2729
|
+
"baseline_state": "new"
|
|
2730
|
+
},
|
|
2731
|
+
{
|
|
2732
|
+
"finding_id": "BOLA-R-0043-1",
|
|
2733
|
+
"category": "bola",
|
|
2734
|
+
"subtype": "missing_ownership_check",
|
|
2735
|
+
"title": "BOLA in ANY /perl-cgi/cgi-bin/order.cgi: missing owner verification",
|
|
2736
|
+
"route_id": "R-0043",
|
|
2737
|
+
"endpoint": {
|
|
2738
|
+
"method": "ANY",
|
|
2739
|
+
"path": "/perl-cgi/cgi-bin/order.cgi"
|
|
2740
|
+
},
|
|
2741
|
+
"location": {
|
|
2742
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
2743
|
+
"start_line": 13
|
|
2744
|
+
},
|
|
2745
|
+
"evidence": [
|
|
2746
|
+
{
|
|
2747
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
2748
|
+
"start_line": 13,
|
|
2749
|
+
"code": "$sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");",
|
|
2750
|
+
"why": "The query selects an order by id without filtering on the session user, enabling IDOR.",
|
|
2751
|
+
"line": 13
|
|
2752
|
+
}
|
|
2753
|
+
],
|
|
2754
|
+
"severity": "high",
|
|
2755
|
+
"confidence": "medium",
|
|
2756
|
+
"cwe": [
|
|
2757
|
+
"CWE-284",
|
|
2758
|
+
"CWE-639"
|
|
2759
|
+
],
|
|
2760
|
+
"recommendation": "Add a user_id filter to the query.",
|
|
2761
|
+
"status": "likely",
|
|
2762
|
+
"verification": {
|
|
2763
|
+
"verdict": "likely",
|
|
2764
|
+
"reason_code": "code_not_visible",
|
|
2765
|
+
"checked": [
|
|
2766
|
+
"order.cgi query preparation (lines 13‑14)"
|
|
2767
|
+
],
|
|
2768
|
+
"control_found": null,
|
|
2769
|
+
"notes": "The prepared statement selects an order by id without including the session user_id. No role or ownership check is visible in the provided snippet.",
|
|
2770
|
+
"suggested_subtype": null,
|
|
2771
|
+
"suggested_cwe": null
|
|
2772
|
+
},
|
|
2773
|
+
"fingerprint": "kfp1:0823c809d4892eb324f1b12ff01c568fed5e7b10e716e2a0064b9ed53c6f0380",
|
|
2774
|
+
"baseline_state": "new"
|
|
2775
|
+
},
|
|
2776
|
+
{
|
|
2777
|
+
"finding_id": "BOLA-R-0044-1",
|
|
2778
|
+
"category": "bola",
|
|
2779
|
+
"subtype": "missing_ownership_check",
|
|
2780
|
+
"title": "BOLA in ANY /invoice/view/{id}: missing owner verification",
|
|
2781
|
+
"route_id": "R-0044",
|
|
2782
|
+
"endpoint": {
|
|
2783
|
+
"method": "ANY",
|
|
2784
|
+
"path": "/invoice/view/{id}"
|
|
2785
|
+
},
|
|
2786
|
+
"location": {
|
|
2787
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
2788
|
+
"start_line": 9
|
|
2789
|
+
},
|
|
2790
|
+
"evidence": [
|
|
2791
|
+
{
|
|
2792
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
2793
|
+
"start_line": 9,
|
|
2794
|
+
"code": "$q = $this->db->query(\"SELECT * FROM invoices WHERE id = $id\");",
|
|
2795
|
+
"why": "The query retrieves an invoice by id without checking the authenticated user, allowing any user to view another user's invoice.",
|
|
2796
|
+
"line": 9
|
|
2797
|
+
}
|
|
2798
|
+
],
|
|
2799
|
+
"severity": "high",
|
|
2800
|
+
"confidence": "medium",
|
|
2801
|
+
"cwe": [
|
|
2802
|
+
"CWE-284",
|
|
2803
|
+
"CWE-639"
|
|
2804
|
+
],
|
|
2805
|
+
"recommendation": "Bind the query to the current session user.",
|
|
2806
|
+
"status": "likely",
|
|
2807
|
+
"verification": {
|
|
2808
|
+
"verdict": "likely",
|
|
2809
|
+
"reason_code": "code_not_visible",
|
|
2810
|
+
"checked": [
|
|
2811
|
+
"php-codeigniter/application/controllers/Invoice.php:9-11"
|
|
2812
|
+
],
|
|
2813
|
+
"control_found": null,
|
|
2814
|
+
"notes": "The view method performs a raw SELECT by id without any user_id filter or ownership check. No ownership guard is visible in the provided code, and the base controller (MY_Controller) is not shown, so a compensating control cannot be confirmed.",
|
|
2815
|
+
"suggested_subtype": null,
|
|
2816
|
+
"suggested_cwe": null
|
|
2817
|
+
},
|
|
2818
|
+
"fingerprint": "kfp1:266f870d96cd69a0b4644c5c983b5c92d59a3d989f9d2514e1016f6ffd372f3b",
|
|
2819
|
+
"baseline_state": "new"
|
|
2820
|
+
},
|
|
2821
|
+
{
|
|
2822
|
+
"finding_id": "BOLA-R-0046-1",
|
|
2823
|
+
"category": "bola",
|
|
2824
|
+
"subtype": "missing_ownership_check",
|
|
2825
|
+
"title": "BOLA in ANY /invoice/update: missing owner verification",
|
|
2826
|
+
"route_id": "R-0046",
|
|
2827
|
+
"endpoint": {
|
|
2828
|
+
"method": "ANY",
|
|
2829
|
+
"path": "/invoice/update"
|
|
2830
|
+
},
|
|
2831
|
+
"location": {
|
|
2832
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
2833
|
+
"start_line": 20
|
|
2834
|
+
},
|
|
2835
|
+
"evidence": [
|
|
2836
|
+
{
|
|
2837
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
2838
|
+
"start_line": 20,
|
|
2839
|
+
"code": "$this->db->query(\"UPDATE invoices SET note = ? WHERE id = ?\", array($note, $id));",
|
|
2840
|
+
"why": "The update statement modifies an invoice by id without ensuring the invoice belongs to the authenticated user, enabling IDOR.",
|
|
2841
|
+
"line": 20
|
|
2842
|
+
}
|
|
2843
|
+
],
|
|
2844
|
+
"severity": "high",
|
|
2845
|
+
"confidence": "medium",
|
|
2846
|
+
"cwe": [
|
|
2847
|
+
"CWE-284",
|
|
2848
|
+
"CWE-639"
|
|
2849
|
+
],
|
|
2850
|
+
"recommendation": "Add a user_id filter to the update statement.",
|
|
2851
|
+
"status": "likely",
|
|
2852
|
+
"verification": {
|
|
2853
|
+
"verdict": "likely",
|
|
2854
|
+
"reason_code": "code_not_visible",
|
|
2855
|
+
"checked": [
|
|
2856
|
+
"php-codeigniter/application/controllers/Invoice.php:20-23"
|
|
2857
|
+
],
|
|
2858
|
+
"control_found": null,
|
|
2859
|
+
"notes": "The update method updates an invoice by id without checking the authenticated user. No ownership guard is visible in the snippet, and the base controller is not examined, so the absence of a check cannot be ruled out.",
|
|
2860
|
+
"suggested_subtype": null,
|
|
2861
|
+
"suggested_cwe": null
|
|
2862
|
+
},
|
|
2863
|
+
"fingerprint": "kfp1:f8000507518dfd07801d08ee0115647eaf2efdfdcfcd467cab0be7ea43514273",
|
|
2864
|
+
"baseline_state": "new"
|
|
2865
|
+
},
|
|
2866
|
+
{
|
|
2867
|
+
"finding_id": "BOLA-R-0057-view",
|
|
2868
|
+
"category": "bola",
|
|
2869
|
+
"subtype": "missing_ownership_check",
|
|
2870
|
+
"title": "BOLA in GET /php-plain/admin.php?action=view: missing owner verification",
|
|
2871
|
+
"route_id": "R-0057",
|
|
2872
|
+
"endpoint": {
|
|
2873
|
+
"method": "GET",
|
|
2874
|
+
"path": "/php-plain/admin.php?action=view"
|
|
2875
|
+
},
|
|
2876
|
+
"location": {
|
|
2877
|
+
"file": "php-plain/admin.php",
|
|
2878
|
+
"start_line": 6
|
|
2879
|
+
},
|
|
2880
|
+
"evidence": [
|
|
2881
|
+
{
|
|
2882
|
+
"file": "php-plain/admin.php",
|
|
2883
|
+
"start_line": 7,
|
|
2884
|
+
"code": "$uid = (int)$_GET['uid'];",
|
|
2885
|
+
"why": "ID from request",
|
|
2886
|
+
"line": 7
|
|
2887
|
+
},
|
|
2888
|
+
{
|
|
2889
|
+
"file": "php-plain/admin.php",
|
|
2890
|
+
"start_line": 8,
|
|
2891
|
+
"code": "$r = mysql_query(\"SELECT * FROM users WHERE id = \" . $uid);",
|
|
2892
|
+
"why": "Query uses id without user ownership check",
|
|
2893
|
+
"line": 8
|
|
2894
|
+
}
|
|
2895
|
+
],
|
|
2896
|
+
"severity": "high",
|
|
2897
|
+
"confidence": "high",
|
|
2898
|
+
"cwe": [
|
|
2899
|
+
"CWE-639",
|
|
2900
|
+
"CWE-284"
|
|
2901
|
+
],
|
|
2902
|
+
"recommendation": "Bind query to current session user",
|
|
2903
|
+
"status": "confirmed",
|
|
2904
|
+
"verification": {
|
|
2905
|
+
"verdict": "confirmed",
|
|
2906
|
+
"reason_code": "traced",
|
|
2907
|
+
"checked": [
|
|
2908
|
+
"php-plain/admin.php lines 5-9",
|
|
2909
|
+
"php-plain/inc/auth.php lines 1-7"
|
|
2910
|
+
],
|
|
2911
|
+
"control_found": null,
|
|
2912
|
+
"notes": "The request parameter is cast to int, but the query selects from users by id without any user_id filter or role check. The included auth.php only verifies a logged‑in session, not ownership.",
|
|
2913
|
+
"suggested_subtype": null,
|
|
2914
|
+
"suggested_cwe": null
|
|
2915
|
+
},
|
|
2916
|
+
"fingerprint": "kfp1:3691f0046489f4fb4004e0df5818c6f613138b47d5675c7dc926255b0a186096",
|
|
2917
|
+
"baseline_state": "new"
|
|
2918
|
+
},
|
|
2919
|
+
{
|
|
2920
|
+
"finding_id": "BOLA-R-0058-delete",
|
|
2921
|
+
"category": "bola",
|
|
2922
|
+
"subtype": "missing_ownership_check",
|
|
2923
|
+
"title": "BOLA in POST /php-plain/admin.php?action=delete: missing owner verification",
|
|
2924
|
+
"route_id": "R-0058",
|
|
2925
|
+
"endpoint": {
|
|
2926
|
+
"method": "POST",
|
|
2927
|
+
"path": "/php-plain/admin.php?action=delete"
|
|
2928
|
+
},
|
|
2929
|
+
"location": {
|
|
2930
|
+
"file": "php-plain/admin.php",
|
|
2931
|
+
"start_line": 10
|
|
2932
|
+
},
|
|
2933
|
+
"evidence": [
|
|
2934
|
+
{
|
|
2935
|
+
"file": "php-plain/admin.php",
|
|
2936
|
+
"start_line": 11,
|
|
2937
|
+
"code": "$id = $_POST['id'];",
|
|
2938
|
+
"why": "ID from request",
|
|
2939
|
+
"line": 11
|
|
2940
|
+
},
|
|
2941
|
+
{
|
|
2942
|
+
"file": "php-plain/admin.php",
|
|
2943
|
+
"start_line": 12,
|
|
2944
|
+
"code": "mysql_query(\"DELETE FROM users WHERE id = $id\");",
|
|
2945
|
+
"why": "Delete without ownership check",
|
|
2946
|
+
"line": 12
|
|
2947
|
+
}
|
|
2948
|
+
],
|
|
2949
|
+
"severity": "high",
|
|
2950
|
+
"confidence": "high",
|
|
2951
|
+
"cwe": [
|
|
2952
|
+
"CWE-639",
|
|
2953
|
+
"CWE-284"
|
|
2954
|
+
],
|
|
2955
|
+
"recommendation": "Bind delete to current session user",
|
|
2956
|
+
"status": "confirmed",
|
|
2957
|
+
"verification": {
|
|
2958
|
+
"verdict": "confirmed",
|
|
2959
|
+
"reason_code": "traced",
|
|
2960
|
+
"checked": [
|
|
2961
|
+
"php-plain/admin.php lines 10-13",
|
|
2962
|
+
"php-plain/inc/auth.php lines 1-7"
|
|
2963
|
+
],
|
|
2964
|
+
"control_found": null,
|
|
2965
|
+
"notes": "The delete statement uses the id from the request directly; no ownership or role guard is present. The auth.php only checks for a logged‑in session.",
|
|
2966
|
+
"suggested_subtype": null,
|
|
2967
|
+
"suggested_cwe": null
|
|
2968
|
+
},
|
|
2969
|
+
"fingerprint": "kfp1:00dddf4b55c567cdf4432ca9180652ef14141f6a7209f530d04973f172a383e8",
|
|
2970
|
+
"baseline_state": "new"
|
|
2971
|
+
},
|
|
2972
|
+
{
|
|
2973
|
+
"finding_id": "BOLA-R-0059-manage_users",
|
|
2974
|
+
"category": "bola",
|
|
2975
|
+
"subtype": "missing_ownership_check",
|
|
2976
|
+
"title": "BOLA in POST /php-plain/manage_users.php: missing owner verification",
|
|
2977
|
+
"route_id": "R-0059",
|
|
2978
|
+
"endpoint": {
|
|
2979
|
+
"method": "POST",
|
|
2980
|
+
"path": "/php-plain/manage_users.php"
|
|
2981
|
+
},
|
|
2982
|
+
"location": {
|
|
2983
|
+
"file": "php-plain/manage_users.php",
|
|
2984
|
+
"start_line": 5
|
|
2985
|
+
},
|
|
2986
|
+
"evidence": [
|
|
2987
|
+
{
|
|
2988
|
+
"file": "php-plain/manage_users.php",
|
|
2989
|
+
"start_line": 5,
|
|
2990
|
+
"code": "if ($_SERVER['REQUEST_METHOD'] === 'POST') {",
|
|
2991
|
+
"why": "POST request",
|
|
2992
|
+
"line": 5
|
|
2993
|
+
},
|
|
2994
|
+
{
|
|
2995
|
+
"file": "php-plain/manage_users.php",
|
|
2996
|
+
"start_line": 6,
|
|
2997
|
+
"code": "$stmt = $db->prepare(\"DELETE FROM users WHERE id = ?\");",
|
|
2998
|
+
"why": "Delete without ownership check",
|
|
2999
|
+
"line": 6
|
|
3000
|
+
},
|
|
3001
|
+
{
|
|
3002
|
+
"file": "php-plain/manage_users.php",
|
|
3003
|
+
"start_line": 7,
|
|
3004
|
+
"code": "$stmt->execute(array((int)$_POST['id']));",
|
|
3005
|
+
"why": "Execute delete",
|
|
3006
|
+
"line": 7
|
|
3007
|
+
}
|
|
3008
|
+
],
|
|
3009
|
+
"severity": "high",
|
|
3010
|
+
"confidence": "high",
|
|
3011
|
+
"cwe": [
|
|
3012
|
+
"CWE-639",
|
|
3013
|
+
"CWE-284"
|
|
3014
|
+
],
|
|
3015
|
+
"recommendation": "Bind delete to current session user",
|
|
3016
|
+
"status": "confirmed",
|
|
3017
|
+
"verification": {
|
|
3018
|
+
"verdict": "confirmed",
|
|
3019
|
+
"reason_code": "traced",
|
|
3020
|
+
"checked": [
|
|
3021
|
+
"php-plain/manage_users.php"
|
|
3022
|
+
],
|
|
3023
|
+
"control_found": null,
|
|
3024
|
+
"notes": "The DELETE statement uses a POST parameter for the user id with no ownership or role verification. The cast to int does not mitigate the lack of authorization.",
|
|
3025
|
+
"suggested_subtype": null,
|
|
3026
|
+
"suggested_cwe": null
|
|
3027
|
+
},
|
|
3028
|
+
"fingerprint": "kfp1:08e7e40b1898b061e12415cfde4fc28a2ba729418d4c548f7e22b68a4056e0cc",
|
|
3029
|
+
"baseline_state": "new"
|
|
3030
|
+
},
|
|
3031
|
+
{
|
|
3032
|
+
"finding_id": "BOLA-R-0061-order_detail",
|
|
3033
|
+
"category": "bola",
|
|
3034
|
+
"subtype": "missing_ownership_check",
|
|
3035
|
+
"title": "BOLA in GET /php-plain/order_detail.php: missing owner verification",
|
|
3036
|
+
"route_id": "R-0061",
|
|
3037
|
+
"endpoint": {
|
|
3038
|
+
"method": "GET",
|
|
3039
|
+
"path": "/php-plain/order_detail.php"
|
|
3040
|
+
},
|
|
3041
|
+
"location": {
|
|
3042
|
+
"file": "php-plain/order_detail.php",
|
|
3043
|
+
"start_line": 5
|
|
3044
|
+
},
|
|
3045
|
+
"evidence": [
|
|
3046
|
+
{
|
|
3047
|
+
"file": "php-plain/order_detail.php",
|
|
3048
|
+
"start_line": 5,
|
|
3049
|
+
"code": "$id = $_GET['id'];",
|
|
3050
|
+
"why": "ID from request",
|
|
3051
|
+
"line": 5
|
|
3052
|
+
},
|
|
3053
|
+
{
|
|
3054
|
+
"file": "php-plain/order_detail.php",
|
|
3055
|
+
"start_line": 6,
|
|
3056
|
+
"code": "$res = mysql_query(\"SELECT * FROM orders WHERE id = \" . $id);",
|
|
3057
|
+
"why": "Query uses id without user ownership check",
|
|
3058
|
+
"line": 6
|
|
3059
|
+
}
|
|
3060
|
+
],
|
|
3061
|
+
"severity": "high",
|
|
3062
|
+
"confidence": "high",
|
|
3063
|
+
"cwe": [
|
|
3064
|
+
"CWE-639",
|
|
3065
|
+
"CWE-284"
|
|
3066
|
+
],
|
|
3067
|
+
"recommendation": "Bind query to current session user",
|
|
3068
|
+
"status": "confirmed",
|
|
3069
|
+
"verification": {
|
|
3070
|
+
"verdict": "confirmed",
|
|
3071
|
+
"reason_code": "traced",
|
|
3072
|
+
"checked": [
|
|
3073
|
+
"php-plain/order_detail.php"
|
|
3074
|
+
],
|
|
3075
|
+
"control_found": null,
|
|
3076
|
+
"notes": "The query selects an order by id from the request without filtering by the current user’s id. No ownership check or role guard is present.",
|
|
3077
|
+
"suggested_subtype": null,
|
|
3078
|
+
"suggested_cwe": null
|
|
3079
|
+
},
|
|
3080
|
+
"fingerprint": "kfp1:140efc93b08c193dd167db59f6a495c4cda56c967489cf32705bb8e227ed82e4",
|
|
3081
|
+
"baseline_state": "new"
|
|
3082
|
+
},
|
|
3083
|
+
{
|
|
3084
|
+
"finding_id": "BOLA-R-0066-delete_user",
|
|
3085
|
+
"category": "bola",
|
|
3086
|
+
"subtype": "missing_ownership_check",
|
|
3087
|
+
"title": "BOLA in POST /php-plain/admin/delete_user.php: missing owner verification",
|
|
3088
|
+
"route_id": "R-0066",
|
|
3089
|
+
"endpoint": {
|
|
3090
|
+
"method": "POST",
|
|
3091
|
+
"path": "/php-plain/admin/delete_user.php"
|
|
3092
|
+
},
|
|
3093
|
+
"location": {
|
|
3094
|
+
"file": "php-plain/admin/delete_user.php",
|
|
3095
|
+
"start_line": 5
|
|
3096
|
+
},
|
|
3097
|
+
"evidence": [
|
|
3098
|
+
{
|
|
3099
|
+
"file": "php-plain/admin/delete_user.php",
|
|
3100
|
+
"start_line": 5,
|
|
3101
|
+
"code": "$id = (int)$_POST['id'];",
|
|
3102
|
+
"why": "ID from request",
|
|
3103
|
+
"line": 5
|
|
3104
|
+
},
|
|
3105
|
+
{
|
|
3106
|
+
"file": "php-plain/admin/delete_user.php",
|
|
3107
|
+
"start_line": 6,
|
|
3108
|
+
"code": "$stmt = $db->prepare(\"DELETE FROM users WHERE id = ?\");",
|
|
3109
|
+
"why": "Delete without ownership check",
|
|
3110
|
+
"line": 6
|
|
3111
|
+
},
|
|
3112
|
+
{
|
|
3113
|
+
"file": "php-plain/admin/delete_user.php",
|
|
3114
|
+
"start_line": 7,
|
|
3115
|
+
"code": "$stmt->execute(array($id));",
|
|
3116
|
+
"why": "Execute delete",
|
|
3117
|
+
"line": 7
|
|
3118
|
+
}
|
|
3119
|
+
],
|
|
3120
|
+
"severity": "high",
|
|
3121
|
+
"confidence": "high",
|
|
3122
|
+
"cwe": [
|
|
3123
|
+
"CWE-639",
|
|
3124
|
+
"CWE-284"
|
|
3125
|
+
],
|
|
3126
|
+
"recommendation": "Bind delete to current session user",
|
|
3127
|
+
"status": "confirmed",
|
|
3128
|
+
"verification": {
|
|
3129
|
+
"verdict": "confirmed",
|
|
3130
|
+
"reason_code": "traced",
|
|
3131
|
+
"checked": [
|
|
3132
|
+
"php-plain/admin/delete_user.php lines 5-7",
|
|
3133
|
+
"php-plain/inc/auth.php lines 1-7"
|
|
3134
|
+
],
|
|
3135
|
+
"control_found": null,
|
|
3136
|
+
"notes": "The delete query is parameterized but still deletes by id without verifying that the id belongs to the current session user or that the caller has an admin role. No ownership check is visible.",
|
|
3137
|
+
"suggested_subtype": null,
|
|
3138
|
+
"suggested_cwe": null
|
|
3139
|
+
},
|
|
3140
|
+
"fingerprint": "kfp1:0da2f858297a3d4ebd54b94ece77760ab41c73280cf69a320b15b12ae8d88b7f",
|
|
3141
|
+
"baseline_state": "new"
|
|
3142
|
+
},
|
|
3143
|
+
{
|
|
3144
|
+
"finding_id": "BOLA-R-0067-promote",
|
|
3145
|
+
"category": "bola",
|
|
3146
|
+
"subtype": "missing_ownership_check",
|
|
3147
|
+
"title": "BOLA in POST /php-plain/admin/promote.php: missing owner verification",
|
|
3148
|
+
"route_id": "R-0067",
|
|
3149
|
+
"endpoint": {
|
|
3150
|
+
"method": "POST",
|
|
3151
|
+
"path": "/php-plain/admin/promote.php"
|
|
3152
|
+
},
|
|
3153
|
+
"location": {
|
|
3154
|
+
"file": "php-plain/admin/promote.php",
|
|
3155
|
+
"start_line": 5
|
|
3156
|
+
},
|
|
3157
|
+
"evidence": [
|
|
3158
|
+
{
|
|
3159
|
+
"file": "php-plain/admin/promote.php",
|
|
3160
|
+
"start_line": 5,
|
|
3161
|
+
"code": "if ($_POST['is_admin'] == '1') {",
|
|
3162
|
+
"why": "Admin flag from request",
|
|
3163
|
+
"line": 5
|
|
3164
|
+
},
|
|
3165
|
+
{
|
|
3166
|
+
"file": "php-plain/admin/promote.php",
|
|
3167
|
+
"start_line": 6,
|
|
3168
|
+
"code": "$stmt = $db->prepare(\"UPDATE users SET role = 'admin' WHERE id = ?\");",
|
|
3169
|
+
"why": "Update without ownership check",
|
|
3170
|
+
"line": 6
|
|
3171
|
+
},
|
|
3172
|
+
{
|
|
3173
|
+
"file": "php-plain/admin/promote.php",
|
|
3174
|
+
"start_line": 7,
|
|
3175
|
+
"code": "$stmt->execute(array((int)$_POST['uid']));",
|
|
3176
|
+
"why": "Execute update",
|
|
3177
|
+
"line": 7
|
|
3178
|
+
}
|
|
3179
|
+
],
|
|
3180
|
+
"severity": "high",
|
|
3181
|
+
"confidence": "high",
|
|
3182
|
+
"cwe": [
|
|
3183
|
+
"CWE-639",
|
|
3184
|
+
"CWE-284"
|
|
3185
|
+
],
|
|
3186
|
+
"recommendation": "Bind update to current session user",
|
|
3187
|
+
"status": "confirmed",
|
|
3188
|
+
"verification": {
|
|
3189
|
+
"verdict": "confirmed",
|
|
3190
|
+
"reason_code": "traced",
|
|
3191
|
+
"checked": [
|
|
3192
|
+
"php-plain/admin/promote.php"
|
|
3193
|
+
],
|
|
3194
|
+
"control_found": null,
|
|
3195
|
+
"notes": "The code updates a user’s role based solely on a POST parameter without any ownership or role check. The only cast is to int for the user id, which does not provide authorization.",
|
|
3196
|
+
"suggested_subtype": null,
|
|
3197
|
+
"suggested_cwe": null
|
|
3198
|
+
},
|
|
3199
|
+
"fingerprint": "kfp1:c015ee6be1af117790c78fc9a97374926e8a34a36361142150be94c318ff9dd8",
|
|
3200
|
+
"baseline_state": "new"
|
|
3201
|
+
},
|
|
3202
|
+
{
|
|
3203
|
+
"finding_id": "BOLA-R-0069-order",
|
|
3204
|
+
"category": "bola",
|
|
3205
|
+
"subtype": "missing_ownership_check",
|
|
3206
|
+
"title": "BOLA in GET /orders/<int:order_id>: missing owner verification",
|
|
3207
|
+
"route_id": "R-0069",
|
|
3208
|
+
"endpoint": {
|
|
3209
|
+
"method": "GET",
|
|
3210
|
+
"path": "/orders/<int:order_id>"
|
|
3211
|
+
},
|
|
3212
|
+
"location": {
|
|
3213
|
+
"file": "python-flask/app.py",
|
|
3214
|
+
"start_line": 12
|
|
3215
|
+
},
|
|
3216
|
+
"evidence": [
|
|
3217
|
+
{
|
|
3218
|
+
"file": "python-flask/app.py",
|
|
3219
|
+
"start_line": 12,
|
|
3220
|
+
"code": "cur.execute(\"SELECT * FROM orders WHERE id = %s\" % order_id)",
|
|
3221
|
+
"why": "Query uses id without user ownership check",
|
|
3222
|
+
"line": 12
|
|
3223
|
+
}
|
|
3224
|
+
],
|
|
3225
|
+
"severity": "high",
|
|
3226
|
+
"confidence": "high",
|
|
3227
|
+
"cwe": [
|
|
3228
|
+
"CWE-639",
|
|
3229
|
+
"CWE-284"
|
|
3230
|
+
],
|
|
3231
|
+
"recommendation": "Bind query to current session user",
|
|
3232
|
+
"status": "confirmed",
|
|
3233
|
+
"verification": {
|
|
3234
|
+
"verdict": "confirmed",
|
|
3235
|
+
"reason_code": "traced",
|
|
3236
|
+
"checked": [
|
|
3237
|
+
"python-flask/app.py"
|
|
3238
|
+
],
|
|
3239
|
+
"control_found": null,
|
|
3240
|
+
"notes": "Although the route requires authentication, the query retrieves an order by id without verifying that the order belongs to the authenticated user.",
|
|
3241
|
+
"suggested_subtype": null,
|
|
3242
|
+
"suggested_cwe": null
|
|
3243
|
+
},
|
|
3244
|
+
"fingerprint": "kfp1:8cba56db899ed30b4e1dab440f085921515c324f8d9fff2d15ee38eb60afa641",
|
|
3245
|
+
"baseline_state": "new"
|
|
3246
|
+
},
|
|
3247
|
+
{
|
|
3248
|
+
"finding_id": "BOLA-R-0073",
|
|
3249
|
+
"category": "bola",
|
|
3250
|
+
"subtype": "missing_ownership_check",
|
|
3251
|
+
"title": "BOLA in POST /users/<int:uid>/name: missing owner verification",
|
|
3252
|
+
"route_id": "R-0073",
|
|
3253
|
+
"endpoint": {
|
|
3254
|
+
"method": "POST",
|
|
3255
|
+
"path": "/users/<int:uid>/name"
|
|
3256
|
+
},
|
|
3257
|
+
"location": {
|
|
3258
|
+
"file": "python-flask/profile.py",
|
|
3259
|
+
"start_line": 16
|
|
3260
|
+
},
|
|
3261
|
+
"evidence": [
|
|
3262
|
+
{
|
|
3263
|
+
"file": "python-flask/profile.py",
|
|
3264
|
+
"start_line": 16,
|
|
3265
|
+
"code": "def rename(uid):\n user = User.query.get(uid)\n user.name = request.json[\"name\"]\n db.session.commit()",
|
|
3266
|
+
"why": "The user ID comes from the URL and is used directly to load a user record without checking that the record belongs to the authenticated user.",
|
|
3267
|
+
"line": 16
|
|
3268
|
+
}
|
|
3269
|
+
],
|
|
3270
|
+
"severity": "high",
|
|
3271
|
+
"confidence": "high",
|
|
3272
|
+
"cwe": [
|
|
3273
|
+
"CWE-284",
|
|
3274
|
+
"CWE-639"
|
|
3275
|
+
],
|
|
3276
|
+
"recommendation": "Bind the update to the authenticated user.",
|
|
3277
|
+
"status": "confirmed",
|
|
3278
|
+
"verification": {
|
|
3279
|
+
"verdict": "confirmed",
|
|
3280
|
+
"reason_code": "traced",
|
|
3281
|
+
"checked": [
|
|
3282
|
+
"python-flask/profile.py"
|
|
3283
|
+
],
|
|
3284
|
+
"control_found": null,
|
|
3285
|
+
"notes": "The endpoint loads a user by the id from the URL and updates the name without checking that the user id matches the authenticated user.",
|
|
3286
|
+
"suggested_subtype": null,
|
|
3287
|
+
"suggested_cwe": null
|
|
3288
|
+
},
|
|
3289
|
+
"fingerprint": "kfp1:bfc179df51db588076982a9b160cccb6aa5f7c21b296231a88eb6cbdfe2c3842",
|
|
3290
|
+
"baseline_state": "new"
|
|
3291
|
+
},
|
|
3292
|
+
{
|
|
3293
|
+
"finding_id": "BOLA-R-0074",
|
|
3294
|
+
"category": "bola",
|
|
3295
|
+
"subtype": "missing_ownership_check",
|
|
3296
|
+
"title": "BOLA in PATCH /users/<int:uid>: missing owner verification",
|
|
3297
|
+
"route_id": "R-0074",
|
|
3298
|
+
"endpoint": {
|
|
3299
|
+
"method": "PATCH",
|
|
3300
|
+
"path": "/users/<int:uid>"
|
|
3301
|
+
},
|
|
3302
|
+
"location": {
|
|
3303
|
+
"file": "python-flask/profile.py",
|
|
3304
|
+
"start_line": 24
|
|
3305
|
+
},
|
|
3306
|
+
"evidence": [
|
|
3307
|
+
{
|
|
3308
|
+
"file": "python-flask/profile.py",
|
|
3309
|
+
"start_line": 24,
|
|
3310
|
+
"code": "def patch(uid):\n user = User.query.get(uid)\n for key, value in request.json.items():\n setattr(user, key, value)\n db.session.commit()",
|
|
3311
|
+
"why": "The user ID is taken from the URL and the record is updated without verifying ownership.",
|
|
3312
|
+
"line": 24
|
|
3313
|
+
}
|
|
3314
|
+
],
|
|
3315
|
+
"severity": "high",
|
|
3316
|
+
"confidence": "medium",
|
|
3317
|
+
"cwe": [
|
|
3318
|
+
"CWE-284",
|
|
3319
|
+
"CWE-639"
|
|
3320
|
+
],
|
|
3321
|
+
"recommendation": "Ensure the target user belongs to the authenticated session.",
|
|
3322
|
+
"status": "likely",
|
|
3323
|
+
"verification": {
|
|
3324
|
+
"verdict": "likely",
|
|
3325
|
+
"reason_code": "code_not_visible",
|
|
3326
|
+
"checked": [
|
|
3327
|
+
"python-flask/profile.py: lines 24-30"
|
|
3328
|
+
],
|
|
3329
|
+
"control_found": null,
|
|
3330
|
+
"notes": "The PATCH handler updates the user record directly from the request JSON without any visible ownership check or cast. No role or global filter is shown in the provided context.",
|
|
3331
|
+
"suggested_subtype": null,
|
|
3332
|
+
"suggested_cwe": null
|
|
3333
|
+
},
|
|
3334
|
+
"fingerprint": "kfp1:53120a82329f249cb5d921adbb2d6965297c52b37440e5f47d8a2525bbe46fde",
|
|
3335
|
+
"baseline_state": "new"
|
|
3336
|
+
},
|
|
3337
|
+
{
|
|
3338
|
+
"finding_id": "MASS-M-0011-1",
|
|
3339
|
+
"category": "mass_assignment",
|
|
3340
|
+
"subtype": "privileged_field_writable",
|
|
3341
|
+
"title": "Profile update allows role change",
|
|
3342
|
+
"candidate_id": "M-0011",
|
|
3343
|
+
"location": {
|
|
3344
|
+
"file": "php-plain/profile.php",
|
|
3345
|
+
"start_line": 6
|
|
3346
|
+
},
|
|
3347
|
+
"evidence": [
|
|
3348
|
+
{
|
|
3349
|
+
"file": "php-plain/profile.php",
|
|
3350
|
+
"line": 10,
|
|
3351
|
+
"why": "$user->role = $_POST['role']; no restriction on role field"
|
|
3352
|
+
}
|
|
3353
|
+
],
|
|
3354
|
+
"impact": "Privilege escalation via role field",
|
|
3355
|
+
"severity": "high",
|
|
3356
|
+
"confidence": "high",
|
|
3357
|
+
"cwe": [
|
|
3358
|
+
"CWE-915"
|
|
3359
|
+
],
|
|
3360
|
+
"recommendation": "Do not bind role field from request; set role server‑side only",
|
|
3361
|
+
"status": "confirmed",
|
|
3362
|
+
"verification": {
|
|
3363
|
+
"verdict": "confirmed",
|
|
3364
|
+
"reason_code": "traced",
|
|
3365
|
+
"checked": [
|
|
3366
|
+
"php-plain/profile.php",
|
|
3367
|
+
"php-plain/inc/auth.php",
|
|
3368
|
+
"php-plain/inc/db.php"
|
|
3369
|
+
],
|
|
3370
|
+
"control_found": null,
|
|
3371
|
+
"notes": "The code assigns $_POST['role'] directly to $user->role without any restriction, allowing privilege escalation.",
|
|
3372
|
+
"suggested_subtype": null,
|
|
3373
|
+
"suggested_cwe": null
|
|
3374
|
+
},
|
|
3375
|
+
"fingerprint": "kfp1:81701ee31537d09fc4ae8bdcf69ee09e4b7209ec647bdb0a30fdd9a541c42a79",
|
|
3376
|
+
"baseline_state": "new"
|
|
3377
|
+
},
|
|
3378
|
+
{
|
|
3379
|
+
"finding_id": "INJ-I-0005",
|
|
3380
|
+
"category": "sql_injection",
|
|
3381
|
+
"subtype": "string_concatenation",
|
|
3382
|
+
"title": "SQL Injection in classic-asp/shop/order.asp:12",
|
|
3383
|
+
"candidate_id": "I-0005",
|
|
3384
|
+
"location": {
|
|
3385
|
+
"file": "classic-asp/shop/order.asp",
|
|
3386
|
+
"start_line": 12
|
|
3387
|
+
},
|
|
3388
|
+
"evidence": [
|
|
3389
|
+
{
|
|
3390
|
+
"file": "classic-asp/shop/order.asp",
|
|
3391
|
+
"start_line": 12,
|
|
3392
|
+
"code": "Set rs2 = conn.Execute(\"SELECT * FROM orders WHERE id = \" & sid & \" AND user_id = \" & CLng(Session(\"UserID\")))",
|
|
3393
|
+
"why": "sid from Request.QueryString(\"sid\") concatenated without sanitization",
|
|
3394
|
+
"line": 12
|
|
3395
|
+
}
|
|
3396
|
+
],
|
|
3397
|
+
"severity": "critical",
|
|
3398
|
+
"confidence": "high",
|
|
3399
|
+
"cwe": [
|
|
3400
|
+
"CWE-89"
|
|
3401
|
+
],
|
|
3402
|
+
"recommendation": "Use parameterized queries",
|
|
3403
|
+
"status": "rejected",
|
|
3404
|
+
"verification": {
|
|
3405
|
+
"verdict": "rejected",
|
|
3406
|
+
"reason_code": "control_found",
|
|
3407
|
+
"checked": [
|
|
3408
|
+
"classic-asp/shop/order.asp line 11 (sid cast)",
|
|
3409
|
+
"classic-asp/shop/order.asp line 12 (user_id cast)",
|
|
3410
|
+
"classic-asp/shop/order.asp line 12 (query execution)"
|
|
3411
|
+
],
|
|
3412
|
+
"control_found": {
|
|
3413
|
+
"file": "classic-asp/shop/order.asp",
|
|
3414
|
+
"line": 11,
|
|
3415
|
+
"code": "sid = CLng(Request.QueryString(\"sid\"))"
|
|
3416
|
+
},
|
|
3417
|
+
"notes": "Both the order id and user id are cast to integers before concatenation, preventing SQL injection.",
|
|
3418
|
+
"suggested_subtype": null,
|
|
3419
|
+
"suggested_cwe": null
|
|
3420
|
+
},
|
|
3421
|
+
"fingerprint": "kfp1:e2716780282320839bea274168fbf79466e379ba46017b4d17ab8ce1703c7742"
|
|
3422
|
+
}
|
|
3423
|
+
]
|
|
3424
|
+
}
|