@hoanghainh/komagu 1.8.0 → 2.0.1

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.
Files changed (210) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/assess/lsa/CHANGELOG.md +6 -0
  4. package/assess/lsa/VERSION +1 -1
  5. package/assess/lsa/adapters/build_adapters.py +16 -8
  6. package/assess/lsa/adapters/codex/README.md +1 -1
  7. package/assess/lsa/adapters/generic/README.md +1 -1
  8. package/assess/lsa/examples/eval-run-4/ground-truth.json +823 -0
  9. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/ai-run-stats.json +58 -0
  10. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/coverage.json +85 -0
  11. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings/priv-privilege-001.json +822 -0
  12. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings/priv-privilege-002.json +393 -0
  13. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/findings.json +4477 -0
  14. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/mass-assignment.candidates.json +232 -0
  15. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-001.json +425 -0
  16. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-002.json +333 -0
  17. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-003.json +400 -0
  18. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-004.json +403 -0
  19. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-005.json +398 -0
  20. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/routes/routes-006.json +63 -0
  21. package/assess/lsa/examples/eval-run-4/iter0-gptoss-a/score.json +120 -0
  22. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/ai-run-stats.json +55 -0
  23. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/coverage.json +50 -0
  24. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings/priv-privilege-001.json +613 -0
  25. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings/priv-privilege-002.json +287 -0
  26. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/findings.json +4870 -0
  27. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/mass-assignment.candidates.json +232 -0
  28. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-001.json +425 -0
  29. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-002.json +333 -0
  30. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-003.json +400 -0
  31. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-004.json +403 -0
  32. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-005.json +398 -0
  33. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/routes/routes-006.json +63 -0
  34. package/assess/lsa/examples/eval-run-4/iter1-gptoss-a/score.json +107 -0
  35. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/ai-run-stats.json +58 -0
  36. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/coverage.json +92 -0
  37. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings/priv-privilege-001.json +645 -0
  38. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings/priv-privilege-002.json +222 -0
  39. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/findings.json +4859 -0
  40. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/mass-assignment.candidates.json +232 -0
  41. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-001.json +425 -0
  42. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-002.json +333 -0
  43. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-003.json +400 -0
  44. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-004.json +403 -0
  45. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-005.json +398 -0
  46. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/routes/routes-006.json +63 -0
  47. package/assess/lsa/examples/eval-run-4/iter1-gptoss-b/score.json +121 -0
  48. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/coverage.json +111 -0
  49. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings/priv-privilege-001.json +6 -0
  50. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings/priv-privilege-002.json +344 -0
  51. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/findings.json +3544 -0
  52. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/mass-assignment.candidates.json +232 -0
  53. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-001.json +425 -0
  54. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-002.json +333 -0
  55. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-003.json +400 -0
  56. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-004.json +403 -0
  57. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-005.json +398 -0
  58. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/routes/routes-006.json +63 -0
  59. package/assess/lsa/examples/eval-run-4/iter1-qwen-a-incomplete/score.json +123 -0
  60. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/ai-run-stats.json +50 -0
  61. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/coverage.json +42 -0
  62. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings/priv-privilege-001.json +540 -0
  63. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings/priv-privilege-002.json +238 -0
  64. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings.json +4383 -0
  65. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/findings.sarif +8729 -0
  66. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/mass-assignment.candidates.json +232 -0
  67. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/report.ja.md +1911 -0
  68. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/report.md +1911 -0
  69. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-001.json +425 -0
  70. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-002.json +333 -0
  71. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-003.json +400 -0
  72. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-004.json +403 -0
  73. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-005.json +398 -0
  74. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/routes/routes-006.json +63 -0
  75. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/score.json +101 -0
  76. package/assess/lsa/examples/eval-run-4/iter2-gptoss-a/stack-profile.json +226 -0
  77. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/ai-run-stats.json +54 -0
  78. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/coverage.json +66 -0
  79. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings/priv-privilege-001.json +440 -0
  80. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings/priv-privilege-002.json +229 -0
  81. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/findings.json +3424 -0
  82. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/mass-assignment.candidates.json +232 -0
  83. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-001.json +425 -0
  84. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-002.json +333 -0
  85. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-003.json +400 -0
  86. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-004.json +403 -0
  87. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-005.json +398 -0
  88. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/routes/routes-006.json +63 -0
  89. package/assess/lsa/examples/eval-run-4/iter2-gptoss-b/score.json +120 -0
  90. package/assess/lsa/examples/eval-run-5/gptoss-a/ai-run-stats.json +88 -0
  91. package/assess/lsa/examples/eval-run-5/gptoss-a/coverage.json +36 -0
  92. package/assess/lsa/examples/eval-run-5/gptoss-a/findings/priv-privilege-001.json +530 -0
  93. package/assess/lsa/examples/eval-run-5/gptoss-a/findings/priv-privilege-002.json +248 -0
  94. package/assess/lsa/examples/eval-run-5/gptoss-a/findings.json +4766 -0
  95. package/assess/lsa/examples/eval-run-5/gptoss-a/findings.sarif +9326 -0
  96. package/assess/lsa/examples/eval-run-5/gptoss-a/mass-assignment.candidates.json +232 -0
  97. package/assess/lsa/examples/eval-run-5/gptoss-a/report.ja.md +2011 -0
  98. package/assess/lsa/examples/eval-run-5/gptoss-a/report.md +2011 -0
  99. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-001.json +425 -0
  100. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-002.json +333 -0
  101. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-003.json +400 -0
  102. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-004.json +403 -0
  103. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-005.json +398 -0
  104. package/assess/lsa/examples/eval-run-5/gptoss-a/routes/routes-006.json +63 -0
  105. package/assess/lsa/examples/eval-run-5/gptoss-a/score.json +80 -0
  106. package/assess/lsa/examples/eval-run-5/gptoss-a/stack-profile.json +226 -0
  107. package/assess/lsa/examples/eval-run-5/gptoss-b/ai-run-stats.json +83 -0
  108. package/assess/lsa/examples/eval-run-5/gptoss-b/coverage.json +44 -0
  109. package/assess/lsa/examples/eval-run-5/gptoss-b/findings/priv-privilege-001.json +579 -0
  110. package/assess/lsa/examples/eval-run-5/gptoss-b/findings/priv-privilege-002.json +268 -0
  111. package/assess/lsa/examples/eval-run-5/gptoss-b/findings.json +3913 -0
  112. package/assess/lsa/examples/eval-run-5/gptoss-b/mass-assignment.candidates.json +232 -0
  113. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-001.json +425 -0
  114. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-002.json +333 -0
  115. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-003.json +400 -0
  116. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-004.json +403 -0
  117. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-005.json +398 -0
  118. package/assess/lsa/examples/eval-run-5/gptoss-b/routes/routes-006.json +63 -0
  119. package/assess/lsa/examples/eval-run-5/gptoss-b/score.json +94 -0
  120. package/assess/lsa/examples/eval-run-5/ground-truth.json +823 -0
  121. package/assess/lsa/knowledge/severity-and-cwe.md +1 -1
  122. package/assess/lsa/prompts/35-privilege-auditor.md +3 -1
  123. package/assess/lsa/scripts/baseline.py +5 -2
  124. package/assess/lsa/scripts/findings_to_sarif.py +24 -1
  125. package/assess/lsa/tests/EVAL-RESULTS.md +156 -0
  126. package/assess/lsa/tests/score_findings.py +58 -0
  127. package/assess/lsa/tests/test_adapters.py +21 -2
  128. package/assess/lsa/tests/test_baseline.py +8 -0
  129. package/assess/lsa/tests/test_contract_groundwork.py +7 -7
  130. package/assess/lsa/tests/test_eval_run_4.py +73 -0
  131. package/assess/lsa/tests/test_eval_run_5.py +73 -0
  132. package/assess/lsa/tests/test_privilege_tier2.py +30 -0
  133. package/operate/ai/anchoring.py +130 -0
  134. package/operate/ai/client.py +13 -0
  135. package/operate/ai/context.py +105 -0
  136. package/operate/ai/runner.py +197 -69
  137. package/operate/cli/__init__.py +1 -1
  138. package/operate/cli/commands/scan.py +3 -8
  139. package/operate/cli/commands/test.py +1 -1
  140. package/operate/cli/env.py +4 -20
  141. package/operate/cross_user_tester/persona_matrix.py +5 -1
  142. package/operate/devsecops/pipeline.py +5 -5
  143. package/operate/exploit/generator.py +5 -1
  144. package/operate/lsa_sarif/lsa_to_sarif.py +24 -2
  145. package/operate/lsa_sarif/sarif_findings.py +96 -0
  146. package/operate/remediator/runner.py +1 -5
  147. package/operate/remediator/strategies.py +1 -1
  148. package/operate/tests/test_ai_anchoring.py +184 -0
  149. package/operate/tests/test_cli_baseline.py +1 -9
  150. package/operate/tests/test_cli_env.py +8 -29
  151. package/operate/tests/test_cross_user_pipeline.py +2 -2
  152. package/operate/tests/test_exploit_and_virtual_patch.py +3 -3
  153. package/operate/tests/test_headless_ai.py +148 -1
  154. package/operate/tests/test_npm_package.py +2 -16
  155. package/operate/tests/test_sarif_from_scan.py +156 -0
  156. package/package.json +2 -4
  157. package/remediate/authz/README.md +1 -1
  158. package/remediate/authz/dotnet/src/Komagu.Security.Authorization/DefaultKomaguAuthorizationService.cs +1 -1
  159. package/remediate/authz/dotnet/src/Komagu.Security.Authorization/SecurityAuditEvent.cs +2 -2
  160. package/remediate/authz/golang/authz.go +1 -1
  161. package/remediate/authz/nodejs/src/service.js +1 -1
  162. package/remediate/authz/nodejs/tests/test-authz.js +1 -1
  163. package/remediate/authz/patcher.py +3 -4
  164. package/remediate/authz/python/komagu_authz/models.py +2 -2
  165. package/remediate/authz/python/tests/test_fastapi_adapter.py +1 -1
  166. package/remediate/authz/python/tests/test_fastapi_d5_crosstest.py +1 -1
  167. package/remediate/authz/python/tests/test_python_authz.py +3 -3
  168. package/remediate/authz/spring/src/main/kotlin/io/komagu/security/authorization/DefaultKomaguSecurityManager.kt +1 -1
  169. package/remediate/authz/spring/src/main/kotlin/io/komagu/security/authorization/SecurityAuditEvent.kt +1 -2
  170. package/remediate/authz/tests/test_bola_patcher.py +1 -1
  171. package/remediate/edge/coraza/rules/coraza-crs-custom.conf +3 -4
  172. package/remediate/edge/coraza/virtual_patcher.py +4 -6
  173. package/remediate/edge/docker-compose.yml +1 -1
  174. package/remediate/ekyc/server/jpki_verifier.py +2 -8
  175. package/remediate/ekyc/server/tokenization.py +2 -8
  176. package/remediate/identity/README.md +5 -5
  177. package/remediate/identity/dotnet/src/Komagu.Security.Identity/KomaguOidcOptions.cs +2 -2
  178. package/remediate/identity/dotnet/tests/Komagu.Security.Identity.Tests/TestTokenGenerator.cs +1 -1
  179. package/remediate/identity/dotnet/tests/Komagu.Security.Identity.Tests/TokenValidationTests.cs +1 -1
  180. package/remediate/identity/python/komagu_identity/oidc_validator.py +2 -8
  181. package/remediate/identity/python/tests/test_oidc_validator.py +1 -1
  182. package/remediate/identity/spring/src/main/kotlin/io/komagu/security/identity/KomaguOidcProperties.kt +2 -2
  183. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/KomaguIdentityAutoConfigurationTest.kt +2 -2
  184. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/TestJwtFactory.kt +1 -1
  185. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/TokenValidationIntegrationTest.kt +1 -1
  186. package/remediate/identity/test-env/realm-komagu.json +1 -1
  187. package/remediate/legacy_shims/coldfusion/KomaguSecurityShim.cfc +5 -5
  188. package/remediate/query/README.md +1 -1
  189. package/remediate/query/dotnet/src/Komagu.Security.Query.Analyzers/DiagnosticIds.cs +1 -1
  190. package/remediate/query/dotnet/src/Komagu.Security.Query.Analyzers/Komagu.Security.Query.Analyzers.csproj +1 -1
  191. package/remediate/query/spring/src/main/kotlin/io/komagu/security/query/detekt/KomaguRuleSetProvider.kt +1 -1
  192. package/remediate/resilience/dr/dr_manager.py +2 -8
  193. package/remediate/resilience/dr/runbook.md +2 -2
  194. package/remediate/resilience/terraform/variables.tf +1 -1
  195. package/remediate/tenancy/audit/audit_trail.py +2 -8
  196. package/remediate/tenancy/crypto/byok_manager.py +2 -8
  197. package/remediate/tenancy/middleware/tenant_context.py +2 -8
  198. package/remediate/tenancy/sql/rls_isolation.sql +11 -11
  199. package/remediate/tenancy/sql/schema_per_tenant.sql +7 -7
  200. package/remediate/tenancy/test_sql_postgres.py +1 -1
  201. package/remediate/tenancy/tests/test_tenancy.py +4 -4
  202. package/bin/komainu +0 -16
  203. package/bin/komainu-legacy.js +0 -16
  204. package/remediate/ekyc/tests/test_legacy_env.py +0 -33
  205. package/remediate/identity/python/tests/test_legacy_env.py +0 -33
  206. package/remediate/identity/spring/src/main/kotlin/io/komagu/security/identity/LegacyKomainuPropertiesPostProcessor.kt +0 -60
  207. package/remediate/identity/spring/src/main/resources/META-INF/spring.factories +0 -2
  208. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/LegacyKomainuPropertiesPostProcessorTest.kt +0 -86
  209. package/remediate/resilience/tests/test_legacy_env.py +0 -33
  210. package/remediate/tenancy/tests/test_legacy_env.py +0 -49
@@ -0,0 +1,4383 @@
1
+ {
2
+ "generated_by": "lsa merge_findings.py 0.3.1",
3
+ "summary": {
4
+ "total_reported": 97,
5
+ "active": 96,
6
+ "rejected_by_verifier": 1,
7
+ "by_severity": {
8
+ "critical": 51,
9
+ "high": 45,
10
+ "medium": 0,
11
+ "low": 0,
12
+ "info": 0
13
+ },
14
+ "by_category": {
15
+ "bola": 45,
16
+ "sql_injection": 30,
17
+ "nosql_injection": 1,
18
+ "bfla": 12,
19
+ "mass_assignment": 8
20
+ },
21
+ "by_status": {
22
+ "unverified": 0,
23
+ "confirmed": 41,
24
+ "likely": 55,
25
+ "rejected": 1,
26
+ "needs_review": 0
27
+ }
28
+ },
29
+ "findings": [
30
+ {
31
+ "finding_id": "BFLA-R-0003-1",
32
+ "category": "bfla",
33
+ "subtype": "missing_role_check",
34
+ "title": "Unrestricted member deletion in classic‑ASP",
35
+ "route_id": "R-0003",
36
+ "location": {
37
+ "file": "classic-asp/shop/member.asp",
38
+ "start_line": 1
39
+ },
40
+ "evidence": [
41
+ {
42
+ "file": "classic-asp/shop/member.asp",
43
+ "line": 10,
44
+ "why": "DELETE FROM members WHERE member_id = ... (privileged action, no role check)"
45
+ },
46
+ {
47
+ "file": "classic-asp/shop/member.asp",
48
+ "line": 9,
49
+ "why": "no role check before the delete"
50
+ }
51
+ ],
52
+ "impact": "Any authenticated user can delete any member record.",
53
+ "severity": "critical",
54
+ "confidence": "medium",
55
+ "cwe": [
56
+ "CWE-285"
57
+ ],
58
+ "recommendation": "Add a server‑side check that the current user has admin privileges before executing the delete.",
59
+ "status": "likely",
60
+ "verification": {
61
+ "verdict": "likely",
62
+ "reason_code": "code_not_visible",
63
+ "checked": [
64
+ "classic-asp/shop/member.asp lines 1-12",
65
+ "included inc/auth.asp lines 1-3",
66
+ "included inc/conn.asp lines 1-4"
67
+ ],
68
+ "control_found": null,
69
+ "notes": "The DELETE statement is executed without any role or ownership check. The included auth file only verifies authentication, not authorization.",
70
+ "suggested_subtype": null,
71
+ "suggested_cwe": null
72
+ },
73
+ "fingerprint": "kfp1:36414a17d1cfcd365c5e184c7077c68dbf44f76e203f7e2b3728d6b2b9ae7adf",
74
+ "baseline_state": "new"
75
+ },
76
+ {
77
+ "finding_id": "BFLA-R-0007-1",
78
+ "category": "bfla",
79
+ "subtype": "missing_role_check",
80
+ "title": "Unauthenticated user can delete any user in ASP.NET MVC",
81
+ "route_id": "R-0007",
82
+ "location": {
83
+ "file": "Web/Controllers/AdminController.cs",
84
+ "start_line": 1
85
+ },
86
+ "evidence": [
87
+ {
88
+ "file": "Web/Controllers/AdminController.cs",
89
+ "line": 14,
90
+ "why": "db.Users.Remove(u); (privileged action, no role check)"
91
+ },
92
+ {
93
+ "file": "Web/Controllers/AdminController.cs",
94
+ "line": 12,
95
+ "why": "no [Authorize(Roles=\"Admin\")] on DeleteUser"
96
+ }
97
+ ],
98
+ "impact": "Any authenticated user can delete any account.",
99
+ "severity": "critical",
100
+ "confidence": "medium",
101
+ "cwe": [
102
+ "CWE-285"
103
+ ],
104
+ "recommendation": "Add [Authorize(Roles=\"Admin\")] to DeleteUser or enforce role check in code.",
105
+ "status": "likely",
106
+ "verification": {
107
+ "verdict": "likely",
108
+ "reason_code": "code_not_visible",
109
+ "checked": [
110
+ "no code_context provided for Web/Controllers/AdminController.cs"
111
+ ],
112
+ "control_found": null,
113
+ "notes": "The file containing the DeleteUser action is missing from the provided context, so no authorization check can be verified.",
114
+ "suggested_subtype": null,
115
+ "suggested_cwe": null
116
+ },
117
+ "fingerprint": "kfp1:3b5fdd60b26873c932b9f5ab2453c29648414bc2f8ceaa8c68b3788497904098",
118
+ "baseline_state": "new"
119
+ },
120
+ {
121
+ "finding_id": "BFLA-R-0009-1",
122
+ "category": "bfla",
123
+ "subtype": "role_from_request",
124
+ "title": "Export endpoint controlled by request parameter in ASP.NET MVC",
125
+ "route_id": "R-0009",
126
+ "location": {
127
+ "file": "Web/Controllers/AdminController.cs",
128
+ "start_line": 1
129
+ },
130
+ "evidence": [
131
+ {
132
+ "file": "Web/Controllers/AdminController.cs",
133
+ "line": 32,
134
+ "why": "if (Request.QueryString[\"isAdmin\"] == \"true\") return Json(db.Users.ToList());"
135
+ },
136
+ {
137
+ "file": "Web/Controllers/AdminController.cs",
138
+ "line": 30,
139
+ "why": "no role check before the export"
140
+ }
141
+ ],
142
+ "impact": "Any authenticated user can export all user data by setting isAdmin=true.",
143
+ "severity": "critical",
144
+ "confidence": "medium",
145
+ "cwe": [
146
+ "CWE-269",
147
+ "CWE-285"
148
+ ],
149
+ "recommendation": "Validate the caller's role server‑side before returning the data.",
150
+ "status": "likely",
151
+ "verification": {
152
+ "verdict": "likely",
153
+ "reason_code": "code_not_visible",
154
+ "checked": [
155
+ "no code_context provided for Web/Controllers/AdminController.cs"
156
+ ],
157
+ "control_found": null,
158
+ "notes": "The export endpoint code is not available; cannot confirm presence or absence of role validation.",
159
+ "suggested_subtype": null,
160
+ "suggested_cwe": null
161
+ },
162
+ "fingerprint": "kfp1:cb45e9ea87a2f34967c7a1ed0e22e0aa83c0c9af109e7fff960b3714390b1ff9",
163
+ "baseline_state": "new"
164
+ },
165
+ {
166
+ "finding_id": "BFLA-R-0023-1",
167
+ "category": "bfla",
168
+ "subtype": "missing_role_check",
169
+ "title": "Unprotected user deletion in Spring MVC",
170
+ "route_id": "R-0023",
171
+ "location": {
172
+ "file": "com/acme/web/AdminUserController.java",
173
+ "start_line": 1
174
+ },
175
+ "evidence": [
176
+ {
177
+ "file": "com/acme/web/AdminUserController.java",
178
+ "line": 15,
179
+ "why": "userDao.deleteById(id); (privileged action, no role check)"
180
+ },
181
+ {
182
+ "file": "com/acme/web/AdminUserController.java",
183
+ "line": 13,
184
+ "why": "no @PreAuthorize on delete method"
185
+ }
186
+ ],
187
+ "impact": "Any authenticated user can delete any user.",
188
+ "severity": "critical",
189
+ "confidence": "medium",
190
+ "cwe": [
191
+ "CWE-285"
192
+ ],
193
+ "recommendation": "Add @PreAuthorize(\"hasRole('ADMIN')\") to the delete method.",
194
+ "status": "likely",
195
+ "verification": {
196
+ "verdict": "likely",
197
+ "reason_code": "code_not_visible",
198
+ "checked": [
199
+ "no code_context provided for com/acme/web/AdminUserController.java"
200
+ ],
201
+ "control_found": null,
202
+ "notes": "The controller file is missing from the context; no evidence of a role check is visible.",
203
+ "suggested_subtype": null,
204
+ "suggested_cwe": null
205
+ },
206
+ "fingerprint": "kfp1:f785e7cf0a2c37f37c9a2b8fe045e13f226fcb924338f3a812a78df91a2eee3a",
207
+ "baseline_state": "new"
208
+ },
209
+ {
210
+ "finding_id": "BFLA-R-0030-1",
211
+ "category": "bfla",
212
+ "subtype": "missing_role_check",
213
+ "title": "Unprotected user deletion in Express.js",
214
+ "route_id": "R-0030",
215
+ "location": {
216
+ "file": "routes.js",
217
+ "start_line": 1
218
+ },
219
+ "evidence": [
220
+ {
221
+ "file": "routes.js",
222
+ "line": 9,
223
+ "why": "User.deleteOne({ _id: req.params.id }) (privileged action, no admin check)"
224
+ },
225
+ {
226
+ "file": "routes.js",
227
+ "line": 8,
228
+ "why": "ensureLoggedIn only, no requireAdmin"
229
+ }
230
+ ],
231
+ "impact": "Any authenticated user can delete any user.",
232
+ "severity": "critical",
233
+ "confidence": "medium",
234
+ "cwe": [
235
+ "CWE-285"
236
+ ],
237
+ "recommendation": "Add a server‑side admin check before the delete operation.",
238
+ "status": "likely",
239
+ "verification": {
240
+ "verdict": "likely",
241
+ "reason_code": "code_not_visible",
242
+ "checked": [
243
+ "routes.js not present in code_context"
244
+ ],
245
+ "control_found": null,
246
+ "notes": "The code_context for routes.js is missing; no evidence of a role check or other compensating control can be examined.",
247
+ "suggested_subtype": null,
248
+ "suggested_cwe": null
249
+ },
250
+ "fingerprint": "kfp1:377fc1d213bc0b3a306e89b1d0c8bf44eca825527752ad7f5c36b47c2b5fb8b1",
251
+ "baseline_state": "new"
252
+ },
253
+ {
254
+ "finding_id": "BFLA-R-0032-1",
255
+ "category": "bfla",
256
+ "subtype": "role_from_request",
257
+ "title": "Export endpoint controlled by query param in Express.js",
258
+ "route_id": "R-0032",
259
+ "location": {
260
+ "file": "routes.js",
261
+ "start_line": 1
262
+ },
263
+ "evidence": [
264
+ {
265
+ "file": "routes.js",
266
+ "line": 17,
267
+ "why": "res.json([]) when req.query.isAdmin === 'true' (privileged action, no role check)"
268
+ },
269
+ {
270
+ "file": "routes.js",
271
+ "line": 16,
272
+ "why": "ensureLoggedIn only, no admin check"
273
+ }
274
+ ],
275
+ "impact": "Any authenticated user can export all users by setting isAdmin=true.",
276
+ "severity": "critical",
277
+ "confidence": "medium",
278
+ "cwe": [
279
+ "CWE-269",
280
+ "CWE-285"
281
+ ],
282
+ "recommendation": "Validate the caller's role server‑side before returning data.",
283
+ "status": "likely",
284
+ "verification": {
285
+ "verdict": "likely",
286
+ "reason_code": "code_not_visible",
287
+ "checked": [
288
+ "routes.js not present in code_context"
289
+ ],
290
+ "control_found": null,
291
+ "notes": "The code_context for routes.js is missing; no evidence of a role check or other compensating control can be examined.",
292
+ "suggested_subtype": null,
293
+ "suggested_cwe": null
294
+ },
295
+ "fingerprint": "kfp1:59101199ac1a8a5c2a5a73c5219ce5422207daba79953f968fbdebb4e79725b1",
296
+ "baseline_state": "new"
297
+ },
298
+ {
299
+ "finding_id": "BFLA-R-0057-1",
300
+ "category": "bfla",
301
+ "subtype": "missing_role_check",
302
+ "title": "Unprotected user view in PHP plain",
303
+ "route_id": "R-0057",
304
+ "location": {
305
+ "file": "php-plain/admin.php",
306
+ "start_line": 1
307
+ },
308
+ "evidence": [
309
+ {
310
+ "file": "php-plain/admin.php",
311
+ "line": 8,
312
+ "why": "SELECT * FROM users WHERE id = ... (privileged action, no role check)"
313
+ },
314
+ {
315
+ "file": "php-plain/admin.php",
316
+ "line": 6,
317
+ "why": "no role check before the query"
318
+ }
319
+ ],
320
+ "impact": "Any authenticated user can view any user record.",
321
+ "severity": "critical",
322
+ "confidence": "high",
323
+ "cwe": [
324
+ "CWE-285"
325
+ ],
326
+ "recommendation": "Add a server‑side admin check before executing the query.",
327
+ "status": "confirmed",
328
+ "verification": {
329
+ "verdict": "confirmed",
330
+ "reason_code": "traced",
331
+ "checked": [
332
+ "php-plain/admin.php lines 1-14",
333
+ "php-plain/inc/auth.php lines 1-7"
334
+ ],
335
+ "control_found": null,
336
+ "notes": "The script performs a SELECT on users by id without any admin or ownership check. Only a login check is present in inc/auth.php.",
337
+ "suggested_subtype": null,
338
+ "suggested_cwe": null
339
+ },
340
+ "fingerprint": "kfp1:e2f3e7a9252fd930e1249cde8888d01381209af16be4563f15b79cdf7828f9c2",
341
+ "baseline_state": "new"
342
+ },
343
+ {
344
+ "finding_id": "BFLA-R-0058-1",
345
+ "category": "bfla",
346
+ "subtype": "missing_role_check",
347
+ "title": "Unprotected user deletion in PHP plain",
348
+ "route_id": "R-0058",
349
+ "location": {
350
+ "file": "php-plain/admin.php",
351
+ "start_line": 1
352
+ },
353
+ "evidence": [
354
+ {
355
+ "file": "php-plain/admin.php",
356
+ "line": 12,
357
+ "why": "DELETE FROM users WHERE id = $id (privileged action, no role check)"
358
+ },
359
+ {
360
+ "file": "php-plain/admin.php",
361
+ "line": 10,
362
+ "why": "no role check before the delete"
363
+ }
364
+ ],
365
+ "impact": "Any authenticated user can delete any user.",
366
+ "severity": "critical",
367
+ "confidence": "high",
368
+ "cwe": [
369
+ "CWE-285"
370
+ ],
371
+ "recommendation": "Add a server‑side admin check before executing the delete.",
372
+ "status": "confirmed",
373
+ "verification": {
374
+ "verdict": "confirmed",
375
+ "reason_code": "traced",
376
+ "checked": [
377
+ "php-plain/admin.php lines 1-14",
378
+ "php-plain/inc/auth.php lines 1-7"
379
+ ],
380
+ "control_found": null,
381
+ "notes": "The DELETE statement is executed without any admin or ownership check. Only a login check is present in inc/auth.php.",
382
+ "suggested_subtype": null,
383
+ "suggested_cwe": null
384
+ },
385
+ "fingerprint": "kfp1:a22714e56eb601967ec1563ec7f235676d6d0ea4b7a35231e16bedc5c67f18e2",
386
+ "baseline_state": "new"
387
+ },
388
+ {
389
+ "finding_id": "BFLA-R-0059-1",
390
+ "category": "bfla",
391
+ "subtype": "client_side_role_check",
392
+ "title": "Client‑side role check only in PHP plain",
393
+ "route_id": "R-0059",
394
+ "location": {
395
+ "file": "php-plain/manage_users.php",
396
+ "start_line": 1
397
+ },
398
+ "evidence": [
399
+ {
400
+ "file": "php-plain/manage_users.php",
401
+ "line": 6,
402
+ "why": "DELETE FROM users WHERE id = ? (privileged action, no server‑side role check)"
403
+ },
404
+ {
405
+ "file": "php-plain/manage_users.php",
406
+ "line": 11,
407
+ "why": "role check only in HTML output, not in code"
408
+ }
409
+ ],
410
+ "impact": "Any authenticated user can delete any user.",
411
+ "severity": "critical",
412
+ "confidence": "high",
413
+ "cwe": [
414
+ "CWE-602",
415
+ "CWE-285"
416
+ ],
417
+ "recommendation": "Add a server‑side admin check before executing the delete.",
418
+ "status": "confirmed",
419
+ "verification": {
420
+ "verdict": "confirmed",
421
+ "reason_code": "traced",
422
+ "checked": [
423
+ "php-plain/manage_users.php",
424
+ "php-plain/inc/auth.php"
425
+ ],
426
+ "control_found": null,
427
+ "notes": "The DELETE statement is executed for any authenticated user. The only role check present is in the HTML output, which does not prevent the server from executing the delete. No server‑side admin check is visible.",
428
+ "suggested_subtype": null,
429
+ "suggested_cwe": null
430
+ },
431
+ "fingerprint": "kfp1:46a95c25c9fdd0024572d331fd6b49713b18fd6e351df3afa986ca37372da405",
432
+ "baseline_state": "new"
433
+ },
434
+ {
435
+ "finding_id": "BFLA-R-0063-1",
436
+ "category": "bfla",
437
+ "subtype": "role_from_request",
438
+ "title": "Privilege escalation via role field in PHP plain profile update",
439
+ "route_id": "R-0063",
440
+ "location": {
441
+ "file": "php-plain/profile.php",
442
+ "start_line": 1
443
+ },
444
+ "evidence": [
445
+ {
446
+ "file": "php-plain/profile.php",
447
+ "line": 6,
448
+ "why": "foreach ($_POST as $field => $value) { $user->$field = $value; } (whole object binding)"
449
+ },
450
+ {
451
+ "file": "php-plain/profile.php",
452
+ "line": 10,
453
+ "why": "$user->role = $_POST['role']; (privileged field)"
454
+ },
455
+ {
456
+ "file": "php-plain/profile.php",
457
+ "line": 11,
458
+ "why": "save_user($user); (writes role to DB)"
459
+ }
460
+ ],
461
+ "impact": "Any authenticated user can change their role to admin.",
462
+ "severity": "critical",
463
+ "confidence": "high",
464
+ "cwe": [
465
+ "CWE-915",
466
+ "CWE-269"
467
+ ],
468
+ "recommendation": "Restrict binding to non‑privileged fields or set privileged fields server‑side.",
469
+ "status": "confirmed",
470
+ "verification": {
471
+ "verdict": "confirmed",
472
+ "reason_code": "traced",
473
+ "checked": [
474
+ "php-plain/profile.php",
475
+ "php-plain/inc/auth.php"
476
+ ],
477
+ "control_found": null,
478
+ "notes": "The script binds all POST fields to the user object, including the privileged 'role' field, and then saves the user. No role or ownership check is present in the visible code.",
479
+ "suggested_subtype": null,
480
+ "suggested_cwe": null
481
+ },
482
+ "fingerprint": "kfp1:5d358b0d7773db98c6fc18bec77889109e89b127d7146e7bc9ca7406ae6ff5fc",
483
+ "baseline_state": "new"
484
+ },
485
+ {
486
+ "finding_id": "BFLA-R-0066-1",
487
+ "category": "bfla",
488
+ "subtype": "missing_role_check",
489
+ "title": "Unprotected user deletion in PHP plain",
490
+ "route_id": "R-0066",
491
+ "location": {
492
+ "file": "php-plain/admin/delete_user.php",
493
+ "start_line": 1
494
+ },
495
+ "evidence": [
496
+ {
497
+ "file": "php-plain/admin/delete_user.php",
498
+ "line": 6,
499
+ "why": "DELETE FROM users WHERE id = ? (privileged action, no role check)"
500
+ },
501
+ {
502
+ "file": "php-plain/admin/delete_user.php",
503
+ "line": 1,
504
+ "why": "no role check before the delete"
505
+ }
506
+ ],
507
+ "impact": "Any authenticated user can delete any user.",
508
+ "severity": "critical",
509
+ "confidence": "high",
510
+ "cwe": [
511
+ "CWE-285"
512
+ ],
513
+ "recommendation": "Add a server‑side admin check before executing the delete.",
514
+ "status": "confirmed",
515
+ "verification": {
516
+ "verdict": "confirmed",
517
+ "reason_code": "traced",
518
+ "checked": [
519
+ "php-plain/admin/delete_user.php lines 1-8",
520
+ "php-plain/inc/auth.php lines 1-7"
521
+ ],
522
+ "control_found": null,
523
+ "notes": "The delete_user script performs a DELETE on users by id without any admin or ownership check. Only a login check is present in inc/auth.php.",
524
+ "suggested_subtype": null,
525
+ "suggested_cwe": null
526
+ },
527
+ "fingerprint": "kfp1:ac5acea0a998815d202206c2242aa04d68020c74c2b9bf604fd6e9620c81190d",
528
+ "baseline_state": "new"
529
+ },
530
+ {
531
+ "finding_id": "BFLA-R-0067-1",
532
+ "category": "bfla",
533
+ "subtype": "role_from_request",
534
+ "title": "Privilege escalation via role promotion in PHP plain",
535
+ "route_id": "R-0067",
536
+ "location": {
537
+ "file": "php-plain/admin/promote.php",
538
+ "start_line": 1
539
+ },
540
+ "evidence": [
541
+ {
542
+ "file": "php-plain/admin/promote.php",
543
+ "line": 6,
544
+ "why": "UPDATE users SET role = 'admin' WHERE id = ... (privileged action, no role check)"
545
+ },
546
+ {
547
+ "file": "php-plain/admin/promote.php",
548
+ "line": 5,
549
+ "why": "role set from $_POST['is_admin'] (client‑side control)"
550
+ },
551
+ {
552
+ "file": "php-plain/admin/promote.php",
553
+ "line": 1,
554
+ "why": "no role check before the update"
555
+ }
556
+ ],
557
+ "impact": "Any authenticated user can promote themselves to admin.",
558
+ "severity": "critical",
559
+ "confidence": "high",
560
+ "cwe": [
561
+ "CWE-269",
562
+ "CWE-285"
563
+ ],
564
+ "recommendation": "Validate the caller's role server‑side before allowing role changes.",
565
+ "status": "confirmed",
566
+ "verification": {
567
+ "verdict": "confirmed",
568
+ "reason_code": "traced",
569
+ "checked": [
570
+ "php-plain/admin/promote.php",
571
+ "php-plain/inc/auth.php"
572
+ ],
573
+ "control_found": null,
574
+ "notes": "The code performs a role update based solely on a POST parameter and the user ID supplied in the request. The included auth.php only verifies that a session exists; it does not check that the current user is an administrator. No other role or ownership check is visible in the code context.",
575
+ "suggested_subtype": null,
576
+ "suggested_cwe": null
577
+ },
578
+ "fingerprint": "kfp1:d174ebc0365672a7b111b699d6c623186ff22f9478565d4ad9e479d844293faf",
579
+ "baseline_state": "new"
580
+ },
581
+ {
582
+ "finding_id": "INJ-I-0001",
583
+ "category": "sql_injection",
584
+ "subtype": "string_concatenation",
585
+ "title": "SQL Injection in classic-asp/shop/member.asp:6",
586
+ "candidate_id": "I-0001",
587
+ "location": {
588
+ "file": "classic-asp/shop/member.asp",
589
+ "start_line": 6
590
+ },
591
+ "evidence": [
592
+ {
593
+ "file": "classic-asp/shop/member.asp",
594
+ "start_line": 6,
595
+ "code": "sql = \"UPDATE members SET name = '\" & Replace(Request.Form(\"name\"), \"'\", \"''\") & \"'\"",
596
+ "why": "Unsanitized input concatenated into query",
597
+ "line": 6
598
+ },
599
+ {
600
+ "file": "classic-asp/shop/member.asp",
601
+ "start_line": 7,
602
+ "code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
603
+ "why": "Unsanitized input concatenated into query",
604
+ "line": 7
605
+ }
606
+ ],
607
+ "severity": "critical",
608
+ "confidence": "high",
609
+ "cwe": [
610
+ "CWE-89"
611
+ ],
612
+ "recommendation": "Use parameterized queries or stored procedures",
613
+ "status": "confirmed",
614
+ "verification": {
615
+ "verdict": "confirmed",
616
+ "reason_code": "traced",
617
+ "checked": [
618
+ "classic-asp/shop/member.asp:6-7",
619
+ "classic-asp/shop/inc/auth.asp:1-3",
620
+ "classic-asp/shop/inc/conn.asp:1-4"
621
+ ],
622
+ "control_found": null,
623
+ "notes": "No ownership or role check is present; the UPDATE statement concatenates user input directly, enabling SQL injection.",
624
+ "suggested_subtype": null,
625
+ "suggested_cwe": null
626
+ },
627
+ "fingerprint": "kfp1:52c63ccaf583de3933acccb3eff1f79314c58ac311cdeecdfc26c798403a7c89",
628
+ "baseline_state": "new"
629
+ },
630
+ {
631
+ "finding_id": "INJ-I-0002",
632
+ "category": "sql_injection",
633
+ "subtype": "string_concatenation",
634
+ "title": "SQL Injection in classic-asp/shop/member.asp:7",
635
+ "candidate_id": "I-0002",
636
+ "location": {
637
+ "file": "classic-asp/shop/member.asp",
638
+ "start_line": 7
639
+ },
640
+ "evidence": [
641
+ {
642
+ "file": "classic-asp/shop/member.asp",
643
+ "start_line": 7,
644
+ "code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
645
+ "why": "Unsanitized input concatenated into query",
646
+ "line": 7
647
+ }
648
+ ],
649
+ "severity": "critical",
650
+ "confidence": "high",
651
+ "cwe": [
652
+ "CWE-89"
653
+ ],
654
+ "recommendation": "Use parameterized queries or stored procedures",
655
+ "status": "confirmed",
656
+ "verification": {
657
+ "verdict": "confirmed",
658
+ "reason_code": "traced",
659
+ "checked": [
660
+ "classic-asp/shop/member.asp:6-7",
661
+ "classic-asp/shop/inc/auth.asp:1-3",
662
+ "classic-asp/shop/inc/conn.asp:1-4"
663
+ ],
664
+ "control_found": null,
665
+ "notes": "The WHERE clause concatenates user input without any cast or ownership check, exposing the query to injection.",
666
+ "suggested_subtype": null,
667
+ "suggested_cwe": null
668
+ },
669
+ "fingerprint": "kfp1:a425457aee9a3c9db04caa44ddba7d35ecadd834bf5a0100207b9fce90ea85dd",
670
+ "baseline_state": "new"
671
+ },
672
+ {
673
+ "finding_id": "INJ-I-0003",
674
+ "category": "sql_injection",
675
+ "subtype": "string_concatenation",
676
+ "title": "SQL Injection in classic-asp/shop/member.asp:10",
677
+ "candidate_id": "I-0003",
678
+ "location": {
679
+ "file": "classic-asp/shop/member.asp",
680
+ "start_line": 10
681
+ },
682
+ "evidence": [
683
+ {
684
+ "file": "classic-asp/shop/member.asp",
685
+ "start_line": 10,
686
+ "code": "conn.Execute \"DELETE FROM members WHERE member_id = \" & Request.QueryString(\"member_id\")",
687
+ "why": "Unsanitized input concatenated into query",
688
+ "line": 10
689
+ }
690
+ ],
691
+ "severity": "critical",
692
+ "confidence": "high",
693
+ "cwe": [
694
+ "CWE-89"
695
+ ],
696
+ "recommendation": "Use parameterized queries or stored procedures",
697
+ "status": "confirmed",
698
+ "verification": {
699
+ "verdict": "confirmed",
700
+ "reason_code": "traced",
701
+ "checked": [
702
+ "classic-asp/shop/member.asp:9-11",
703
+ "classic-asp/shop/inc/auth.asp:1-3",
704
+ "classic-asp/shop/inc/conn.asp:1-4"
705
+ ],
706
+ "control_found": null,
707
+ "notes": "The DELETE statement uses unsanitized QueryString input directly; no ownership or role guard is applied.",
708
+ "suggested_subtype": null,
709
+ "suggested_cwe": null
710
+ },
711
+ "fingerprint": "kfp1:f1fb34f9c39374bc339b3dc230f5ac6b00731c69bf6cd1399b983ba2d2833525",
712
+ "baseline_state": "new"
713
+ },
714
+ {
715
+ "finding_id": "INJ-I-0004",
716
+ "category": "sql_injection",
717
+ "subtype": "string_concatenation",
718
+ "title": "SQL Injection in classic-asp/shop/order.asp:6",
719
+ "candidate_id": "I-0004",
720
+ "location": {
721
+ "file": "classic-asp/shop/order.asp",
722
+ "start_line": 6
723
+ },
724
+ "evidence": [
725
+ {
726
+ "file": "classic-asp/shop/order.asp",
727
+ "start_line": 6,
728
+ "code": "Set rs = conn.Execute(\"SELECT * FROM orders WHERE id = \" & id)",
729
+ "why": "Unsanitized input concatenated into query",
730
+ "line": 6
731
+ }
732
+ ],
733
+ "severity": "critical",
734
+ "confidence": "high",
735
+ "cwe": [
736
+ "CWE-89"
737
+ ],
738
+ "recommendation": "Use parameterized queries or stored procedures",
739
+ "status": "confirmed",
740
+ "verification": {
741
+ "verdict": "confirmed",
742
+ "reason_code": "traced",
743
+ "checked": [
744
+ "classic-asp/shop/order.asp:5-6",
745
+ "classic-asp/shop/inc/auth.asp:1-3",
746
+ "classic-asp/shop/inc/conn.asp:1-4"
747
+ ],
748
+ "control_found": null,
749
+ "notes": "The SELECT query concatenates the id parameter directly; no cast or ownership check is present.",
750
+ "suggested_subtype": null,
751
+ "suggested_cwe": null
752
+ },
753
+ "fingerprint": "kfp1:07b1c914202a928e4156e6b6e9e5ab32fe7a75cdceda182d55d68051eeb61ac9",
754
+ "baseline_state": "new"
755
+ },
756
+ {
757
+ "finding_id": "INJ-I-0006",
758
+ "category": "sql_injection",
759
+ "subtype": "string_concatenation",
760
+ "title": "SQL Injection in coldfusion/app/OrderService.cfc:5",
761
+ "candidate_id": "I-0006",
762
+ "location": {
763
+ "file": "coldfusion/app/OrderService.cfc",
764
+ "start_line": 5
765
+ },
766
+ "evidence": [
767
+ {
768
+ "file": "coldfusion/app/OrderService.cfc",
769
+ "start_line": 5,
770
+ "code": "SELECT * FROM orders WHERE id = #arguments.orderId#",
771
+ "why": "Unsanitized input concatenated into query",
772
+ "line": 5
773
+ }
774
+ ],
775
+ "severity": "critical",
776
+ "confidence": "high",
777
+ "cwe": [
778
+ "CWE-89"
779
+ ],
780
+ "recommendation": "Use <cfqueryparam> or stored procedures",
781
+ "status": "confirmed",
782
+ "verification": {
783
+ "verdict": "confirmed",
784
+ "reason_code": "traced",
785
+ "checked": [
786
+ "coldfusion/app/OrderService.cfc line 5"
787
+ ],
788
+ "control_found": null,
789
+ "notes": "The query concatenates the unsanitized argument directly into the SQL string with no parameter binding, cast, or ownership check.",
790
+ "suggested_subtype": null,
791
+ "suggested_cwe": null
792
+ },
793
+ "fingerprint": "kfp1:b6824160d6d38156b7a16dc1526dda6be874be4401ad843a3c185f94446dcf5e",
794
+ "baseline_state": "new"
795
+ },
796
+ {
797
+ "finding_id": "INJ-I-0007",
798
+ "category": "sql_injection",
799
+ "subtype": "string_concatenation",
800
+ "title": "SQL Injection in coldfusion/app/order.cfm:3",
801
+ "candidate_id": "I-0007",
802
+ "location": {
803
+ "file": "coldfusion/app/order.cfm",
804
+ "start_line": 3
805
+ },
806
+ "evidence": [
807
+ {
808
+ "file": "coldfusion/app/order.cfm",
809
+ "start_line": 3,
810
+ "code": "SELECT * FROM orders WHERE id = #url.id#",
811
+ "why": "Unsanitized input concatenated into query",
812
+ "line": 3
813
+ }
814
+ ],
815
+ "severity": "critical",
816
+ "confidence": "high",
817
+ "cwe": [
818
+ "CWE-89"
819
+ ],
820
+ "recommendation": "Use <cfqueryparam> or stored procedures",
821
+ "status": "confirmed",
822
+ "verification": {
823
+ "verdict": "confirmed",
824
+ "reason_code": "traced",
825
+ "checked": [
826
+ "coldfusion/app/order.cfm line 3"
827
+ ],
828
+ "control_found": null,
829
+ "notes": "The first query uses the unsanitized URL parameter directly; no parameter binding or ownership check is present.",
830
+ "suggested_subtype": null,
831
+ "suggested_cwe": null
832
+ },
833
+ "fingerprint": "kfp1:d2650d07ae7cedfc90bd1abda3c42a63716563d54c45ecde428ae21505214f72",
834
+ "baseline_state": "new"
835
+ },
836
+ {
837
+ "finding_id": "INJ-I-0008",
838
+ "category": "sql_injection",
839
+ "subtype": "string_concatenation",
840
+ "title": "SQL Injection in dotnet-legacy/Web/Controllers/InvoiceController.cs:28",
841
+ "candidate_id": "I-0008",
842
+ "location": {
843
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
844
+ "start_line": 28
845
+ },
846
+ "evidence": [
847
+ {
848
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
849
+ "start_line": 28,
850
+ "code": "var list = db.Database.SqlQuery<Invoice>(\"SELECT * FROM Invoices WHERE Customer = '\" + customer + \"'\").ToList();",
851
+ "why": "Unsanitized input concatenated into query",
852
+ "line": 28
853
+ }
854
+ ],
855
+ "severity": "critical",
856
+ "confidence": "medium",
857
+ "cwe": [
858
+ "CWE-89"
859
+ ],
860
+ "recommendation": "Use parameterized queries",
861
+ "status": "likely",
862
+ "verification": {
863
+ "verdict": "likely",
864
+ "reason_code": "code_not_visible",
865
+ "checked": [
866
+ "dotnet-legacy/Web/Controllers/InvoiceController.cs:26-28"
867
+ ],
868
+ "control_found": null,
869
+ "notes": "The Search action concatenates the 'customer' parameter into a raw SQL string; no parameterization or ownership check is shown in the context.",
870
+ "suggested_subtype": null,
871
+ "suggested_cwe": null
872
+ },
873
+ "fingerprint": "kfp1:81106c3dfe7181ee5aad08bbd8e6c94143e8ebb6bf477a18828ca399339d1271",
874
+ "baseline_state": "new"
875
+ },
876
+ {
877
+ "finding_id": "INJ-I-0009",
878
+ "category": "sql_injection",
879
+ "subtype": "string_concatenation",
880
+ "title": "SQL Injection in dotnet-legacy/Web/Orders/EditOrder.aspx.vb:7",
881
+ "candidate_id": "I-0009",
882
+ "location": {
883
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
884
+ "start_line": 7
885
+ },
886
+ "evidence": [
887
+ {
888
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
889
+ "start_line": 7,
890
+ "code": "Dim sql As String = \"UPDATE Orders SET Note = '\" & txtNote.Text & \"'\"",
891
+ "why": "Unsanitized input concatenated into query",
892
+ "line": 7
893
+ },
894
+ {
895
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
896
+ "start_line": 8,
897
+ "code": "sql &= \" WHERE OrderId = \" & hfOrderId.Value",
898
+ "why": "Unsanitized input concatenated into query",
899
+ "line": 8
900
+ }
901
+ ],
902
+ "severity": "critical",
903
+ "confidence": "high",
904
+ "cwe": [
905
+ "CWE-89"
906
+ ],
907
+ "recommendation": "Use SqlCommand with parameters",
908
+ "status": "confirmed",
909
+ "verification": {
910
+ "verdict": "confirmed",
911
+ "reason_code": "traced",
912
+ "checked": [
913
+ "dotnet-legacy/Web/Orders/EditOrder.aspx.vb lines 7-8"
914
+ ],
915
+ "control_found": null,
916
+ "notes": "SQL is built by string concatenation with user input; no parameterization or ownership validation is shown.",
917
+ "suggested_subtype": null,
918
+ "suggested_cwe": null
919
+ },
920
+ "fingerprint": "kfp1:999e755f32c1edc6b46f7497ebdfd065d8afcc3518cab3211f45fc11a7342afd",
921
+ "baseline_state": "new"
922
+ },
923
+ {
924
+ "finding_id": "INJ-I-0010",
925
+ "category": "sql_injection",
926
+ "subtype": "string_concatenation",
927
+ "title": "SQL Injection in dotnet-legacy/Web/Orders/EditOrder.aspx.vb:8",
928
+ "candidate_id": "I-0010",
929
+ "location": {
930
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
931
+ "start_line": 8
932
+ },
933
+ "evidence": [
934
+ {
935
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
936
+ "start_line": 8,
937
+ "code": "sql &= \" WHERE OrderId = \" & hfOrderId.Value",
938
+ "why": "Unsanitized input concatenated into query",
939
+ "line": 8
940
+ }
941
+ ],
942
+ "severity": "critical",
943
+ "confidence": "high",
944
+ "cwe": [
945
+ "CWE-89"
946
+ ],
947
+ "recommendation": "Use SqlCommand with parameters",
948
+ "status": "confirmed",
949
+ "verification": {
950
+ "verdict": "confirmed",
951
+ "reason_code": "traced",
952
+ "checked": [
953
+ "dotnet-legacy/Web/Orders/EditOrder.aspx.vb line 8"
954
+ ],
955
+ "control_found": null,
956
+ "notes": "The query concatenates the hidden field value directly; no parameter binding or ownership check is present.",
957
+ "suggested_subtype": null,
958
+ "suggested_cwe": null
959
+ },
960
+ "fingerprint": "kfp1:323eb8697c45d7b7466292d80a0763dd2310608e0975d837273bde14e3458f59",
961
+ "baseline_state": "new"
962
+ },
963
+ {
964
+ "finding_id": "INJ-I-0011",
965
+ "category": "sql_injection",
966
+ "subtype": "string_concatenation",
967
+ "title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:13",
968
+ "candidate_id": "I-0011",
969
+ "location": {
970
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
971
+ "start_line": 13
972
+ },
973
+ "evidence": [
974
+ {
975
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
976
+ "start_line": 13,
977
+ "code": "var cmd = new SqlCommand(\"SELECT * FROM Orders WHERE OrderId = \" + id, conn);",
978
+ "why": "Unsanitized input concatenated into query",
979
+ "line": 13
980
+ },
981
+ {
982
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
983
+ "start_line": 19,
984
+ "code": "string sql2 = string.Format(\"SELECT * FROM Logs WHERE Ref = '{0}'\", Request[\"ref\"]);",
985
+ "why": "Unsanitized input concatenated into query",
986
+ "line": 19
987
+ },
988
+ {
989
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
990
+ "start_line": 20,
991
+ "code": "string sql3 = $\"DELETE FROM Carts WHERE CartId = {Request.Form[\"cart\"]}\";",
992
+ "why": "Unsanitized input concatenated into query",
993
+ "line": 20
994
+ }
995
+ ],
996
+ "severity": "critical",
997
+ "confidence": "high",
998
+ "cwe": [
999
+ "CWE-89"
1000
+ ],
1001
+ "recommendation": "Use SqlCommand with parameters",
1002
+ "status": "confirmed",
1003
+ "verification": {
1004
+ "verdict": "confirmed",
1005
+ "reason_code": "traced",
1006
+ "checked": [
1007
+ "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs lines 13, 19, 20"
1008
+ ],
1009
+ "control_found": null,
1010
+ "notes": "All three queries are constructed via string concatenation or string.Format with unsanitized request data; no parameterization or ownership check is shown.",
1011
+ "suggested_subtype": null,
1012
+ "suggested_cwe": null
1013
+ },
1014
+ "fingerprint": "kfp1:c9aa426f72d032a9b0729b0905c9c25a6fb8844a92a91c45d72d3e26170bbae5",
1015
+ "baseline_state": "new"
1016
+ },
1017
+ {
1018
+ "finding_id": "INJ-I-0012",
1019
+ "category": "sql_injection",
1020
+ "subtype": "string_concatenation",
1021
+ "title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:19",
1022
+ "candidate_id": "I-0012",
1023
+ "location": {
1024
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
1025
+ "start_line": 19
1026
+ },
1027
+ "evidence": [
1028
+ {
1029
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
1030
+ "start_line": 19,
1031
+ "code": "string sql2 = string.Format(\"SELECT * FROM Logs WHERE Ref = '{0}'\", Request[\"ref\"]);",
1032
+ "why": "Unsanitized input concatenated into query",
1033
+ "line": 19
1034
+ }
1035
+ ],
1036
+ "severity": "critical",
1037
+ "confidence": "high",
1038
+ "cwe": [
1039
+ "CWE-89"
1040
+ ],
1041
+ "recommendation": "Use parameterized queries",
1042
+ "status": "likely",
1043
+ "verification": {
1044
+ "verdict": "likely",
1045
+ "reason_code": "code_not_visible",
1046
+ "checked": [
1047
+ "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:19"
1048
+ ],
1049
+ "control_found": null,
1050
+ "notes": "The code concatenates Request[\"ref\"] into a SQL string and executes it. No ownership or role check, integer cast, or allow‑list is visible in the provided snippet.",
1051
+ "suggested_subtype": null,
1052
+ "suggested_cwe": null
1053
+ },
1054
+ "fingerprint": "kfp1:c0adff113329292a51bb7d2f2aa03dd242c6d767cee060a789ff750f3ab9b946",
1055
+ "baseline_state": "new"
1056
+ },
1057
+ {
1058
+ "finding_id": "INJ-I-0013",
1059
+ "category": "sql_injection",
1060
+ "subtype": "string_concatenation",
1061
+ "title": "SQL Injection in dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:20",
1062
+ "candidate_id": "I-0013",
1063
+ "location": {
1064
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
1065
+ "start_line": 20
1066
+ },
1067
+ "evidence": [
1068
+ {
1069
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
1070
+ "start_line": 20,
1071
+ "code": "string sql3 = $\"DELETE FROM Carts WHERE CartId = {Request.Form[\"cart\"]}\";",
1072
+ "why": "Unsanitized input concatenated into query",
1073
+ "line": 20
1074
+ }
1075
+ ],
1076
+ "severity": "critical",
1077
+ "confidence": "high",
1078
+ "cwe": [
1079
+ "CWE-89"
1080
+ ],
1081
+ "recommendation": "Use parameterized queries",
1082
+ "status": "likely",
1083
+ "verification": {
1084
+ "verdict": "likely",
1085
+ "reason_code": "code_not_visible",
1086
+ "checked": [
1087
+ "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs:20"
1088
+ ],
1089
+ "control_found": null,
1090
+ "notes": "The code builds a DELETE statement using Request.Form[\"cart\"] without sanitization or parameter binding. No compensating control is shown.",
1091
+ "suggested_subtype": null,
1092
+ "suggested_cwe": null
1093
+ },
1094
+ "fingerprint": "kfp1:4dbfab5201fa4fb196296b8ea0e4be14bb1ae1e6d3136309f24af78eb9977441",
1095
+ "baseline_state": "new"
1096
+ },
1097
+ {
1098
+ "finding_id": "INJ-I-0014",
1099
+ "category": "sql_injection",
1100
+ "subtype": "string_concatenation",
1101
+ "title": "SQL Injection in java-legacy/WebContent/order/detail.jsp:5",
1102
+ "candidate_id": "I-0014",
1103
+ "location": {
1104
+ "file": "java-legacy/WebContent/order/detail.jsp",
1105
+ "start_line": 5
1106
+ },
1107
+ "evidence": [
1108
+ {
1109
+ "file": "java-legacy/WebContent/order/detail.jsp",
1110
+ "start_line": 5,
1111
+ "code": "ResultSet rs = c.createStatement().executeQuery(\"SELECT * FROM orders WHERE order_no = '\" + no + \"'\");",
1112
+ "why": "Unsanitized input concatenated into query",
1113
+ "line": 5
1114
+ }
1115
+ ],
1116
+ "severity": "critical",
1117
+ "confidence": "high",
1118
+ "cwe": [
1119
+ "CWE-89"
1120
+ ],
1121
+ "recommendation": "Use PreparedStatement with parameters",
1122
+ "status": "likely",
1123
+ "verification": {
1124
+ "verdict": "likely",
1125
+ "reason_code": "code_not_visible",
1126
+ "checked": [
1127
+ "java-legacy/WebContent/order/detail.jsp:5"
1128
+ ],
1129
+ "control_found": null,
1130
+ "notes": "The query concatenates the request parameter \"no\" directly into the SQL string. No ownership or role check, cast, or allow‑list is present in the snippet.",
1131
+ "suggested_subtype": null,
1132
+ "suggested_cwe": null
1133
+ },
1134
+ "fingerprint": "kfp1:b8e7acb1ca7119156e96cf2bd42356b53bb6107a0a904b492534714730ac45f8",
1135
+ "baseline_state": "new"
1136
+ },
1137
+ {
1138
+ "finding_id": "INJ-I-0015",
1139
+ "category": "sql_injection",
1140
+ "subtype": "dynamic_identifier",
1141
+ "title": "SQL Injection in java-legacy/src/com/acme/mapper/OrderMapper.xml:9",
1142
+ "candidate_id": "I-0015",
1143
+ "location": {
1144
+ "file": "java-legacy/src/com/acme/mapper/OrderMapper.xml",
1145
+ "start_line": 9
1146
+ },
1147
+ "evidence": [
1148
+ {
1149
+ "file": "java-legacy/src/com/acme/mapper/OrderMapper.xml",
1150
+ "start_line": 9,
1151
+ "code": "ORDER BY ${orderBy}",
1152
+ "why": "Dynamic identifier substituted without validation",
1153
+ "line": 9
1154
+ }
1155
+ ],
1156
+ "severity": "critical",
1157
+ "confidence": "medium",
1158
+ "cwe": [
1159
+ "CWE-89"
1160
+ ],
1161
+ "recommendation": "Validate ORDER BY values against an allow‑list before substitution",
1162
+ "status": "likely",
1163
+ "verification": {
1164
+ "verdict": "likely",
1165
+ "reason_code": "code_not_visible",
1166
+ "checked": [
1167
+ "java-legacy/src/com/acme/mapper/OrderMapper.xml:7-9"
1168
+ ],
1169
+ "control_found": null,
1170
+ "notes": "The mapper XML contains a raw ORDER BY substitution without any visible allow‑list or parameter binding. No ownership or role check is present in the snippet.",
1171
+ "suggested_subtype": null,
1172
+ "suggested_cwe": null
1173
+ },
1174
+ "fingerprint": "kfp1:a0212ab67bd8e95a9fa71520fd15ba101852184637a1a60ec1bb91525308964f",
1175
+ "baseline_state": "new"
1176
+ },
1177
+ {
1178
+ "finding_id": "INJ-I-0016",
1179
+ "category": "sql_injection",
1180
+ "subtype": "string_concatenation",
1181
+ "title": "SQL Injection in java-legacy/src/com/acme/struts/EditUserAction.java:13",
1182
+ "candidate_id": "I-0016",
1183
+ "location": {
1184
+ "file": "java-legacy/src/com/acme/struts/EditUserAction.java",
1185
+ "start_line": 13
1186
+ },
1187
+ "evidence": [
1188
+ {
1189
+ "file": "java-legacy/src/com/acme/struts/EditUserAction.java",
1190
+ "start_line": 13,
1191
+ "code": "PreparedStatement ps = conn.prepareStatement(\"UPDATE users SET email = '\" + email + \"' WHERE id = \" + userId);",
1192
+ "why": "Unsanitized input concatenated into query",
1193
+ "line": 13
1194
+ }
1195
+ ],
1196
+ "severity": "critical",
1197
+ "confidence": "high",
1198
+ "cwe": [
1199
+ "CWE-89"
1200
+ ],
1201
+ "recommendation": "Use PreparedStatement with parameters",
1202
+ "status": "likely",
1203
+ "verification": {
1204
+ "verdict": "likely",
1205
+ "reason_code": "code_not_visible",
1206
+ "checked": [
1207
+ "java-legacy/src/com/acme/struts/EditUserAction.java:13"
1208
+ ],
1209
+ "control_found": null,
1210
+ "notes": "The PreparedStatement is built by concatenating user input into the SQL string. No ownership or role check, cast, or allow‑list is visible.",
1211
+ "suggested_subtype": null,
1212
+ "suggested_cwe": null
1213
+ },
1214
+ "fingerprint": "kfp1:2976fb21c23c927d1de0f3af7dc883d9b66a1d051ec67bb9ec1b44396f6479fc",
1215
+ "baseline_state": "new"
1216
+ },
1217
+ {
1218
+ "finding_id": "INJ-I-0017",
1219
+ "category": "sql_injection",
1220
+ "subtype": "string_concatenation",
1221
+ "title": "SQL Injection in java-legacy/src/com/acme/web/InvoiceController.java:29",
1222
+ "candidate_id": "I-0017",
1223
+ "location": {
1224
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
1225
+ "start_line": 29
1226
+ },
1227
+ "evidence": [
1228
+ {
1229
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
1230
+ "start_line": 29,
1231
+ "code": "session.createQuery(\"from Invoice i where i.customer = '\" + customer + \"'\").list();",
1232
+ "why": "Unsanitized input concatenated into query",
1233
+ "line": 29
1234
+ }
1235
+ ],
1236
+ "severity": "critical",
1237
+ "confidence": "high",
1238
+ "cwe": [
1239
+ "CWE-89"
1240
+ ],
1241
+ "recommendation": "Use parameterized HQL queries",
1242
+ "status": "likely",
1243
+ "verification": {
1244
+ "verdict": "likely",
1245
+ "reason_code": "code_not_visible",
1246
+ "checked": [
1247
+ "java-legacy/src/com/acme/web/InvoiceController.java:29"
1248
+ ],
1249
+ "control_found": null,
1250
+ "notes": "The HQL query concatenates the \"customer\" request parameter directly. No ownership or role check, cast, or allow‑list is shown in the snippet.",
1251
+ "suggested_subtype": null,
1252
+ "suggested_cwe": null
1253
+ },
1254
+ "fingerprint": "kfp1:7796f734194bfe71dc7268f597efd6338a4e967a788e0220edb61b8e1c198b16",
1255
+ "baseline_state": "new"
1256
+ },
1257
+ {
1258
+ "finding_id": "INJ-I-0018",
1259
+ "category": "sql_injection",
1260
+ "subtype": "string_concatenation",
1261
+ "title": "SQL Injection in java-legacy/src/com/acme/web/OrderServlet.java:15",
1262
+ "candidate_id": "I-0018",
1263
+ "location": {
1264
+ "file": "java-legacy/src/com/acme/web/OrderServlet.java",
1265
+ "start_line": 15
1266
+ },
1267
+ "evidence": [
1268
+ {
1269
+ "file": "java-legacy/src/com/acme/web/OrderServlet.java",
1270
+ "start_line": 15,
1271
+ "code": "ResultSet rs = stmt.executeQuery(\"SELECT * FROM orders WHERE id = '\" + id + \"'\");",
1272
+ "why": "Unsanitized input concatenated into query",
1273
+ "line": 15
1274
+ },
1275
+ {
1276
+ "file": "java-legacy/src/com/acme/web/OrderServlet.java",
1277
+ "start_line": 17,
1278
+ "code": "sb.append(\" AND order_id = \").append(id);",
1279
+ "why": "Unsanitized input concatenated into query",
1280
+ "line": 17
1281
+ }
1282
+ ],
1283
+ "severity": "critical",
1284
+ "confidence": "medium",
1285
+ "cwe": [
1286
+ "CWE-89"
1287
+ ],
1288
+ "recommendation": "Use PreparedStatement with bound parameters",
1289
+ "status": "likely",
1290
+ "verification": {
1291
+ "verdict": "likely",
1292
+ "reason_code": "code_not_visible",
1293
+ "checked": [
1294
+ "java-legacy/src/com/acme/web/OrderServlet.java:13-18"
1295
+ ],
1296
+ "control_found": null,
1297
+ "notes": "The servlet concatenates user input directly into SQL strings. No integer cast, allow‑list, or ownership check is shown in the snippet.",
1298
+ "suggested_subtype": null,
1299
+ "suggested_cwe": null
1300
+ },
1301
+ "fingerprint": "kfp1:eed713c040fe4b03f16a649b4da2fa326995fd074ad3ba46bbbb4958486b6b8d",
1302
+ "baseline_state": "new"
1303
+ },
1304
+ {
1305
+ "finding_id": "INJ-I-0020",
1306
+ "category": "sql_injection",
1307
+ "subtype": "string_concatenation",
1308
+ "title": "SQL Injection in node-express/routes/orders.js:17",
1309
+ "candidate_id": "I-0020",
1310
+ "location": {
1311
+ "file": "node-express/routes/orders.js",
1312
+ "start_line": 17
1313
+ },
1314
+ "evidence": [
1315
+ {
1316
+ "file": "node-express/routes/orders.js",
1317
+ "start_line": 17,
1318
+ "code": "db.query(\"SELECT * FROM reports WHERE month = '\" + req.query.month + \"'\", function (e, rows) { res.json(rows); });",
1319
+ "why": "Unsanitized input concatenated into query",
1320
+ "line": 17
1321
+ },
1322
+ {
1323
+ "file": "node-express/routes/orders.js",
1324
+ "start_line": 29,
1325
+ "code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
1326
+ "why": "Unsanitized input concatenated into query",
1327
+ "line": 29
1328
+ }
1329
+ ],
1330
+ "severity": "critical",
1331
+ "confidence": "high",
1332
+ "cwe": [
1333
+ "CWE-89"
1334
+ ],
1335
+ "recommendation": "Use parameterized queries or ORM",
1336
+ "status": "confirmed",
1337
+ "verification": {
1338
+ "verdict": "confirmed",
1339
+ "reason_code": "traced",
1340
+ "checked": [
1341
+ "node-express/routes/orders.js:17"
1342
+ ],
1343
+ "control_found": null,
1344
+ "notes": "The query concatenates the unsanitized req.query.month directly into the SQL string. No integer cast, allow‑list, or parameter binding is present in the visible code.",
1345
+ "suggested_subtype": null,
1346
+ "suggested_cwe": null
1347
+ },
1348
+ "fingerprint": "kfp1:fc0f31011ca4510d026845f7fb0dcd77812ef24f6ea5329ad24fbc08a15b58ff",
1349
+ "baseline_state": "new"
1350
+ },
1351
+ {
1352
+ "finding_id": "INJ-I-0022",
1353
+ "category": "sql_injection",
1354
+ "subtype": "string_concatenation",
1355
+ "title": "SQL Injection in node-express/routes/orders.js:21",
1356
+ "candidate_id": "I-0022",
1357
+ "location": {
1358
+ "file": "node-express/routes/orders.js",
1359
+ "start_line": 21
1360
+ },
1361
+ "evidence": [
1362
+ {
1363
+ "file": "node-express/routes/orders.js",
1364
+ "start_line": 21,
1365
+ "code": "db.collection('users').findOne(req.body, function (e, u) { res.json(!!u); });",
1366
+ "why": "Unsanitized input used as query object",
1367
+ "line": 21
1368
+ }
1369
+ ],
1370
+ "severity": "critical",
1371
+ "confidence": "high",
1372
+ "cwe": [
1373
+ "CWE-89"
1374
+ ],
1375
+ "recommendation": "Validate and sanitize request body before using as query",
1376
+ "status": "confirmed",
1377
+ "verification": {
1378
+ "verdict": "confirmed",
1379
+ "reason_code": "traced",
1380
+ "checked": [
1381
+ "node-express/routes/orders.js:21"
1382
+ ],
1383
+ "control_found": null,
1384
+ "notes": "The request body is passed directly to db.collection('users').findOne without validation or sanitization, exposing the query to injection.",
1385
+ "suggested_subtype": null,
1386
+ "suggested_cwe": null
1387
+ },
1388
+ "fingerprint": "kfp1:ce1d2e4f45d43976acdef65e9ac39896b64d4b16b8d2d07e7403e9408e5daba4",
1389
+ "baseline_state": "new"
1390
+ },
1391
+ {
1392
+ "finding_id": "INJ-I-0023",
1393
+ "category": "sql_injection",
1394
+ "subtype": "operator_injection",
1395
+ "title": "SQL Injection in node-express/routes/orders.js:25",
1396
+ "candidate_id": "I-0023",
1397
+ "location": {
1398
+ "file": "node-express/routes/orders.js",
1399
+ "start_line": 25
1400
+ },
1401
+ "evidence": [
1402
+ {
1403
+ "file": "node-express/routes/orders.js",
1404
+ "start_line": 25,
1405
+ "code": "db.collection('items').find({ $where: \"this.name == '\" + req.query.n + \"'\" }).toArray(function (e, r) { res.json(r); });",
1406
+ "why": "Unsanitized input used in $where JavaScript expression",
1407
+ "line": 25
1408
+ }
1409
+ ],
1410
+ "severity": "critical",
1411
+ "confidence": "high",
1412
+ "cwe": [
1413
+ "CWE-89"
1414
+ ],
1415
+ "recommendation": "Avoid $where; use indexed fields or parameterized queries",
1416
+ "status": "confirmed",
1417
+ "verification": {
1418
+ "verdict": "confirmed",
1419
+ "reason_code": "traced",
1420
+ "checked": [
1421
+ "node-express/routes/orders.js:25"
1422
+ ],
1423
+ "control_found": null,
1424
+ "notes": "The $where clause concatenates req.query.n into a JavaScript expression, allowing injection of arbitrary code.",
1425
+ "suggested_subtype": null,
1426
+ "suggested_cwe": null
1427
+ },
1428
+ "fingerprint": "kfp1:4adb02f62f3a6cc025b5f6a8cf67256c58ba026d3816f1d2e41944cd97d25ed5",
1429
+ "baseline_state": "new"
1430
+ },
1431
+ {
1432
+ "finding_id": "INJ-I-0024",
1433
+ "category": "sql_injection",
1434
+ "subtype": "string_concatenation",
1435
+ "title": "SQL Injection in perl-cgi/cgi-bin/order.cgi:13",
1436
+ "candidate_id": "I-0024",
1437
+ "location": {
1438
+ "file": "perl-cgi/cgi-bin/order.cgi",
1439
+ "start_line": 13
1440
+ },
1441
+ "evidence": [
1442
+ {
1443
+ "file": "perl-cgi/cgi-bin/order.cgi",
1444
+ "start_line": 13,
1445
+ "code": "my $sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");",
1446
+ "why": "Unsanitized input concatenated into query",
1447
+ "line": 13
1448
+ },
1449
+ {
1450
+ "file": "perl-cgi/cgi-bin/order.cgi",
1451
+ "start_line": 19,
1452
+ "code": "$dbh->do(\"DELETE FROM carts WHERE cart_id = \" . $q->param('cart'))",
1453
+ "why": "Unsanitized input concatenated into query",
1454
+ "line": 19
1455
+ }
1456
+ ],
1457
+ "severity": "critical",
1458
+ "confidence": "high",
1459
+ "cwe": [
1460
+ "CWE-89"
1461
+ ],
1462
+ "recommendation": "Use placeholders or parameterized queries",
1463
+ "status": "confirmed",
1464
+ "verification": {
1465
+ "verdict": "confirmed",
1466
+ "reason_code": "traced",
1467
+ "checked": [
1468
+ "perl-cgi/cgi-bin/order.cgi:13"
1469
+ ],
1470
+ "control_found": null,
1471
+ "notes": "The SQL statement is built by interpolating the unsanitized $id variable directly into the query string.",
1472
+ "suggested_subtype": null,
1473
+ "suggested_cwe": null
1474
+ },
1475
+ "fingerprint": "kfp1:0594761f603533b7391a9b7a8464e6865b71c1b61b71fdcd10991d861f51b5fb",
1476
+ "baseline_state": "new"
1477
+ },
1478
+ {
1479
+ "finding_id": "INJ-I-0025",
1480
+ "category": "sql_injection",
1481
+ "subtype": "string_concatenation",
1482
+ "title": "SQL Injection in perl-cgi/cgi-bin/order.cgi:19",
1483
+ "candidate_id": "I-0025",
1484
+ "location": {
1485
+ "file": "perl-cgi/cgi-bin/order.cgi",
1486
+ "start_line": 19
1487
+ },
1488
+ "evidence": [
1489
+ {
1490
+ "file": "perl-cgi/cgi-bin/order.cgi",
1491
+ "start_line": 19,
1492
+ "code": "$dbh->do(\"DELETE FROM carts WHERE cart_id = \" . $q->param('cart'))",
1493
+ "why": "Unsanitized input concatenated into query",
1494
+ "line": 19
1495
+ }
1496
+ ],
1497
+ "severity": "critical",
1498
+ "confidence": "high",
1499
+ "cwe": [
1500
+ "CWE-89"
1501
+ ],
1502
+ "recommendation": "Use placeholders or parameterized queries",
1503
+ "status": "confirmed",
1504
+ "verification": {
1505
+ "verdict": "confirmed",
1506
+ "reason_code": "traced",
1507
+ "checked": [
1508
+ "perl-cgi/cgi-bin/order.cgi:19"
1509
+ ],
1510
+ "control_found": null,
1511
+ "notes": "The DELETE statement concatenates the unsanitized cart ID from the query string directly into the SQL command.",
1512
+ "suggested_subtype": null,
1513
+ "suggested_cwe": null
1514
+ },
1515
+ "fingerprint": "kfp1:c7206e5510c18d43418b9ed9a4d20047783ea5263cfdc395a138b735b613debc",
1516
+ "baseline_state": "new"
1517
+ },
1518
+ {
1519
+ "finding_id": "INJ-I-0026",
1520
+ "category": "sql_injection",
1521
+ "subtype": "string_concatenation",
1522
+ "title": "SQL Injection in php-codeigniter/application/controllers/Invoice.php:10",
1523
+ "candidate_id": "I-0026",
1524
+ "location": {
1525
+ "file": "php-codeigniter/application/controllers/Invoice.php",
1526
+ "start_line": 10
1527
+ },
1528
+ "evidence": [
1529
+ {
1530
+ "file": "php-codeigniter/application/controllers/Invoice.php",
1531
+ "start_line": 10,
1532
+ "code": "$q = $this->db->query(\"SELECT * FROM invoices WHERE id = $id\");",
1533
+ "why": "Unsanitized input concatenated into query",
1534
+ "line": 10
1535
+ }
1536
+ ],
1537
+ "severity": "critical",
1538
+ "confidence": "medium",
1539
+ "cwe": [
1540
+ "CWE-89"
1541
+ ],
1542
+ "recommendation": "Use parameterized queries",
1543
+ "status": "likely",
1544
+ "verification": {
1545
+ "verdict": "likely",
1546
+ "reason_code": "code_not_visible",
1547
+ "checked": [
1548
+ "php-codeigniter/application/controllers/Invoice.php:9-11"
1549
+ ],
1550
+ "control_found": null,
1551
+ "notes": "The query concatenates the id directly. No cast, allow‑list, or ownership check is present in the snippet.",
1552
+ "suggested_subtype": null,
1553
+ "suggested_cwe": null
1554
+ },
1555
+ "fingerprint": "kfp1:cab7179a42b52f77a862191152d4b0ebc8511c6c77b956503f7c53525c9390b0",
1556
+ "baseline_state": "new"
1557
+ },
1558
+ {
1559
+ "finding_id": "INJ-I-0027",
1560
+ "category": "sql_injection",
1561
+ "subtype": "string_concatenation",
1562
+ "title": "SQL Injection in php-plain/admin.php:12",
1563
+ "candidate_id": "I-0027",
1564
+ "location": {
1565
+ "file": "php-plain/admin.php",
1566
+ "start_line": 12
1567
+ },
1568
+ "evidence": [
1569
+ {
1570
+ "file": "php-plain/admin.php",
1571
+ "start_line": 12,
1572
+ "code": "mysql_query(\"DELETE FROM users WHERE id = $id\");",
1573
+ "why": "Unsanitized input concatenated into query",
1574
+ "line": 12
1575
+ }
1576
+ ],
1577
+ "severity": "critical",
1578
+ "confidence": "medium",
1579
+ "cwe": [
1580
+ "CWE-89"
1581
+ ],
1582
+ "recommendation": "Use prepared statements or cast to integer",
1583
+ "status": "likely",
1584
+ "verification": {
1585
+ "verdict": "likely",
1586
+ "reason_code": "code_not_visible",
1587
+ "checked": [
1588
+ "php-plain/admin.php",
1589
+ "php-plain/inc/auth.php",
1590
+ "php-plain/inc/db.php"
1591
+ ],
1592
+ "control_found": null,
1593
+ "notes": "The code concatenates an unsanitized POST parameter into a DELETE statement. No ownership or role check, integer cast, or parameter binding is visible in the provided context.",
1594
+ "suggested_subtype": null,
1595
+ "suggested_cwe": null
1596
+ },
1597
+ "fingerprint": "kfp1:59fca8cd0dedd8f70d286a5d3808292d9eddcf084148a63a448b7043b69c7948",
1598
+ "baseline_state": "new"
1599
+ },
1600
+ {
1601
+ "finding_id": "INJ-I-0029",
1602
+ "category": "nosql_injection",
1603
+ "subtype": "operator_injection",
1604
+ "title": "NoSQL Injection in php-plain/mongo_find.php:6",
1605
+ "candidate_id": "I-0029",
1606
+ "location": {
1607
+ "file": "php-plain/mongo_find.php",
1608
+ "start_line": 6
1609
+ },
1610
+ "evidence": [
1611
+ {
1612
+ "file": "php-plain/mongo_find.php",
1613
+ "start_line": 6,
1614
+ "code": "$docs = $coll->find(array('$where' => \"this.name == '\" . $_GET['n'] . \"'\"));",
1615
+ "why": "Unsanitized input used in $where JavaScript expression",
1616
+ "line": 6
1617
+ }
1618
+ ],
1619
+ "severity": "critical",
1620
+ "confidence": "medium",
1621
+ "cwe": [
1622
+ "CWE-89"
1623
+ ],
1624
+ "recommendation": "Avoid $where; use indexed fields or parameterized queries",
1625
+ "status": "likely",
1626
+ "verification": {
1627
+ "verdict": "likely",
1628
+ "reason_code": "code_not_visible",
1629
+ "checked": [
1630
+ "php-plain/mongo_find.php",
1631
+ "php-plain/inc/auth.php"
1632
+ ],
1633
+ "control_found": null,
1634
+ "notes": "The $where clause is built from an unsanitized GET parameter. No sanitization, allow‑list, or ownership check is present in the context.",
1635
+ "suggested_subtype": null,
1636
+ "suggested_cwe": null
1637
+ },
1638
+ "fingerprint": "kfp1:bf0197ac678eaca25ff151d805751c71b878e909d2e7180bacf39dd373b53b09",
1639
+ "baseline_state": "new"
1640
+ },
1641
+ {
1642
+ "finding_id": "INJ-I-0031",
1643
+ "category": "sql_injection",
1644
+ "subtype": "string_concatenation",
1645
+ "title": "SQL Injection in php-plain/order_detail.php:6",
1646
+ "candidate_id": "I-0031",
1647
+ "location": {
1648
+ "file": "php-plain/order_detail.php",
1649
+ "start_line": 6
1650
+ },
1651
+ "evidence": [
1652
+ {
1653
+ "file": "php-plain/order_detail.php",
1654
+ "start_line": 5,
1655
+ "code": "$id = $_GET['id'];",
1656
+ "why": "source: GET parameter",
1657
+ "line": 5
1658
+ },
1659
+ {
1660
+ "file": "php-plain/order_detail.php",
1661
+ "start_line": 6,
1662
+ "code": "$res = mysql_query(\"SELECT * FROM orders WHERE id = \" . $id);",
1663
+ "why": "Unsanitized input concatenated into query",
1664
+ "line": 6
1665
+ }
1666
+ ],
1667
+ "severity": "critical",
1668
+ "confidence": "medium",
1669
+ "cwe": [
1670
+ "CWE-89"
1671
+ ],
1672
+ "recommendation": "Use parameterized queries",
1673
+ "status": "likely",
1674
+ "verification": {
1675
+ "verdict": "likely",
1676
+ "reason_code": "code_not_visible",
1677
+ "checked": [
1678
+ "php-plain/order_detail.php",
1679
+ "php-plain/inc/auth.php",
1680
+ "php-plain/inc/db.php"
1681
+ ],
1682
+ "control_found": null,
1683
+ "notes": "The GET parameter 'id' is concatenated into a SELECT statement without casting or parameter binding. No ownership or role check is visible in the provided context.",
1684
+ "suggested_subtype": null,
1685
+ "suggested_cwe": null
1686
+ },
1687
+ "fingerprint": "kfp1:3065614ddeff53f64ce73f2bd0210f5b36a2249f4d2561f69219095ad867ac9f",
1688
+ "baseline_state": "new"
1689
+ },
1690
+ {
1691
+ "finding_id": "INJ-I-0032",
1692
+ "category": "sql_injection",
1693
+ "subtype": "string_concatenation",
1694
+ "title": "SQL Injection in php-plain/search.php:8",
1695
+ "candidate_id": "I-0032",
1696
+ "location": {
1697
+ "file": "php-plain/search.php",
1698
+ "start_line": 8
1699
+ },
1700
+ "evidence": [
1701
+ {
1702
+ "file": "php-plain/search.php",
1703
+ "start_line": 6,
1704
+ "code": "$sort = $_GET['sort'];",
1705
+ "why": "source: GET parameter",
1706
+ "line": 6
1707
+ },
1708
+ {
1709
+ "file": "php-plain/search.php",
1710
+ "start_line": 9,
1711
+ "code": "$sql .= \" ORDER BY \" . $sort;",
1712
+ "why": "Unsanitized input concatenated into ORDER BY clause",
1713
+ "line": 9
1714
+ }
1715
+ ],
1716
+ "severity": "critical",
1717
+ "confidence": "medium",
1718
+ "cwe": [
1719
+ "CWE-89"
1720
+ ],
1721
+ "recommendation": "Use parameterized queries and allow‑list ORDER BY values",
1722
+ "status": "likely",
1723
+ "verification": {
1724
+ "verdict": "likely",
1725
+ "reason_code": "code_not_visible",
1726
+ "checked": [
1727
+ "php-plain/search.php:6-9"
1728
+ ],
1729
+ "control_found": null,
1730
+ "notes": "The ORDER BY clause is built from the raw $_GET['sort'] value with no cast, allow‑list, or ownership check visible in the provided context.",
1731
+ "suggested_subtype": null,
1732
+ "suggested_cwe": null
1733
+ },
1734
+ "fingerprint": "kfp1:7290ec7c22df15c86f213eb1e27320eaf80f4bafc68a9a6813fb0bd32771b6da",
1735
+ "baseline_state": "new"
1736
+ },
1737
+ {
1738
+ "finding_id": "INJ-I-0033",
1739
+ "category": "sql_injection",
1740
+ "subtype": "string_concatenation",
1741
+ "title": "SQL Injection in php-plain/search.php:9",
1742
+ "candidate_id": "I-0033",
1743
+ "location": {
1744
+ "file": "php-plain/search.php",
1745
+ "start_line": 9
1746
+ },
1747
+ "evidence": [
1748
+ {
1749
+ "file": "php-plain/search.php",
1750
+ "start_line": 6,
1751
+ "code": "$sort = $_GET['sort'];",
1752
+ "why": "source: GET parameter",
1753
+ "line": 6
1754
+ },
1755
+ {
1756
+ "file": "php-plain/search.php",
1757
+ "start_line": 9,
1758
+ "code": "$sql .= \" ORDER BY \" . $sort;",
1759
+ "why": "Unsanitized input concatenated into ORDER BY clause",
1760
+ "line": 9
1761
+ }
1762
+ ],
1763
+ "severity": "critical",
1764
+ "confidence": "medium",
1765
+ "cwe": [
1766
+ "CWE-89"
1767
+ ],
1768
+ "recommendation": "Use parameterized queries and allow‑list ORDER BY values",
1769
+ "status": "likely",
1770
+ "verification": {
1771
+ "verdict": "likely",
1772
+ "reason_code": "code_not_visible",
1773
+ "checked": [
1774
+ "php-plain/search.php:6-9"
1775
+ ],
1776
+ "control_found": null,
1777
+ "notes": "Same as INJ-I-0032: unsanitized ORDER BY input with no visible compensating control.",
1778
+ "suggested_subtype": null,
1779
+ "suggested_cwe": null
1780
+ },
1781
+ "fingerprint": "kfp1:8c4bdd004544c42683c337ca9c80322f9f82a07db96d9b16b80b744a3083e672",
1782
+ "baseline_state": "new"
1783
+ },
1784
+ {
1785
+ "finding_id": "INJ-I-0034",
1786
+ "category": "sql_injection",
1787
+ "subtype": "string_concatenation",
1788
+ "title": "SQL Injection in php-plain/search.php:14",
1789
+ "candidate_id": "I-0034",
1790
+ "location": {
1791
+ "file": "php-plain/search.php",
1792
+ "start_line": 14
1793
+ },
1794
+ "evidence": [
1795
+ {
1796
+ "file": "php-plain/search.php",
1797
+ "start_line": 14,
1798
+ "code": "WHERE category = '{$_GET['cat']}'",
1799
+ "why": "Unsanitized input concatenated into query",
1800
+ "line": 14
1801
+ }
1802
+ ],
1803
+ "severity": "critical",
1804
+ "confidence": "medium",
1805
+ "cwe": [
1806
+ "CWE-89"
1807
+ ],
1808
+ "recommendation": "Use parameterized queries",
1809
+ "status": "likely",
1810
+ "verification": {
1811
+ "verdict": "likely",
1812
+ "reason_code": "code_not_visible",
1813
+ "checked": [
1814
+ "php-plain/search.php:13-15"
1815
+ ],
1816
+ "control_found": null,
1817
+ "notes": "The category filter interpolates $_GET['cat'] directly into the query; no cast, allow‑list, or ownership check is shown.",
1818
+ "suggested_subtype": null,
1819
+ "suggested_cwe": null
1820
+ },
1821
+ "fingerprint": "kfp1:59c91493f8e83065ed0bab7d82438a17443ae7ba9bc82c1659053686f63083d7",
1822
+ "baseline_state": "new"
1823
+ },
1824
+ {
1825
+ "finding_id": "INJ-I-0036",
1826
+ "category": "sql_injection",
1827
+ "subtype": "string_interpolation",
1828
+ "title": "SQL Injection in python-flask/app.py:29",
1829
+ "candidate_id": "I-0036",
1830
+ "location": {
1831
+ "file": "python-flask/app.py",
1832
+ "start_line": 29
1833
+ },
1834
+ "evidence": [
1835
+ {
1836
+ "file": "python-flask/app.py",
1837
+ "start_line": 29,
1838
+ "code": "cur.execute(f\"SELECT * FROM products WHERE name LIKE '%{q}%'\")",
1839
+ "why": "Unsanitized input interpolated into query",
1840
+ "line": 29
1841
+ }
1842
+ ],
1843
+ "severity": "critical",
1844
+ "confidence": "medium",
1845
+ "cwe": [
1846
+ "CWE-89"
1847
+ ],
1848
+ "recommendation": "Use parameterized queries",
1849
+ "status": "likely",
1850
+ "verification": {
1851
+ "verdict": "likely",
1852
+ "reason_code": "code_not_visible",
1853
+ "checked": [
1854
+ "python-flask/app.py:24-30"
1855
+ ],
1856
+ "control_found": null,
1857
+ "notes": "The search route uses an f‑string to embed the user supplied 'q' directly into the SQL; no parameter binding or ownership check is visible.",
1858
+ "suggested_subtype": null,
1859
+ "suggested_cwe": null
1860
+ },
1861
+ "fingerprint": "kfp1:52c1a1b2beb4129f6fbbfa5c9bcc2f05de1cb6b4a835dcb6adfa7075c03edf79",
1862
+ "baseline_state": "new"
1863
+ },
1864
+ {
1865
+ "finding_id": "INJ-I-0037",
1866
+ "category": "sql_injection",
1867
+ "subtype": "stored_procedure_dynamic_sql",
1868
+ "title": "SQL Injection in sql-procs/sp_search_orders.sql:5",
1869
+ "candidate_id": "I-0037",
1870
+ "location": {
1871
+ "file": "sql-procs/sp_search_orders.sql",
1872
+ "start_line": 5
1873
+ },
1874
+ "evidence": [
1875
+ {
1876
+ "file": "sql-procs/sp_search_orders.sql",
1877
+ "start_line": 5,
1878
+ "code": "SET @sql = 'SELECT * FROM Orders WHERE Customer = ''' + @Customer + ''' ORDER BY ' + @Sort",
1879
+ "why": "Dynamic SQL built from user‑supplied parameters without validation",
1880
+ "line": 5
1881
+ }
1882
+ ],
1883
+ "severity": "critical",
1884
+ "confidence": "medium",
1885
+ "cwe": [
1886
+ "CWE-89"
1887
+ ],
1888
+ "recommendation": "Avoid dynamic SQL; use parameterized queries or validate @Sort against an allow‑list",
1889
+ "status": "likely",
1890
+ "verification": {
1891
+ "verdict": "likely",
1892
+ "reason_code": "code_not_visible",
1893
+ "checked": [
1894
+ "sql-procs/sp_search_orders.sql:4-6"
1895
+ ],
1896
+ "control_found": null,
1897
+ "notes": "Dynamic SQL is built from user‑supplied parameters without any visible validation or allow‑list. No ownership or role check is shown.",
1898
+ "suggested_subtype": null,
1899
+ "suggested_cwe": null
1900
+ },
1901
+ "fingerprint": "kfp1:dda6a5bb147b8aa741739e9da8799b0f942492567758d5d3209c1395a97c8f98",
1902
+ "baseline_state": "new"
1903
+ },
1904
+ {
1905
+ "finding_id": "MASS-M-0006-1",
1906
+ "category": "mass_assignment",
1907
+ "subtype": "whole_object_binding",
1908
+ "title": "Profile update binds entire request body to User model",
1909
+ "candidate_id": "M-0006",
1910
+ "location": {
1911
+ "file": "routes/profile.js",
1912
+ "start_line": 7
1913
+ },
1914
+ "evidence": [
1915
+ {
1916
+ "file": "routes/profile.js",
1917
+ "line": 7,
1918
+ "why": "ensureLoggedIn only checks authentication"
1919
+ },
1920
+ {
1921
+ "file": "routes/profile.js",
1922
+ "line": 8,
1923
+ "why": "User.findByIdAndUpdate(req.user._id, req.body, ...) binds whole body"
1924
+ }
1925
+ ],
1926
+ "impact": "Any authenticated user can set privileged fields such as role or admin flag via the profile update endpoint.",
1927
+ "severity": "critical",
1928
+ "confidence": "medium",
1929
+ "cwe": [
1930
+ "CWE-915"
1931
+ ],
1932
+ "recommendation": "Limit bound fields to a whitelist and set privileged fields server‑side.",
1933
+ "status": "likely",
1934
+ "verification": {
1935
+ "verdict": "likely",
1936
+ "reason_code": "code_not_visible",
1937
+ "checked": [
1938
+ "routes/profile.js not found"
1939
+ ],
1940
+ "control_found": null,
1941
+ "notes": "The referenced file is missing from the repository; no ownership or role checks are visible in the provided context.",
1942
+ "suggested_subtype": null,
1943
+ "suggested_cwe": null
1944
+ },
1945
+ "fingerprint": "kfp1:960f064246c57436e1c9e73b6d68a73e2f12c9706d42cf23db19d5ba53deb4de",
1946
+ "baseline_state": "new"
1947
+ },
1948
+ {
1949
+ "finding_id": "MASS-M-0008-1",
1950
+ "category": "mass_assignment",
1951
+ "subtype": "whole_object_binding",
1952
+ "title": "User registration binds entire request body to User model",
1953
+ "candidate_id": "M-0008",
1954
+ "location": {
1955
+ "file": "app/Http/Controllers/AccountController.php",
1956
+ "start_line": 11
1957
+ },
1958
+ "evidence": [
1959
+ {
1960
+ "file": "app/Http/Controllers/AccountController.php",
1961
+ "line": 13,
1962
+ "why": "User::create($request->all()) binds whole body"
1963
+ }
1964
+ ],
1965
+ "impact": "Any user can set privileged fields such as role or admin flag during registration.",
1966
+ "severity": "critical",
1967
+ "confidence": "medium",
1968
+ "cwe": [
1969
+ "CWE-915"
1970
+ ],
1971
+ "recommendation": "Use $fillable or guarded properties to restrict writable fields.",
1972
+ "status": "likely",
1973
+ "verification": {
1974
+ "verdict": "likely",
1975
+ "reason_code": "code_not_visible",
1976
+ "checked": [
1977
+ "app/Http/Controllers/AccountController.php not found"
1978
+ ],
1979
+ "control_found": null,
1980
+ "notes": "The controller file is missing; no indication of $fillable or guarded properties in the visible context.",
1981
+ "suggested_subtype": null,
1982
+ "suggested_cwe": null
1983
+ },
1984
+ "fingerprint": "kfp1:5ad56d30cbf69c227a69cbcbfcd26f42733998e980cae7d122d7bcec7ea73ebc",
1985
+ "baseline_state": "new"
1986
+ },
1987
+ {
1988
+ "finding_id": "MASS-M-0009-1",
1989
+ "category": "mass_assignment",
1990
+ "subtype": "privileged_field_writable",
1991
+ "title": "Team creation allows setting owner_id via request body",
1992
+ "candidate_id": "M-0009",
1993
+ "location": {
1994
+ "file": "app/Http/Controllers/AccountController.php",
1995
+ "start_line": 21
1996
+ },
1997
+ "evidence": [
1998
+ {
1999
+ "file": "app/Http/Controllers/AccountController.php",
2000
+ "line": 23,
2001
+ "why": "Team::create($request->all()) binds whole body, including owner_id"
2002
+ }
2003
+ ],
2004
+ "impact": "Any user can set the owner_id of a team, effectively assigning ownership to themselves or others.",
2005
+ "severity": "critical",
2006
+ "confidence": "medium",
2007
+ "cwe": [
2008
+ "CWE-915",
2009
+ "CWE-269"
2010
+ ],
2011
+ "recommendation": "Do not allow owner_id to be set from the request; set it server‑side to the authenticated user.",
2012
+ "status": "likely",
2013
+ "verification": {
2014
+ "verdict": "likely",
2015
+ "reason_code": "code_not_visible",
2016
+ "checked": [
2017
+ "app/Http/Controllers/AccountController.php not found"
2018
+ ],
2019
+ "control_found": null,
2020
+ "notes": "The file containing the team creation logic is not available; ownership enforcement cannot be confirmed.",
2021
+ "suggested_subtype": null,
2022
+ "suggested_cwe": null
2023
+ },
2024
+ "fingerprint": "kfp1:28b0be984e1eb817cca53b79b6014265eda827fcca1b7ec8b48937bc11d7576e",
2025
+ "baseline_state": "new"
2026
+ },
2027
+ {
2028
+ "finding_id": "MASS-M-0011-1",
2029
+ "category": "mass_assignment",
2030
+ "subtype": "whole_object_binding",
2031
+ "title": "Unrestricted binding of all POST fields to User in PHP plain",
2032
+ "candidate_id": "M-0011",
2033
+ "location": {
2034
+ "file": "php-plain/profile.php",
2035
+ "start_line": 1
2036
+ },
2037
+ "evidence": [
2038
+ {
2039
+ "file": "php-plain/profile.php",
2040
+ "line": 6,
2041
+ "why": "foreach ($_POST as $field => $value) { $user->$field = $value; } (binds all fields)"
2042
+ },
2043
+ {
2044
+ "file": "php-plain/profile.php",
2045
+ "line": 10,
2046
+ "why": "$user->role = $_POST['role']; (privileged field)"
2047
+ },
2048
+ {
2049
+ "file": "php-plain/profile.php",
2050
+ "line": 11,
2051
+ "why": "save_user($user); (writes role to DB)"
2052
+ }
2053
+ ],
2054
+ "impact": "role field can be set by the caller.",
2055
+ "severity": "critical",
2056
+ "confidence": "high",
2057
+ "cwe": [
2058
+ "CWE-915"
2059
+ ],
2060
+ "recommendation": "Restrict binding to allowed fields or set privileged fields server‑side.",
2061
+ "status": "confirmed",
2062
+ "verification": {
2063
+ "verdict": "confirmed",
2064
+ "reason_code": "traced",
2065
+ "checked": [
2066
+ "php-plain/profile.php",
2067
+ "php-plain/inc/auth.php"
2068
+ ],
2069
+ "control_found": null,
2070
+ "notes": "The entire POST payload is assigned to the user object, allowing any field—including privileged ones—to be modified. No whitelist or server‑side restriction is visible.",
2071
+ "suggested_subtype": null,
2072
+ "suggested_cwe": null
2073
+ },
2074
+ "fingerprint": "kfp1:e3a2d567a27e2b4f56e09fcd14f753ae26f90e2703f217a25929619bb1710391",
2075
+ "baseline_state": "new"
2076
+ },
2077
+ {
2078
+ "finding_id": "MASS-M-0012-1",
2079
+ "category": "mass_assignment",
2080
+ "subtype": "privileged_field_writable",
2081
+ "title": "Privilege escalation via role field in PHP plain",
2082
+ "candidate_id": "M-0012",
2083
+ "location": {
2084
+ "file": "php-plain/profile.php",
2085
+ "start_line": 1
2086
+ },
2087
+ "evidence": [
2088
+ {
2089
+ "file": "php-plain/profile.php",
2090
+ "line": 10,
2091
+ "why": "$user->role = $_POST['role']; (privileged field)"
2092
+ },
2093
+ {
2094
+ "file": "php-plain/profile.php",
2095
+ "line": 11,
2096
+ "why": "save_user($user); (writes role to DB)"
2097
+ }
2098
+ ],
2099
+ "impact": "role field can be set by the caller.",
2100
+ "severity": "critical",
2101
+ "confidence": "high",
2102
+ "cwe": [
2103
+ "CWE-915",
2104
+ "CWE-269"
2105
+ ],
2106
+ "recommendation": "Restrict binding to allowed fields or set privileged fields server‑side.",
2107
+ "status": "confirmed",
2108
+ "verification": {
2109
+ "verdict": "confirmed",
2110
+ "reason_code": "traced",
2111
+ "checked": [
2112
+ "php-plain/profile.php",
2113
+ "php-plain/inc/auth.php"
2114
+ ],
2115
+ "control_found": null,
2116
+ "notes": "The 'role' field is explicitly set from POST data and persisted without any server‑side validation or restriction. No compensating control is present in the code context.",
2117
+ "suggested_subtype": null,
2118
+ "suggested_cwe": null
2119
+ },
2120
+ "fingerprint": "kfp1:9b1558f54dcebcc6cf73a1ee19b650fe4c278826d8afc5996df01f7beb944136",
2121
+ "baseline_state": "new"
2122
+ },
2123
+ {
2124
+ "finding_id": "MASS-M-0013-1",
2125
+ "category": "mass_assignment",
2126
+ "subtype": "whole_object_binding",
2127
+ "title": "User insertion uses extract($_POST) to bind all POST fields",
2128
+ "candidate_id": "M-0013",
2129
+ "location": {
2130
+ "file": "register.php",
2131
+ "start_line": 4
2132
+ },
2133
+ "evidence": [
2134
+ {
2135
+ "file": "register.php",
2136
+ "line": 4,
2137
+ "why": "extract($_POST) pulls all POST fields into variables"
2138
+ },
2139
+ {
2140
+ "file": "register.php",
2141
+ "line": 5,
2142
+ "why": "INSERT uses $email and $name from extracted variables"
2143
+ }
2144
+ ],
2145
+ "impact": "Any POST field can be inserted into the users table, including privileged columns if they exist.",
2146
+ "severity": "critical",
2147
+ "confidence": "medium",
2148
+ "cwe": [
2149
+ "CWE-915"
2150
+ ],
2151
+ "recommendation": "Avoid extract(); explicitly bind only allowed fields.",
2152
+ "status": "likely",
2153
+ "verification": {
2154
+ "verdict": "likely",
2155
+ "reason_code": "code_not_visible",
2156
+ "checked": [
2157
+ "register.php not found"
2158
+ ],
2159
+ "control_found": null,
2160
+ "notes": "The registration script is absent from the repository; the use of extract($_POST) cannot be verified.",
2161
+ "suggested_subtype": null,
2162
+ "suggested_cwe": null
2163
+ },
2164
+ "fingerprint": "kfp1:4ef54743c456d54a13b613bfd333eb34b9ad8281e87c415b4633f31cda20a0ce",
2165
+ "baseline_state": "new"
2166
+ },
2167
+ {
2168
+ "finding_id": "MASS-M-0014-1",
2169
+ "category": "mass_assignment",
2170
+ "subtype": "whole_object_binding",
2171
+ "title": "User creation binds entire request JSON to User model",
2172
+ "candidate_id": "M-0014",
2173
+ "location": {
2174
+ "file": "app.py",
2175
+ "start_line": 8
2176
+ },
2177
+ "evidence": [
2178
+ {
2179
+ "file": "app.py",
2180
+ "line": 10,
2181
+ "why": "User(**request.json) binds all JSON fields"
2182
+ }
2183
+ ],
2184
+ "impact": "Any user can set privileged fields such as role or admin flag during account creation.",
2185
+ "severity": "critical",
2186
+ "confidence": "medium",
2187
+ "cwe": [
2188
+ "CWE-915"
2189
+ ],
2190
+ "recommendation": "Use a DTO or whitelist to restrict writable fields.",
2191
+ "status": "likely",
2192
+ "verification": {
2193
+ "verdict": "likely",
2194
+ "reason_code": "code_not_visible",
2195
+ "checked": [
2196
+ "app.py not present in provided code_context"
2197
+ ],
2198
+ "control_found": null,
2199
+ "notes": "The user creation code that binds the entire request JSON is not shown; therefore it is impossible to confirm the presence or absence of a whitelist or other protective measure.",
2200
+ "suggested_subtype": null,
2201
+ "suggested_cwe": null
2202
+ },
2203
+ "fingerprint": "kfp1:ce4a5edbc11d47f0e7f1c8880eb0c744ee98ee0f2834696e9ac8642ee6281773",
2204
+ "baseline_state": "new"
2205
+ },
2206
+ {
2207
+ "finding_id": "MASS-M-0015-1",
2208
+ "category": "mass_assignment",
2209
+ "subtype": "whole_object_binding",
2210
+ "title": "PATCH endpoint sets arbitrary attributes from request JSON",
2211
+ "candidate_id": "M-0015",
2212
+ "location": {
2213
+ "file": "app.py",
2214
+ "start_line": 24
2215
+ },
2216
+ "evidence": [
2217
+ {
2218
+ "file": "app.py",
2219
+ "line": 27,
2220
+ "why": "for key, value in request.json.items(): setattr(user, key, value) binds all fields"
2221
+ }
2222
+ ],
2223
+ "impact": "Any user can modify any attribute of the user record, including privileged fields.",
2224
+ "severity": "critical",
2225
+ "confidence": "medium",
2226
+ "cwe": [
2227
+ "CWE-915"
2228
+ ],
2229
+ "recommendation": "Whitelist allowed fields or use a DTO.",
2230
+ "status": "likely",
2231
+ "verification": {
2232
+ "verdict": "likely",
2233
+ "reason_code": "code_not_visible",
2234
+ "checked": [
2235
+ "app.py not present in provided code_context"
2236
+ ],
2237
+ "control_found": null,
2238
+ "notes": "The relevant code that performs the PATCH binding is not included in the supplied context, so no compensating control can be verified.",
2239
+ "suggested_subtype": null,
2240
+ "suggested_cwe": null
2241
+ },
2242
+ "fingerprint": "kfp1:2b45c26cb0e79c67cde4ca5fd3bda885bdbc5af1c02aab97781ca4656b950580",
2243
+ "baseline_state": "new"
2244
+ },
2245
+ {
2246
+ "finding_id": "BOLA-R-0001-1",
2247
+ "category": "bola",
2248
+ "subtype": "missing_ownership_check",
2249
+ "title": "BOLA in POST /user/edit.do: missing owner verification",
2250
+ "route_id": "R-0001",
2251
+ "endpoint": {
2252
+ "method": "POST",
2253
+ "path": "/user/edit.do"
2254
+ },
2255
+ "location": {
2256
+ "file": "java-legacy/src/com/acme/struts/EditUserAction.java",
2257
+ "start_line": 13
2258
+ },
2259
+ "evidence": [
2260
+ {
2261
+ "file": "java-legacy/src/com/acme/struts/EditUserAction.java",
2262
+ "start_line": 13,
2263
+ "code": "PreparedStatement ps = conn.prepareStatement(\"UPDATE users SET email = '\" + email + \"' WHERE id = \" + userId);",
2264
+ "why": "The user ID comes from the request and is used directly in the UPDATE without checking that the current user owns the record.",
2265
+ "line": 13
2266
+ }
2267
+ ],
2268
+ "severity": "high",
2269
+ "confidence": "medium",
2270
+ "cwe": [
2271
+ "CWE-284",
2272
+ "CWE-639"
2273
+ ],
2274
+ "recommendation": "Bind the UPDATE to the current session user.",
2275
+ "status": "likely",
2276
+ "verification": {
2277
+ "verdict": "likely",
2278
+ "reason_code": "code_not_visible",
2279
+ "checked": [
2280
+ "EditUserAction.java:10-13"
2281
+ ],
2282
+ "control_found": null,
2283
+ "notes": "The code shows the userId coming directly from the request and used in an UPDATE statement without any ownership check, cast, or parameter binding. No ownership helper or allow‑list is visible in the provided context.",
2284
+ "suggested_subtype": null,
2285
+ "suggested_cwe": null
2286
+ },
2287
+ "fingerprint": "kfp1:020aa146c52bc68c1ec20e392577ed8c894b9dbe9c4f2063f660e4d6d22dd065",
2288
+ "baseline_state": "new"
2289
+ },
2290
+ {
2291
+ "finding_id": "BOLA-R-0002-1",
2292
+ "category": "bola",
2293
+ "subtype": "missing_ownership_check",
2294
+ "title": "BOLA in POST /classic-asp/shop/member.asp?mode=edit: missing owner verification",
2295
+ "route_id": "R-0002",
2296
+ "endpoint": {
2297
+ "method": "POST",
2298
+ "path": "/classic-asp/shop/member.asp?mode=edit"
2299
+ },
2300
+ "location": {
2301
+ "file": "classic-asp/shop/member.asp",
2302
+ "start_line": 6
2303
+ },
2304
+ "evidence": [
2305
+ {
2306
+ "file": "classic-asp/shop/member.asp",
2307
+ "start_line": 6,
2308
+ "code": "sql = \"UPDATE members SET name = '\" & Replace(Request.Form(\"name\"), \"'\", \"''\") & \"'\"",
2309
+ "why": "The member_id comes from the request and is used directly in the UPDATE without verifying ownership.",
2310
+ "line": 6
2311
+ },
2312
+ {
2313
+ "file": "classic-asp/shop/member.asp",
2314
+ "start_line": 7,
2315
+ "code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
2316
+ "why": "No ownership check is performed.",
2317
+ "line": 7
2318
+ }
2319
+ ],
2320
+ "severity": "high",
2321
+ "confidence": "medium",
2322
+ "cwe": [
2323
+ "CWE-284",
2324
+ "CWE-639"
2325
+ ],
2326
+ "recommendation": "Add an ownership check to the UPDATE statement.",
2327
+ "status": "likely",
2328
+ "verification": {
2329
+ "verdict": "likely",
2330
+ "reason_code": "code_not_visible",
2331
+ "checked": [
2332
+ "classic-asp/shop/member.asp:6-7",
2333
+ "classic-asp/shop/inc/auth.asp",
2334
+ "classic-asp/shop/inc/conn.asp"
2335
+ ],
2336
+ "control_found": null,
2337
+ "notes": "The UPDATE statement uses member_id from the request without any ownership verification. The included auth file only checks for a non‑empty session, not for ownership.",
2338
+ "suggested_subtype": null,
2339
+ "suggested_cwe": null
2340
+ },
2341
+ "fingerprint": "kfp1:4f17dfd44c8dd14ba50f2b144cc03ac41240bb9bb68f5202789da944e2759f40",
2342
+ "baseline_state": "new"
2343
+ },
2344
+ {
2345
+ "finding_id": "BOLA-R-0003-1",
2346
+ "category": "bola",
2347
+ "subtype": "missing_ownership_check",
2348
+ "title": "BOLA in DELETE /classic-asp/shop/member.asp?mode=delete: missing owner verification",
2349
+ "route_id": "R-0003",
2350
+ "endpoint": {
2351
+ "method": "DELETE",
2352
+ "path": "/classic-asp/shop/member.asp?mode=delete"
2353
+ },
2354
+ "location": {
2355
+ "file": "classic-asp/shop/member.asp",
2356
+ "start_line": 10
2357
+ },
2358
+ "evidence": [
2359
+ {
2360
+ "file": "classic-asp/shop/member.asp",
2361
+ "start_line": 10,
2362
+ "code": "conn.Execute \"DELETE FROM members WHERE member_id = \" & Request.QueryString(\"member_id\")",
2363
+ "why": "The member_id comes from the request and is used directly in the DELETE without verifying ownership.",
2364
+ "line": 10
2365
+ }
2366
+ ],
2367
+ "severity": "high",
2368
+ "confidence": "medium",
2369
+ "cwe": [
2370
+ "CWE-284",
2371
+ "CWE-639"
2372
+ ],
2373
+ "recommendation": "Add an ownership check to the DELETE statement.",
2374
+ "status": "likely",
2375
+ "verification": {
2376
+ "verdict": "likely",
2377
+ "reason_code": "code_not_visible",
2378
+ "checked": [
2379
+ "classic-asp/shop/member.asp:10",
2380
+ "classic-asp/shop/inc/auth.asp",
2381
+ "classic-asp/shop/inc/conn.asp"
2382
+ ],
2383
+ "control_found": null,
2384
+ "notes": "The DELETE statement uses member_id from the request directly. No ownership check or cast is present in the visible code.",
2385
+ "suggested_subtype": null,
2386
+ "suggested_cwe": null
2387
+ },
2388
+ "fingerprint": "kfp1:427d8c8183aaeb95efed29f8cc59aaedd24ce0bd29b2d96a7aab38c5f7500718",
2389
+ "baseline_state": "new"
2390
+ },
2391
+ {
2392
+ "finding_id": "BOLA-R-0004-1",
2393
+ "category": "bola",
2394
+ "subtype": "missing_ownership_check",
2395
+ "title": "BOLA in GET /classic-asp/shop/order.asp: missing owner verification",
2396
+ "route_id": "R-0004",
2397
+ "endpoint": {
2398
+ "method": "GET",
2399
+ "path": "/classic-asp/shop/order.asp"
2400
+ },
2401
+ "location": {
2402
+ "file": "classic-asp/shop/order.asp",
2403
+ "start_line": 5
2404
+ },
2405
+ "evidence": [
2406
+ {
2407
+ "file": "classic-asp/shop/order.asp",
2408
+ "start_line": 5,
2409
+ "code": "id = Request(\"id\")",
2410
+ "why": "The order id comes from the request.",
2411
+ "line": 5
2412
+ },
2413
+ {
2414
+ "file": "classic-asp/shop/order.asp",
2415
+ "start_line": 6,
2416
+ "code": "Set rs = conn.Execute(\"SELECT * FROM orders WHERE id = \" & id)",
2417
+ "why": "No ownership check is performed; any user can read any order.",
2418
+ "line": 6
2419
+ }
2420
+ ],
2421
+ "severity": "high",
2422
+ "confidence": "medium",
2423
+ "cwe": [
2424
+ "CWE-284",
2425
+ "CWE-639"
2426
+ ],
2427
+ "recommendation": "Bind the SELECT to the current session user.",
2428
+ "status": "likely",
2429
+ "verification": {
2430
+ "verdict": "likely",
2431
+ "reason_code": "code_not_visible",
2432
+ "checked": [
2433
+ "classic-asp/shop/order.asp:5-6",
2434
+ "classic-asp/shop/inc/auth.asp",
2435
+ "classic-asp/shop/inc/conn.asp"
2436
+ ],
2437
+ "control_found": null,
2438
+ "notes": "The first SELECT query retrieves an order by id supplied in the request without verifying that the current user owns the order. The later query that uses Session(\"UserID\") is unrelated to the initial unprotected query.",
2439
+ "suggested_subtype": null,
2440
+ "suggested_cwe": null
2441
+ },
2442
+ "fingerprint": "kfp1:159c3f83b77db97472a5cd38910bcb4e83013df93f05a4bb18fc6b9a7923554a",
2443
+ "baseline_state": "new"
2444
+ },
2445
+ {
2446
+ "finding_id": "BOLA-R-0005-1",
2447
+ "category": "bola",
2448
+ "subtype": "missing_ownership_check",
2449
+ "title": "BOLA in GET /coldfusion/app/OrderService.cfc?method=getOrder: missing owner verification",
2450
+ "route_id": "R-0005",
2451
+ "endpoint": {
2452
+ "method": "GET",
2453
+ "path": "/coldfusion/app/OrderService.cfc?method=getOrder"
2454
+ },
2455
+ "location": {
2456
+ "file": "coldfusion/app/OrderService.cfc",
2457
+ "start_line": 4
2458
+ },
2459
+ "evidence": [
2460
+ {
2461
+ "file": "coldfusion/app/OrderService.cfc",
2462
+ "start_line": 4,
2463
+ "code": "<cfquery name=\"q\" datasource=\"shop\"> SELECT * FROM orders WHERE id = #arguments.orderId#",
2464
+ "why": "The orderId comes from the request and is used directly without checking ownership.",
2465
+ "line": 4
2466
+ }
2467
+ ],
2468
+ "severity": "high",
2469
+ "confidence": "medium",
2470
+ "cwe": [
2471
+ "CWE-284",
2472
+ "CWE-639"
2473
+ ],
2474
+ "recommendation": "Add an ownership check to the SELECT statement.",
2475
+ "status": "likely",
2476
+ "verification": {
2477
+ "verdict": "likely",
2478
+ "reason_code": "code_not_visible",
2479
+ "checked": [
2480
+ "coldfusion/app/OrderService.cfc:4-5"
2481
+ ],
2482
+ "control_found": null,
2483
+ "notes": "The query interpolates arguments.orderId directly into the SQL without any ownership check, cast, or allow‑list. No ownership helper is visible in the provided context.",
2484
+ "suggested_subtype": null,
2485
+ "suggested_cwe": null
2486
+ },
2487
+ "fingerprint": "kfp1:243a733bd2e922d1405825de128bec5613258ec9c2f0c9b98b7bd36008c6dfe1",
2488
+ "baseline_state": "new"
2489
+ },
2490
+ {
2491
+ "finding_id": "BOLA-R-0006-1",
2492
+ "category": "bola",
2493
+ "subtype": "missing_ownership_check",
2494
+ "title": "BOLA in GET /coldfusion/app/order.cfm: missing owner verification",
2495
+ "route_id": "R-0006",
2496
+ "endpoint": {
2497
+ "method": "GET",
2498
+ "path": "/coldfusion/app/order.cfm"
2499
+ },
2500
+ "location": {
2501
+ "file": "coldfusion/app/order.cfm",
2502
+ "start_line": 3
2503
+ },
2504
+ "evidence": [
2505
+ {
2506
+ "file": "coldfusion/app/order.cfm",
2507
+ "start_line": 3,
2508
+ "code": "<cfquery name=\"qOrder\" datasource=\"shop\"> SELECT * FROM orders WHERE id = #url.id#",
2509
+ "why": "The id comes from the request and is used directly without checking ownership.",
2510
+ "line": 3
2511
+ }
2512
+ ],
2513
+ "severity": "high",
2514
+ "confidence": "medium",
2515
+ "cwe": [
2516
+ "CWE-284",
2517
+ "CWE-639"
2518
+ ],
2519
+ "recommendation": "Add an ownership check to the SELECT statement.",
2520
+ "status": "likely",
2521
+ "verification": {
2522
+ "verdict": "likely",
2523
+ "reason_code": "code_not_visible",
2524
+ "checked": [
2525
+ "coldfusion/app/order.cfm:1-10"
2526
+ ],
2527
+ "control_found": null,
2528
+ "notes": "The query that retrieves the order uses the request id directly and no ownership check or cast is visible in the provided code context.",
2529
+ "suggested_subtype": null,
2530
+ "suggested_cwe": null
2531
+ },
2532
+ "fingerprint": "kfp1:96946880c41b3f3f959ccab3d04dda131439d50cd329c2738de809f5fd395bf9",
2533
+ "baseline_state": "new"
2534
+ },
2535
+ {
2536
+ "finding_id": "BOLA-R-0007-1",
2537
+ "category": "bola",
2538
+ "subtype": "missing_ownership_check",
2539
+ "title": "BOLA in POST /Admin/DeleteUser: missing owner verification",
2540
+ "route_id": "R-0007",
2541
+ "endpoint": {
2542
+ "method": "POST",
2543
+ "path": "/Admin/DeleteUser"
2544
+ },
2545
+ "location": {
2546
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2547
+ "start_line": 12
2548
+ },
2549
+ "evidence": [
2550
+ {
2551
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2552
+ "start_line": 12,
2553
+ "code": "public ActionResult DeleteUser(int id) { var u = db.Users.Find(id); db.Users.Remove(u); db.SaveChanges(); }",
2554
+ "why": "The user id comes from the request and is used directly without verifying that the current user owns the account.",
2555
+ "line": 12
2556
+ }
2557
+ ],
2558
+ "severity": "high",
2559
+ "confidence": "medium",
2560
+ "cwe": [
2561
+ "CWE-284",
2562
+ "CWE-639"
2563
+ ],
2564
+ "recommendation": "Require admin role or check that the current user is the owner before deleting.",
2565
+ "status": "likely",
2566
+ "verification": {
2567
+ "verdict": "likely",
2568
+ "reason_code": "code_not_visible",
2569
+ "checked": [
2570
+ "dotnet-legacy/Web/Controllers/AdminController.cs:11-18"
2571
+ ],
2572
+ "control_found": null,
2573
+ "notes": "The DeleteUser action is protected only by a generic [Authorize] attribute; no role or ownership check is present in the visible code.",
2574
+ "suggested_subtype": null,
2575
+ "suggested_cwe": null
2576
+ },
2577
+ "fingerprint": "kfp1:ff7ce7baa2540985e6cf2198bc15a646ece40603a915b3ccbe7e0fb05ccca5d7",
2578
+ "baseline_state": "new"
2579
+ },
2580
+ {
2581
+ "finding_id": "BOLA-R-0008-1",
2582
+ "category": "bola",
2583
+ "subtype": "missing_ownership_check",
2584
+ "title": "BOLA in POST /Admin/Export: missing role verification",
2585
+ "route_id": "R-0008",
2586
+ "endpoint": {
2587
+ "method": "POST",
2588
+ "path": "/Admin/Export"
2589
+ },
2590
+ "location": {
2591
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2592
+ "start_line": 32
2593
+ },
2594
+ "evidence": [
2595
+ {
2596
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2597
+ "start_line": 32,
2598
+ "code": "if (Request.QueryString[\"isAdmin\"] == \"true\") { return Json(db.Users.ToList(), JsonRequestBehavior.AllowGet); }",
2599
+ "why": "No role check; any authenticated user can set isAdmin=true and retrieve all users.",
2600
+ "line": 32
2601
+ }
2602
+ ],
2603
+ "severity": "high",
2604
+ "confidence": "medium",
2605
+ "cwe": [
2606
+ "CWE-284",
2607
+ "CWE-639"
2608
+ ],
2609
+ "recommendation": "Enforce admin role before returning the user list.",
2610
+ "status": "likely",
2611
+ "verification": {
2612
+ "verdict": "likely",
2613
+ "reason_code": "code_not_visible",
2614
+ "checked": [
2615
+ "dotnet-legacy/Web/Controllers/AdminController.cs:30-36"
2616
+ ],
2617
+ "control_found": null,
2618
+ "notes": "The Export action checks only a query string flag; no role or ownership verification is shown.",
2619
+ "suggested_subtype": null,
2620
+ "suggested_cwe": null
2621
+ },
2622
+ "fingerprint": "kfp1:66e16dddb13d27bd3f5d954a5d2ef2cb7e8b37bf54747ea0bd96b076c4851ca4",
2623
+ "baseline_state": "new"
2624
+ },
2625
+ {
2626
+ "finding_id": "BOLA-R-0009-1",
2627
+ "category": "bola",
2628
+ "subtype": "missing_ownership_check",
2629
+ "title": "BOLA in POST /Admin/Export: missing role verification",
2630
+ "route_id": "R-0009",
2631
+ "endpoint": {
2632
+ "method": "POST",
2633
+ "path": "/Admin/Export"
2634
+ },
2635
+ "location": {
2636
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2637
+ "start_line": 32
2638
+ },
2639
+ "evidence": [
2640
+ {
2641
+ "file": "dotnet-legacy/Web/Controllers/AdminController.cs",
2642
+ "start_line": 32,
2643
+ "code": "if (Request.QueryString[\"isAdmin\"] == \"true\") { return Json(db.Users.ToList(), JsonRequestBehavior.AllowGet); }",
2644
+ "why": "No role check; any authenticated user can set isAdmin=true and retrieve all users.",
2645
+ "line": 32
2646
+ }
2647
+ ],
2648
+ "severity": "high",
2649
+ "confidence": "medium",
2650
+ "cwe": [
2651
+ "CWE-284",
2652
+ "CWE-639"
2653
+ ],
2654
+ "recommendation": "Enforce admin role before returning the user list.",
2655
+ "status": "likely",
2656
+ "verification": {
2657
+ "verdict": "likely",
2658
+ "reason_code": "code_not_visible",
2659
+ "checked": [
2660
+ "dotnet-legacy/Web/Controllers/AdminController.cs:30-36"
2661
+ ],
2662
+ "control_found": null,
2663
+ "notes": "Same as BOLA-R-0008-1; no role or ownership check is visible.",
2664
+ "suggested_subtype": null,
2665
+ "suggested_cwe": null
2666
+ },
2667
+ "fingerprint": "kfp1:492f77e1febfc11adeac541fe8d9b4c2c8531dda2f863b6cb0afcdd41cbd01ca",
2668
+ "baseline_state": "new"
2669
+ },
2670
+ {
2671
+ "finding_id": "BOLA-R-0010",
2672
+ "category": "bola",
2673
+ "subtype": "missing_ownership_check",
2674
+ "title": "BOLA in POST /Customer/Edit: missing owner verification",
2675
+ "route_id": "R-0010",
2676
+ "endpoint": {
2677
+ "method": "POST",
2678
+ "path": "/Customer/Edit"
2679
+ },
2680
+ "location": {
2681
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2682
+ "start_line": 12
2683
+ },
2684
+ "evidence": [
2685
+ {
2686
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2687
+ "start_line": 12,
2688
+ "code": "public ActionResult Edit(Customer customer)\n{\n db.Entry(customer).State = System.Data.Entity.EntityState.Modified;\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
2689
+ "why": "The Customer object is bound directly from the request and saved without checking that customer.Id belongs to the authenticated user.",
2690
+ "line": 12
2691
+ }
2692
+ ],
2693
+ "severity": "high",
2694
+ "confidence": "high",
2695
+ "cwe": [
2696
+ "CWE-284",
2697
+ "CWE-639"
2698
+ ],
2699
+ "recommendation": "Ensure the customer being edited belongs to the current user or that the user has permission to edit it.",
2700
+ "status": "confirmed",
2701
+ "verification": {
2702
+ "verdict": "confirmed",
2703
+ "reason_code": "traced",
2704
+ "checked": [
2705
+ "dotnet-legacy/Web/Controllers/CustomerController.cs lines 6-16"
2706
+ ],
2707
+ "control_found": null,
2708
+ "notes": "The action is protected by [Authorize] (ensuring authentication) but performs a direct update of the bound Customer entity without verifying that the customer belongs to the current user.",
2709
+ "suggested_subtype": null,
2710
+ "suggested_cwe": null
2711
+ },
2712
+ "fingerprint": "kfp1:2ff50be6396a3261e2543aa3b955d99113acdc748a014446cb0b489407bafe90",
2713
+ "baseline_state": "new"
2714
+ },
2715
+ {
2716
+ "finding_id": "BOLA-R-0011",
2717
+ "category": "bola",
2718
+ "subtype": "missing_ownership_check",
2719
+ "title": "BOLA in POST /Customer/EditName: missing owner verification",
2720
+ "route_id": "R-0011",
2721
+ "endpoint": {
2722
+ "method": "POST",
2723
+ "path": "/Customer/EditName"
2724
+ },
2725
+ "location": {
2726
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2727
+ "start_line": 20
2728
+ },
2729
+ "evidence": [
2730
+ {
2731
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2732
+ "start_line": 20,
2733
+ "code": "public ActionResult EditName([Bind(Include = \"Id,Name\")] Customer customer)\n{\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
2734
+ "why": "The Customer object is bound from the request and saved without verifying that the Id belongs to the authenticated user.",
2735
+ "line": 20
2736
+ }
2737
+ ],
2738
+ "severity": "high",
2739
+ "confidence": "high",
2740
+ "cwe": [
2741
+ "CWE-284",
2742
+ "CWE-639"
2743
+ ],
2744
+ "recommendation": "Validate that the customer Id matches the current user before saving.",
2745
+ "status": "confirmed",
2746
+ "verification": {
2747
+ "verdict": "confirmed",
2748
+ "reason_code": "traced",
2749
+ "checked": [
2750
+ "dotnet-legacy/Web/Controllers/CustomerController.cs lines 20-23"
2751
+ ],
2752
+ "control_found": null,
2753
+ "notes": "The EditName action accepts a bound Customer with only Id and Name, then calls db.SaveChanges() without any ownership validation.",
2754
+ "suggested_subtype": null,
2755
+ "suggested_cwe": null
2756
+ },
2757
+ "fingerprint": "kfp1:f8f8312969722c53dc4fbfcebddf09bfc6ea44e77f308058c6f5a0a79916c6a1",
2758
+ "baseline_state": "new"
2759
+ },
2760
+ {
2761
+ "finding_id": "BOLA-R-0012",
2762
+ "category": "bola",
2763
+ "subtype": "missing_ownership_check",
2764
+ "title": "BOLA in POST /Customer/Refresh: missing owner verification",
2765
+ "route_id": "R-0012",
2766
+ "endpoint": {
2767
+ "method": "POST",
2768
+ "path": "/Customer/Refresh"
2769
+ },
2770
+ "location": {
2771
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2772
+ "start_line": 27
2773
+ },
2774
+ "evidence": [
2775
+ {
2776
+ "file": "dotnet-legacy/Web/Controllers/CustomerController.cs",
2777
+ "start_line": 27,
2778
+ "code": "public ActionResult Refresh(int id)\n{\n var customer = db.Customers.Find(id);\n TryUpdateModel(customer);\n db.SaveChanges();\n return RedirectToAction(\"Index\");\n}",
2779
+ "why": "The id is taken from the URL and used to load a customer record without verifying that the customer belongs to the authenticated user.",
2780
+ "line": 27
2781
+ }
2782
+ ],
2783
+ "severity": "high",
2784
+ "confidence": "high",
2785
+ "cwe": [
2786
+ "CWE-284",
2787
+ "CWE-639"
2788
+ ],
2789
+ "recommendation": "Check that the customer id belongs to the current user before updating.",
2790
+ "status": "confirmed",
2791
+ "verification": {
2792
+ "verdict": "confirmed",
2793
+ "reason_code": "traced",
2794
+ "checked": [
2795
+ "dotnet-legacy/Web/Controllers/CustomerController.cs lines 27-32"
2796
+ ],
2797
+ "control_found": null,
2798
+ "notes": "The Refresh action loads a Customer by id from the URL and updates it without checking that the customer belongs to the authenticated user.",
2799
+ "suggested_subtype": null,
2800
+ "suggested_cwe": null
2801
+ },
2802
+ "fingerprint": "kfp1:642d9e00b1146b80dc8724396082e7bf839dc74fdcc9224c6452557ed7b19ab7",
2803
+ "baseline_state": "new"
2804
+ },
2805
+ {
2806
+ "finding_id": "BOLA-R-0013-1",
2807
+ "category": "bola",
2808
+ "subtype": "missing_ownership_check",
2809
+ "title": "BOLA in GET /Invoice/Details: missing owner verification",
2810
+ "route_id": "R-0013",
2811
+ "endpoint": {
2812
+ "method": "GET",
2813
+ "path": "/Invoice/Details"
2814
+ },
2815
+ "location": {
2816
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2817
+ "start_line": 13
2818
+ },
2819
+ "evidence": [
2820
+ {
2821
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2822
+ "start_line": 13,
2823
+ "code": "var inv = db.Invoices.Find(id); return View(inv);",
2824
+ "why": "The invoice id comes from the request and is used directly without checking ownership.",
2825
+ "line": 13
2826
+ }
2827
+ ],
2828
+ "severity": "high",
2829
+ "confidence": "medium",
2830
+ "cwe": [
2831
+ "CWE-284",
2832
+ "CWE-639"
2833
+ ],
2834
+ "recommendation": "Add an ownership check to the invoice lookup.",
2835
+ "status": "likely",
2836
+ "verification": {
2837
+ "verdict": "likely",
2838
+ "reason_code": "code_not_visible",
2839
+ "checked": [
2840
+ "dotnet-legacy/Web/Controllers/InvoiceController.cs:11-15"
2841
+ ],
2842
+ "control_found": null,
2843
+ "notes": "The Details action retrieves an invoice by id without any ownership or role check in the provided code context.",
2844
+ "suggested_subtype": null,
2845
+ "suggested_cwe": null
2846
+ },
2847
+ "fingerprint": "kfp1:e3ee32160ef7280f283dba3833ae57db6862aef7565d4a10de4989549b0b9904",
2848
+ "baseline_state": "new"
2849
+ },
2850
+ {
2851
+ "finding_id": "BOLA-R-0014-1",
2852
+ "category": "bola",
2853
+ "subtype": "missing_ownership_check",
2854
+ "title": "BOLA in GET /Invoice/Details: missing owner verification",
2855
+ "route_id": "R-0014",
2856
+ "endpoint": {
2857
+ "method": "GET",
2858
+ "path": "/Invoice/Details"
2859
+ },
2860
+ "location": {
2861
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2862
+ "start_line": 13
2863
+ },
2864
+ "evidence": [
2865
+ {
2866
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2867
+ "start_line": 13,
2868
+ "code": "var inv = db.Invoices.Find(id); return View(inv);",
2869
+ "why": "The invoice id comes from the request and is used directly without checking ownership.",
2870
+ "line": 13
2871
+ }
2872
+ ],
2873
+ "severity": "high",
2874
+ "confidence": "medium",
2875
+ "cwe": [
2876
+ "CWE-284",
2877
+ "CWE-639"
2878
+ ],
2879
+ "recommendation": "Add an ownership check to the invoice lookup.",
2880
+ "status": "likely",
2881
+ "verification": {
2882
+ "verdict": "likely",
2883
+ "reason_code": "code_not_visible",
2884
+ "checked": [
2885
+ "dotnet-legacy/Web/Controllers/InvoiceController.cs lines 6-15"
2886
+ ],
2887
+ "control_found": null,
2888
+ "notes": "The controller method retrieves an invoice by id without any ownership check. No ownership verification is visible in the provided code context.",
2889
+ "suggested_subtype": null,
2890
+ "suggested_cwe": null
2891
+ },
2892
+ "fingerprint": "kfp1:2ab395aa795459da434443ee5b3df9accb34a0be3eb3032a5922ce91eb16da11",
2893
+ "baseline_state": "new"
2894
+ },
2895
+ {
2896
+ "finding_id": "BOLA-R-0015-1",
2897
+ "category": "bola",
2898
+ "subtype": "missing_ownership_check",
2899
+ "title": "BOLA in POST /Invoice/Search: missing owner verification",
2900
+ "route_id": "R-0015",
2901
+ "endpoint": {
2902
+ "method": "POST",
2903
+ "path": "/Invoice/Search"
2904
+ },
2905
+ "location": {
2906
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2907
+ "start_line": 28
2908
+ },
2909
+ "evidence": [
2910
+ {
2911
+ "file": "dotnet-legacy/Web/Controllers/InvoiceController.cs",
2912
+ "start_line": 28,
2913
+ "code": "var list = db.Database.SqlQuery<Invoice>(\"SELECT * FROM Invoices WHERE Customer = '\" + customer + \"'\").ToList();",
2914
+ "why": "The customer value comes from the request and is used directly without checking ownership.",
2915
+ "line": 28
2916
+ }
2917
+ ],
2918
+ "severity": "high",
2919
+ "confidence": "medium",
2920
+ "cwe": [
2921
+ "CWE-284",
2922
+ "CWE-639"
2923
+ ],
2924
+ "recommendation": "Add an ownership check to the search query.",
2925
+ "status": "likely",
2926
+ "verification": {
2927
+ "verdict": "likely",
2928
+ "reason_code": "code_not_visible",
2929
+ "checked": [
2930
+ "dotnet-legacy/Web/Controllers/InvoiceController.cs lines 25-30"
2931
+ ],
2932
+ "control_found": null,
2933
+ "notes": "The search query concatenates the customer parameter directly into SQL. No ownership or parameter binding is shown in the context.",
2934
+ "suggested_subtype": null,
2935
+ "suggested_cwe": null
2936
+ },
2937
+ "fingerprint": "kfp1:c9f08667bf2ce3a6e3af70cd2f4310ad24eaf0f5493c9502e89b329d742b249c",
2938
+ "baseline_state": "new"
2939
+ },
2940
+ {
2941
+ "finding_id": "BOLA-R-0016",
2942
+ "category": "bola",
2943
+ "subtype": "no_authentication",
2944
+ "title": "BOLA in ANY /dotnet-legacy/Web/Handlers/GetFile.ashx: missing owner verification",
2945
+ "route_id": "R-0016",
2946
+ "endpoint": {
2947
+ "method": "ANY",
2948
+ "path": "/dotnet-legacy/Web/Handlers/GetFile.ashx"
2949
+ },
2950
+ "location": {
2951
+ "file": "dotnet-legacy/Web/Handlers/GetFile.ashx",
2952
+ "start_line": 8
2953
+ },
2954
+ "evidence": [
2955
+ {
2956
+ "file": "dotnet-legacy/Web/Handlers/GetFile.ashx",
2957
+ "start_line": 8,
2958
+ "code": "string fileId = context.Request.QueryString[\"file_id\"];\nstring path = DocStore.PathFor(fileId);\ncontext.Response.TransmitFile(path);",
2959
+ "why": "The file identifier comes directly from the query string and is used to transmit a file without any authentication or ownership check.",
2960
+ "line": 8
2961
+ }
2962
+ ],
2963
+ "severity": "high",
2964
+ "confidence": "medium",
2965
+ "cwe": [
2966
+ "CWE-284",
2967
+ "CWE-639"
2968
+ ],
2969
+ "recommendation": "Require authentication and verify that the requested file belongs to the current user before transmitting.",
2970
+ "status": "likely",
2971
+ "verification": {
2972
+ "verdict": "likely",
2973
+ "reason_code": "code_not_visible",
2974
+ "checked": [
2975
+ "dotnet-legacy/Web/Handlers/GetFile.ashx lines 8-10"
2976
+ ],
2977
+ "control_found": null,
2978
+ "notes": "The handler transmits a file based on a query string parameter without any visible authentication or ownership check. No global authentication include is shown in the code_context.",
2979
+ "suggested_subtype": null,
2980
+ "suggested_cwe": null
2981
+ },
2982
+ "fingerprint": "kfp1:6dcbc1c34fb5dfa6253d990e9cf121f03f5eb937c1dfb21c275f679b080ba65f",
2983
+ "baseline_state": "new"
2984
+ },
2985
+ {
2986
+ "finding_id": "BOLA-R-0017-1",
2987
+ "category": "bola",
2988
+ "subtype": "missing_ownership_check",
2989
+ "title": "BOLA in POST /dotnet-legacy/Web/Orders/EditOrder.aspx: missing owner verification",
2990
+ "route_id": "R-0017",
2991
+ "endpoint": {
2992
+ "method": "POST",
2993
+ "path": "/dotnet-legacy/Web/Orders/EditOrder.aspx"
2994
+ },
2995
+ "location": {
2996
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
2997
+ "start_line": 7
2998
+ },
2999
+ "evidence": [
3000
+ {
3001
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
3002
+ "start_line": 7,
3003
+ "code": "Dim sql As String = \"UPDATE Orders SET Note = '\" & txtNote.Text & \"'\"",
3004
+ "why": "The OrderId comes from the request (hfOrderId.Value) and is used directly without checking ownership.",
3005
+ "line": 7
3006
+ },
3007
+ {
3008
+ "file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
3009
+ "start_line": 8,
3010
+ "code": "sql &= \" WHERE OrderId = \" & hfOrderId.Value",
3011
+ "why": "No ownership check is performed.",
3012
+ "line": 8
3013
+ }
3014
+ ],
3015
+ "severity": "high",
3016
+ "confidence": "medium",
3017
+ "cwe": [
3018
+ "CWE-284",
3019
+ "CWE-639"
3020
+ ],
3021
+ "recommendation": "Add an ownership check to the UPDATE statement.",
3022
+ "status": "likely",
3023
+ "verification": {
3024
+ "verdict": "likely",
3025
+ "reason_code": "code_not_visible",
3026
+ "checked": [
3027
+ "dotnet-legacy/Web/Orders/EditOrder.aspx.vb lines 7-13"
3028
+ ],
3029
+ "control_found": null,
3030
+ "notes": "The UPDATE statement uses the OrderId from a hidden field without any ownership check. No compensating control is visible.",
3031
+ "suggested_subtype": null,
3032
+ "suggested_cwe": null
3033
+ },
3034
+ "fingerprint": "kfp1:022c4284a0f06ce3fa6393cd6ba193864479796cbba009cc90242111c588d436",
3035
+ "baseline_state": "new"
3036
+ },
3037
+ {
3038
+ "finding_id": "BOLA-R-0018-1",
3039
+ "category": "bola",
3040
+ "subtype": "missing_ownership_check",
3041
+ "title": "BOLA in GET /dotnet-legacy/Web/Orders/OrderDetail.aspx: missing owner verification",
3042
+ "route_id": "R-0018",
3043
+ "endpoint": {
3044
+ "method": "GET",
3045
+ "path": "/dotnet-legacy/Web/Orders/OrderDetail.aspx"
3046
+ },
3047
+ "location": {
3048
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
3049
+ "start_line": 13
3050
+ },
3051
+ "evidence": [
3052
+ {
3053
+ "file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
3054
+ "start_line": 13,
3055
+ "code": "var cmd = new SqlCommand(\"SELECT * FROM Orders WHERE OrderId = \" + id, conn);",
3056
+ "why": "The OrderId comes from the request and is used directly without checking ownership.",
3057
+ "line": 13
3058
+ }
3059
+ ],
3060
+ "severity": "high",
3061
+ "confidence": "medium",
3062
+ "cwe": [
3063
+ "CWE-284",
3064
+ "CWE-639"
3065
+ ],
3066
+ "recommendation": "Add an ownership check to the SELECT statement.",
3067
+ "status": "likely",
3068
+ "verification": {
3069
+ "verdict": "likely",
3070
+ "reason_code": "code_not_visible",
3071
+ "checked": [
3072
+ "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs lines 10-17"
3073
+ ],
3074
+ "control_found": null,
3075
+ "notes": "The first SELECT query uses the id from the query string without ownership verification. The later safe query is not used for this data retrieval.",
3076
+ "suggested_subtype": null,
3077
+ "suggested_cwe": null
3078
+ },
3079
+ "fingerprint": "kfp1:b4305a2e49dfee52063d69e4793bd25abed0299ca9002d6f3823a0258c378a0f",
3080
+ "baseline_state": "new"
3081
+ },
3082
+ {
3083
+ "finding_id": "BOLA-R-0019-1",
3084
+ "category": "bola",
3085
+ "subtype": "missing_ownership_check",
3086
+ "title": "BOLA in GET /java-legacy/WebContent/order/detail.jsp: missing owner verification",
3087
+ "route_id": "R-0019",
3088
+ "endpoint": {
3089
+ "method": "GET",
3090
+ "path": "/java-legacy/WebContent/order/detail.jsp"
3091
+ },
3092
+ "location": {
3093
+ "file": "java-legacy/WebContent/order/detail.jsp",
3094
+ "start_line": 5
3095
+ },
3096
+ "evidence": [
3097
+ {
3098
+ "file": "java-legacy/WebContent/order/detail.jsp",
3099
+ "start_line": 5,
3100
+ "code": "ResultSet rs = c.createStatement().executeQuery(\"SELECT * FROM orders WHERE order_no = '\" + no + \"'\");",
3101
+ "why": "The order_no comes from the request and is used directly without checking ownership.",
3102
+ "line": 5
3103
+ }
3104
+ ],
3105
+ "severity": "high",
3106
+ "confidence": "medium",
3107
+ "cwe": [
3108
+ "CWE-284",
3109
+ "CWE-639"
3110
+ ],
3111
+ "recommendation": "Add an ownership check to the SELECT statement.",
3112
+ "status": "likely",
3113
+ "verification": {
3114
+ "verdict": "likely",
3115
+ "reason_code": "code_not_visible",
3116
+ "checked": [
3117
+ "java-legacy/WebContent/order/detail.jsp lines 3-5"
3118
+ ],
3119
+ "control_found": null,
3120
+ "notes": "The SQL statement concatenates the order_no parameter directly. No ownership check is present in the visible code.",
3121
+ "suggested_subtype": null,
3122
+ "suggested_cwe": null
3123
+ },
3124
+ "fingerprint": "kfp1:d3a74b15481fc3023ceec1693e10f184b7d03022d43611b49c1b26b2edb1c78f",
3125
+ "baseline_state": "new"
3126
+ },
3127
+ {
3128
+ "finding_id": "BOLA-R-0020",
3129
+ "category": "bola",
3130
+ "subtype": "missing_ownership_check",
3131
+ "title": "BOLA in POST /account/save: missing owner verification",
3132
+ "route_id": "R-0020",
3133
+ "endpoint": {
3134
+ "method": "POST",
3135
+ "path": "/account/save"
3136
+ },
3137
+ "location": {
3138
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3139
+ "start_line": 15
3140
+ },
3141
+ "evidence": [
3142
+ {
3143
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3144
+ "start_line": 15,
3145
+ "code": "accountDao.save(account);",
3146
+ "why": "Account ID can be set to another user's ID; no ownership check performed.",
3147
+ "line": 15
3148
+ }
3149
+ ],
3150
+ "severity": "high",
3151
+ "confidence": "high",
3152
+ "cwe": [
3153
+ "CWE-284",
3154
+ "CWE-639"
3155
+ ],
3156
+ "recommendation": "Bind the operation to the current session user.",
3157
+ "status": "confirmed",
3158
+ "verification": {
3159
+ "verdict": "confirmed",
3160
+ "reason_code": "traced",
3161
+ "checked": [
3162
+ "java-legacy/src/com/acme/web/AccountController.java:13-15"
3163
+ ],
3164
+ "control_found": null,
3165
+ "notes": "The POST /account/save handler directly calls accountDao.save(account) with no ownership or role check in the visible code.",
3166
+ "suggested_subtype": null,
3167
+ "suggested_cwe": null
3168
+ },
3169
+ "fingerprint": "kfp1:24fe855b446d28a5d00c674816e053358f40cdb1d4848028f603352d60fda884",
3170
+ "baseline_state": "new"
3171
+ },
3172
+ {
3173
+ "finding_id": "BOLA-R-0021",
3174
+ "category": "bola",
3175
+ "subtype": "missing_ownership_check",
3176
+ "title": "BOLA in POST /account/rename: missing owner verification",
3177
+ "route_id": "R-0021",
3178
+ "endpoint": {
3179
+ "method": "POST",
3180
+ "path": "/account/rename"
3181
+ },
3182
+ "location": {
3183
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3184
+ "start_line": 21
3185
+ },
3186
+ "evidence": [
3187
+ {
3188
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3189
+ "start_line": 21,
3190
+ "code": "accountDao.rename(form.getId(), form.getName());",
3191
+ "why": "The form ID can point to another user's account; no ownership check.",
3192
+ "line": 21
3193
+ }
3194
+ ],
3195
+ "severity": "high",
3196
+ "confidence": "high",
3197
+ "cwe": [
3198
+ "CWE-284",
3199
+ "CWE-639"
3200
+ ],
3201
+ "recommendation": "Verify that the account belongs to the current user before renaming.",
3202
+ "status": "confirmed",
3203
+ "verification": {
3204
+ "verdict": "confirmed",
3205
+ "reason_code": "traced",
3206
+ "checked": [
3207
+ "java-legacy/src/com/acme/web/AccountController.java:19-21"
3208
+ ],
3209
+ "control_found": null,
3210
+ "notes": "The POST /account/rename handler invokes accountDao.rename(form.getId(), form.getName()) without any ownership verification in the shown code.",
3211
+ "suggested_subtype": null,
3212
+ "suggested_cwe": null
3213
+ },
3214
+ "fingerprint": "kfp1:9861ff13d6d3a7c7b166ad5640320a1c58d0a7e89965d79a86f14deddaeae0af",
3215
+ "baseline_state": "new"
3216
+ },
3217
+ {
3218
+ "finding_id": "BOLA-R-0022",
3219
+ "category": "bola",
3220
+ "subtype": "missing_ownership_check",
3221
+ "title": "BOLA in PUT /account/api: missing owner verification",
3222
+ "route_id": "R-0022",
3223
+ "endpoint": {
3224
+ "method": "PUT",
3225
+ "path": "/account/api"
3226
+ },
3227
+ "location": {
3228
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3229
+ "start_line": 28
3230
+ },
3231
+ "evidence": [
3232
+ {
3233
+ "file": "java-legacy/src/com/acme/web/AccountController.java",
3234
+ "start_line": 28,
3235
+ "code": "return accountDao.save(account);",
3236
+ "why": "Account ID can be set to another user's ID; no ownership check.",
3237
+ "line": 28
3238
+ }
3239
+ ],
3240
+ "severity": "high",
3241
+ "confidence": "high",
3242
+ "cwe": [
3243
+ "CWE-284",
3244
+ "CWE-639"
3245
+ ],
3246
+ "recommendation": "Ensure the account belongs to the current user before saving.",
3247
+ "status": "confirmed",
3248
+ "verification": {
3249
+ "verdict": "confirmed",
3250
+ "reason_code": "traced",
3251
+ "checked": [
3252
+ "java-legacy/src/com/acme/web/AccountController.java:25-28"
3253
+ ],
3254
+ "control_found": null,
3255
+ "notes": "The PUT /account/api handler returns accountDao.save(account) with no ownership or role check in the visible code.",
3256
+ "suggested_subtype": null,
3257
+ "suggested_cwe": null
3258
+ },
3259
+ "fingerprint": "kfp1:dd0493f7dcb3e1d57330e174623390900a4d5a957be4da90e8e5de642479da69",
3260
+ "baseline_state": "new"
3261
+ },
3262
+ {
3263
+ "finding_id": "BOLA-R-0023",
3264
+ "category": "bola",
3265
+ "subtype": "missing_ownership_check",
3266
+ "title": "BOLA in POST /admin/users/{id}/delete: missing owner verification",
3267
+ "route_id": "R-0023",
3268
+ "endpoint": {
3269
+ "method": "POST",
3270
+ "path": "/admin/users/{id}/delete"
3271
+ },
3272
+ "location": {
3273
+ "file": "java-legacy/src/com/acme/web/AdminUserController.java",
3274
+ "start_line": 15
3275
+ },
3276
+ "evidence": [
3277
+ {
3278
+ "file": "java-legacy/src/com/acme/web/AdminUserController.java",
3279
+ "start_line": 15,
3280
+ "code": "userDao.deleteById(id);",
3281
+ "why": "Any authenticated user can delete any user; no ownership or admin check.",
3282
+ "line": 15
3283
+ }
3284
+ ],
3285
+ "severity": "high",
3286
+ "confidence": "high",
3287
+ "cwe": [
3288
+ "CWE-284",
3289
+ "CWE-639"
3290
+ ],
3291
+ "recommendation": "Restrict delete to admins or verify ownership.",
3292
+ "status": "confirmed",
3293
+ "verification": {
3294
+ "verdict": "confirmed",
3295
+ "reason_code": "traced",
3296
+ "checked": [
3297
+ "java-legacy/src/com/acme/web/AdminUserController.java:13-15"
3298
+ ],
3299
+ "control_found": null,
3300
+ "notes": "The POST /admin/users/{id}/delete handler calls userDao.deleteById(id) without any role or ownership check in the shown code.",
3301
+ "suggested_subtype": null,
3302
+ "suggested_cwe": null
3303
+ },
3304
+ "fingerprint": "kfp1:0fc9abd5c4b9b2a958a6643e781f5727c69e20054629c44e735658e1dcffa073",
3305
+ "baseline_state": "new"
3306
+ },
3307
+ {
3308
+ "finding_id": "BOLA-R-0025",
3309
+ "category": "bola",
3310
+ "subtype": "missing_ownership_check",
3311
+ "title": "BOLA in GET /invoices/{id}: missing owner verification",
3312
+ "route_id": "R-0025",
3313
+ "endpoint": {
3314
+ "method": "GET",
3315
+ "path": "/invoices/{id}"
3316
+ },
3317
+ "location": {
3318
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
3319
+ "start_line": 17
3320
+ },
3321
+ "evidence": [
3322
+ {
3323
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
3324
+ "start_line": 17,
3325
+ "code": "model.addAttribute(\"invoice\", invoiceDao.findById(id));",
3326
+ "why": "Invoice ID can be any value; no ownership check.",
3327
+ "line": 17
3328
+ }
3329
+ ],
3330
+ "severity": "high",
3331
+ "confidence": "high",
3332
+ "cwe": [
3333
+ "CWE-284",
3334
+ "CWE-639"
3335
+ ],
3336
+ "recommendation": "Bind the invoice lookup to the current user.",
3337
+ "status": "confirmed",
3338
+ "verification": {
3339
+ "verdict": "confirmed",
3340
+ "reason_code": "traced",
3341
+ "checked": [
3342
+ "java-legacy/src/com/acme/web/InvoiceController.java:15-17"
3343
+ ],
3344
+ "control_found": null,
3345
+ "notes": "The GET /invoices/{id} handler uses invoiceDao.findById(id) directly, with no ownership verification in the visible code.",
3346
+ "suggested_subtype": null,
3347
+ "suggested_cwe": null
3348
+ },
3349
+ "fingerprint": "kfp1:5d584a61310d261639c30a41d5c01a1591be415823c1431b9ed0cdd4e6d1549f",
3350
+ "baseline_state": "new"
3351
+ },
3352
+ {
3353
+ "finding_id": "BOLA-R-0027",
3354
+ "category": "bola",
3355
+ "subtype": "missing_ownership_check",
3356
+ "title": "BOLA in GET /invoices/search: missing owner verification",
3357
+ "route_id": "R-0027",
3358
+ "endpoint": {
3359
+ "method": "GET",
3360
+ "path": "/invoices/search"
3361
+ },
3362
+ "location": {
3363
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
3364
+ "start_line": 29
3365
+ },
3366
+ "evidence": [
3367
+ {
3368
+ "file": "java-legacy/src/com/acme/web/InvoiceController.java",
3369
+ "start_line": 29,
3370
+ "code": "model.addAttribute(\"list\", session.createQuery(\"from Invoice i where i.customer = '\" + customer + \"'\").list());",
3371
+ "why": "Search results are not filtered by the current user.",
3372
+ "line": 29
3373
+ }
3374
+ ],
3375
+ "severity": "high",
3376
+ "confidence": "medium",
3377
+ "cwe": [
3378
+ "CWE-284",
3379
+ "CWE-639"
3380
+ ],
3381
+ "recommendation": "Filter invoices by the current user.",
3382
+ "status": "likely",
3383
+ "verification": {
3384
+ "verdict": "likely",
3385
+ "reason_code": "code_not_visible",
3386
+ "checked": [
3387
+ "InvoiceController.java:27-30"
3388
+ ],
3389
+ "control_found": null,
3390
+ "notes": "The search query concatenates the customer parameter directly and does not reference the current user or any ownership check. No global filter or allow‑list is shown in the provided context.",
3391
+ "suggested_subtype": null,
3392
+ "suggested_cwe": null
3393
+ },
3394
+ "fingerprint": "kfp1:1cf3d8c24a4b1ec82a1a260ddafcba873b05ec821d2005d7910795b92d8a5586",
3395
+ "baseline_state": "new"
3396
+ },
3397
+ {
3398
+ "finding_id": "BOLA-R-0028",
3399
+ "category": "bola",
3400
+ "subtype": "missing_ownership_check",
3401
+ "title": "BOLA in GET /order/view: missing owner verification",
3402
+ "route_id": "R-0028",
3403
+ "endpoint": {
3404
+ "method": "GET",
3405
+ "path": "/order/view"
3406
+ },
3407
+ "location": {
3408
+ "file": "java-legacy/src/com/acme/web/OrderServlet.java",
3409
+ "start_line": 15
3410
+ },
3411
+ "evidence": [
3412
+ {
3413
+ "file": "java-legacy/src/com/acme/web/OrderServlet.java",
3414
+ "start_line": 15,
3415
+ "code": "ResultSet rs = stmt.executeQuery(\"SELECT * FROM orders WHERE id = '\" + id + \"'\");",
3416
+ "why": "Order ID is taken from the request and used without checking ownership.",
3417
+ "line": 15
3418
+ }
3419
+ ],
3420
+ "severity": "high",
3421
+ "confidence": "medium",
3422
+ "cwe": [
3423
+ "CWE-284",
3424
+ "CWE-639"
3425
+ ],
3426
+ "recommendation": "Verify that the order belongs to the current user before displaying.",
3427
+ "status": "likely",
3428
+ "verification": {
3429
+ "verdict": "likely",
3430
+ "reason_code": "code_not_visible",
3431
+ "checked": [
3432
+ "OrderServlet.java:13-15"
3433
+ ],
3434
+ "control_found": null,
3435
+ "notes": "The SQL statement uses the orderId request parameter without any comparison to the session user. No cast, allow‑list, or ownership helper is visible in the snippet.",
3436
+ "suggested_subtype": null,
3437
+ "suggested_cwe": null
3438
+ },
3439
+ "fingerprint": "kfp1:afc371e4fadf50f0600ef9e0ca1b821e4453f98e8f49b42a9b8fade94d136354",
3440
+ "baseline_state": "new"
3441
+ },
3442
+ {
3443
+ "finding_id": "BOLA-R-0030",
3444
+ "category": "bola",
3445
+ "subtype": "missing_ownership_check",
3446
+ "title": "BOLA in POST /admin/users/:id/delete: missing owner verification",
3447
+ "route_id": "R-0030",
3448
+ "endpoint": {
3449
+ "method": "POST",
3450
+ "path": "/admin/users/:id/delete"
3451
+ },
3452
+ "location": {
3453
+ "file": "node-express/routes/admin.js",
3454
+ "start_line": 9
3455
+ },
3456
+ "evidence": [
3457
+ {
3458
+ "file": "node-express/routes/admin.js",
3459
+ "start_line": 9,
3460
+ "code": "User.deleteOne({ _id: req.params.id }, function () { res.sendStatus(204); });",
3461
+ "why": "Any logged‑in user can delete any user; no admin or ownership check.",
3462
+ "line": 9
3463
+ }
3464
+ ],
3465
+ "severity": "high",
3466
+ "confidence": "medium",
3467
+ "cwe": [
3468
+ "CWE-284",
3469
+ "CWE-639"
3470
+ ],
3471
+ "recommendation": "Restrict delete to admins or verify ownership.",
3472
+ "status": "likely",
3473
+ "verification": {
3474
+ "verdict": "likely",
3475
+ "reason_code": "code_not_visible",
3476
+ "checked": [
3477
+ "admin.js:8-9"
3478
+ ],
3479
+ "control_found": null,
3480
+ "notes": "The route applies only an ensureLoggedIn middleware; there is no admin role check or ownership verification before deleting a user.",
3481
+ "suggested_subtype": null,
3482
+ "suggested_cwe": null
3483
+ },
3484
+ "fingerprint": "kfp1:5c4be898959dd5b2d53deee92dcdf152d2292edd4a433aaf5fc0e74d1f2724f4",
3485
+ "baseline_state": "new"
3486
+ },
3487
+ {
3488
+ "finding_id": "BOLA-R-0033-1",
3489
+ "category": "bola",
3490
+ "subtype": "missing_ownership_check",
3491
+ "title": "BOLA in GET /orders/:id: missing owner verification",
3492
+ "route_id": "R-0033",
3493
+ "endpoint": {
3494
+ "method": "GET",
3495
+ "path": "/orders/:id"
3496
+ },
3497
+ "location": {
3498
+ "file": "node-express/routes/orders.js",
3499
+ "start_line": 8
3500
+ },
3501
+ "evidence": [
3502
+ {
3503
+ "file": "node-express/routes/orders.js",
3504
+ "start_line": 8,
3505
+ "code": "Order.findById(req.params.id, function (err, order) { res.json(order); });",
3506
+ "why": "The order ID comes from the request path and the query does not filter by the authenticated user.",
3507
+ "line": 8
3508
+ }
3509
+ ],
3510
+ "severity": "high",
3511
+ "confidence": "medium",
3512
+ "cwe": [
3513
+ "CWE-284",
3514
+ "CWE-639"
3515
+ ],
3516
+ "recommendation": "Bind the query to the current session user.",
3517
+ "status": "likely",
3518
+ "verification": {
3519
+ "verdict": "likely",
3520
+ "reason_code": "code_not_visible",
3521
+ "checked": [
3522
+ "orders.js:8-9"
3523
+ ],
3524
+ "control_found": null,
3525
+ "notes": "The GET /orders/:id endpoint uses the request id directly in the query without filtering by the authenticated user. No ownership guard is present in the snippet.",
3526
+ "suggested_subtype": null,
3527
+ "suggested_cwe": null
3528
+ },
3529
+ "fingerprint": "kfp1:3efb41972fd6c818041a922563d6a1e65eb9cdcd63b764b52ff4ffce238a6c8d",
3530
+ "baseline_state": "new"
3531
+ },
3532
+ {
3533
+ "finding_id": "BOLA-R-0038-1",
3534
+ "category": "bola",
3535
+ "subtype": "missing_ownership_check",
3536
+ "title": "BOLA in GET /stats: missing shop ownership verification",
3537
+ "route_id": "R-0038",
3538
+ "endpoint": {
3539
+ "method": "GET",
3540
+ "path": "/stats"
3541
+ },
3542
+ "location": {
3543
+ "file": "node-express/routes/orders.js",
3544
+ "start_line": 28
3545
+ },
3546
+ "evidence": [
3547
+ {
3548
+ "file": "node-express/routes/orders.js",
3549
+ "start_line": 28,
3550
+ "code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
3551
+ "why": "The shop_id is taken from the request query and the query does not verify that the shop belongs to the authenticated user.",
3552
+ "line": 28
3553
+ }
3554
+ ],
3555
+ "severity": "high",
3556
+ "confidence": "medium",
3557
+ "cwe": [
3558
+ "CWE-284",
3559
+ "CWE-639"
3560
+ ],
3561
+ "recommendation": "Verify that the shop_id belongs to the current user before returning statistics.",
3562
+ "status": "likely",
3563
+ "verification": {
3564
+ "verdict": "likely",
3565
+ "reason_code": "code_not_visible",
3566
+ "checked": [
3567
+ "orders.js:28-29"
3568
+ ],
3569
+ "control_found": null,
3570
+ "notes": "The stats endpoint accepts a shop id from the query string and uses it directly in a SQL query. No ownership or admin check is visible in the provided context.",
3571
+ "suggested_subtype": null,
3572
+ "suggested_cwe": null
3573
+ },
3574
+ "fingerprint": "kfp1:e0d4076276caf1e9557699dcd9494f106ac443c30bfdb55c71fb7aaedda29b14",
3575
+ "baseline_state": "new"
3576
+ },
3577
+ {
3578
+ "finding_id": "BOLA-R-0043-1",
3579
+ "category": "bola",
3580
+ "subtype": "missing_ownership_check",
3581
+ "title": "BOLA in Perl CGI order.cgi: missing user ownership verification",
3582
+ "route_id": "R-0043",
3583
+ "endpoint": {
3584
+ "method": "ANY",
3585
+ "path": "/perl-cgi/cgi-bin/order.cgi"
3586
+ },
3587
+ "location": {
3588
+ "file": "perl-cgi/cgi-bin/order.cgi",
3589
+ "start_line": 11
3590
+ },
3591
+ "evidence": [
3592
+ {
3593
+ "file": "perl-cgi/cgi-bin/order.cgi",
3594
+ "start_line": 11,
3595
+ "code": "$id = $q->param('id');\n$sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");\n$sth->execute();",
3596
+ "why": "The order ID is taken from the request and the query does not filter by the authenticated user.",
3597
+ "line": 11
3598
+ }
3599
+ ],
3600
+ "severity": "high",
3601
+ "confidence": "high",
3602
+ "cwe": [
3603
+ "CWE-284",
3604
+ "CWE-639"
3605
+ ],
3606
+ "recommendation": "Add a user_id filter to the query.",
3607
+ "status": "confirmed",
3608
+ "verification": {
3609
+ "verdict": "confirmed",
3610
+ "reason_code": "traced",
3611
+ "checked": [
3612
+ "perl-cgi/cgi-bin/order.cgi: lines 11-17"
3613
+ ],
3614
+ "control_found": null,
3615
+ "notes": "The query at line 13 selects orders by id without filtering by user_id. No ownership check or parameter binding is present. The subsequent query with user_id is not used for the initial data retrieval.",
3616
+ "suggested_subtype": null,
3617
+ "suggested_cwe": null
3618
+ },
3619
+ "fingerprint": "kfp1:446abc0a5ca9d538f5d680526af5265194e8ee2f7644e6ca49c64b3b9d7b2b4e",
3620
+ "baseline_state": "new"
3621
+ },
3622
+ {
3623
+ "finding_id": "BOLA-R-0044-1",
3624
+ "category": "bola",
3625
+ "subtype": "missing_ownership_check",
3626
+ "title": "BOLA in PHP CodeIgniter Invoice view: missing owner verification",
3627
+ "route_id": "R-0044",
3628
+ "endpoint": {
3629
+ "method": "ANY",
3630
+ "path": "/invoice/view/{id}"
3631
+ },
3632
+ "location": {
3633
+ "file": "php-codeigniter/application/controllers/Invoice.php",
3634
+ "start_line": 9
3635
+ },
3636
+ "evidence": [
3637
+ {
3638
+ "file": "php-codeigniter/application/controllers/Invoice.php",
3639
+ "start_line": 9,
3640
+ "code": "$q = $this->db->query(\"SELECT * FROM invoices WHERE id = $id\");",
3641
+ "why": "The invoice ID is taken from the request and the query does not filter by the authenticated user.",
3642
+ "line": 9
3643
+ }
3644
+ ],
3645
+ "severity": "high",
3646
+ "confidence": "high",
3647
+ "cwe": [
3648
+ "CWE-284",
3649
+ "CWE-639"
3650
+ ],
3651
+ "recommendation": "Add a user_id filter to the query.",
3652
+ "status": "confirmed",
3653
+ "verification": {
3654
+ "verdict": "confirmed",
3655
+ "reason_code": "traced",
3656
+ "checked": [
3657
+ "php-codeigniter/application/controllers/Invoice.php: lines 9-17"
3658
+ ],
3659
+ "control_found": null,
3660
+ "notes": "The view method executes a raw query with id only, no user_id filter. No ownership check is present.",
3661
+ "suggested_subtype": null,
3662
+ "suggested_cwe": null
3663
+ },
3664
+ "fingerprint": "kfp1:266f870d96cd69a0b4644c5c983b5c92d59a3d989f9d2514e1016f6ffd372f3b",
3665
+ "baseline_state": "new"
3666
+ },
3667
+ {
3668
+ "finding_id": "BOLA-R-0046-1",
3669
+ "category": "bola",
3670
+ "subtype": "missing_ownership_check",
3671
+ "title": "BOLA in PHP CodeIgniter Invoice update: missing owner verification",
3672
+ "route_id": "R-0046",
3673
+ "endpoint": {
3674
+ "method": "ANY",
3675
+ "path": "/invoice/update"
3676
+ },
3677
+ "location": {
3678
+ "file": "php-codeigniter/application/controllers/Invoice.php",
3679
+ "start_line": 20
3680
+ },
3681
+ "evidence": [
3682
+ {
3683
+ "file": "php-codeigniter/application/controllers/Invoice.php",
3684
+ "start_line": 20,
3685
+ "code": "$this->db->query(\"UPDATE invoices SET note = ? WHERE id = ?\", array($note, $id));",
3686
+ "why": "The invoice ID is taken from the request and the update does not verify that the invoice belongs to the authenticated user.",
3687
+ "line": 20
3688
+ }
3689
+ ],
3690
+ "severity": "high",
3691
+ "confidence": "high",
3692
+ "cwe": [
3693
+ "CWE-284",
3694
+ "CWE-639"
3695
+ ],
3696
+ "recommendation": "Add a user_id filter to the update query.",
3697
+ "status": "confirmed",
3698
+ "verification": {
3699
+ "verdict": "confirmed",
3700
+ "reason_code": "traced",
3701
+ "checked": [
3702
+ "php-codeigniter/application/controllers/Invoice.php: lines 20-23"
3703
+ ],
3704
+ "control_found": null,
3705
+ "notes": "The update query uses id from POST without verifying ownership. No ownership check is present.",
3706
+ "suggested_subtype": null,
3707
+ "suggested_cwe": null
3708
+ },
3709
+ "fingerprint": "kfp1:f8000507518dfd07801d08ee0115647eaf2efdfdcfcd467cab0be7ea43514273",
3710
+ "baseline_state": "new"
3711
+ },
3712
+ {
3713
+ "finding_id": "BOLA-R-0053",
3714
+ "category": "bola",
3715
+ "subtype": "missing_ownership_check",
3716
+ "title": "Needs review: POST /posts – ownership check unknown",
3717
+ "route_id": "R-0053",
3718
+ "endpoint": {
3719
+ "method": "POST",
3720
+ "path": "/posts"
3721
+ },
3722
+ "location": {
3723
+ "file": "php-laravel/routes/web.php",
3724
+ "start_line": 7
3725
+ },
3726
+ "evidence": [
3727
+ {
3728
+ "file": "php-laravel/routes/web.php",
3729
+ "start_line": 7,
3730
+ "code": "Route::post('/posts', [AccountController::class, 'post']);",
3731
+ "why": "Controller code not visible; cannot confirm ownership enforcement",
3732
+ "line": 7
3733
+ }
3734
+ ],
3735
+ "severity": "high",
3736
+ "confidence": "medium",
3737
+ "cwe": [
3738
+ "CWE-639"
3739
+ ],
3740
+ "recommendation": "Verify that the post creation associates the post with the current user and that updates/deletes check ownership",
3741
+ "status": "likely",
3742
+ "verification": {
3743
+ "verdict": "likely",
3744
+ "reason_code": "code_not_visible",
3745
+ "checked": [
3746
+ "php-laravel/routes/web.php line 7"
3747
+ ],
3748
+ "control_found": null,
3749
+ "notes": "The route definition does not show any ownership or authentication check; controller code is not visible.",
3750
+ "suggested_subtype": null,
3751
+ "suggested_cwe": null
3752
+ },
3753
+ "fingerprint": "kfp1:4472d1b3152d66cb04a57fb114d48891327da9647b40100dc135369a10286465",
3754
+ "baseline_state": "new"
3755
+ },
3756
+ {
3757
+ "finding_id": "BOLA-R-0054",
3758
+ "category": "bola",
3759
+ "subtype": "missing_ownership_check",
3760
+ "title": "Needs review: POST /teams – ownership check unknown",
3761
+ "route_id": "R-0054",
3762
+ "endpoint": {
3763
+ "method": "POST",
3764
+ "path": "/teams"
3765
+ },
3766
+ "location": {
3767
+ "file": "php-laravel/routes/web.php",
3768
+ "start_line": 8
3769
+ },
3770
+ "evidence": [
3771
+ {
3772
+ "file": "php-laravel/routes/web.php",
3773
+ "start_line": 8,
3774
+ "code": "Route::post('/teams', [AccountController::class, 'team']);",
3775
+ "why": "Controller code not visible; cannot confirm ownership enforcement",
3776
+ "line": 8
3777
+ }
3778
+ ],
3779
+ "severity": "high",
3780
+ "confidence": "medium",
3781
+ "cwe": [
3782
+ "CWE-639"
3783
+ ],
3784
+ "recommendation": "Verify that team operations enforce that the current user owns or is a member of the team",
3785
+ "status": "likely",
3786
+ "verification": {
3787
+ "verdict": "likely",
3788
+ "reason_code": "code_not_visible",
3789
+ "checked": [
3790
+ "php-laravel/routes/web.php line 8"
3791
+ ],
3792
+ "control_found": null,
3793
+ "notes": "The route definition does not reveal any ownership or authentication check; controller code is not visible.",
3794
+ "suggested_subtype": null,
3795
+ "suggested_cwe": null
3796
+ },
3797
+ "fingerprint": "kfp1:92210815c72921df95be809bbea79b3317ed94e52b82d925ff97a2842ddf4c44",
3798
+ "baseline_state": "new"
3799
+ },
3800
+ {
3801
+ "finding_id": "BOLA-R-0055",
3802
+ "category": "bola",
3803
+ "subtype": "missing_ownership_check",
3804
+ "title": "Needs review: POST /account/rename – ownership check unknown",
3805
+ "route_id": "R-0055",
3806
+ "endpoint": {
3807
+ "method": "POST",
3808
+ "path": "/account/rename"
3809
+ },
3810
+ "location": {
3811
+ "file": "php-laravel/routes/web.php",
3812
+ "start_line": 9
3813
+ },
3814
+ "evidence": [
3815
+ {
3816
+ "file": "php-laravel/routes/web.php",
3817
+ "start_line": 9,
3818
+ "code": "Route::post('/account/rename', [AccountController::class, 'rename']);",
3819
+ "why": "Controller code not visible; cannot confirm ownership enforcement",
3820
+ "line": 9
3821
+ }
3822
+ ],
3823
+ "severity": "high",
3824
+ "confidence": "medium",
3825
+ "cwe": [
3826
+ "CWE-639"
3827
+ ],
3828
+ "recommendation": "Verify that the rename action checks that the target account belongs to the current user",
3829
+ "status": "likely",
3830
+ "verification": {
3831
+ "verdict": "likely",
3832
+ "reason_code": "code_not_visible",
3833
+ "checked": [
3834
+ "php-laravel/routes/web.php line 9"
3835
+ ],
3836
+ "control_found": null,
3837
+ "notes": "The route definition does not show any ownership or authentication check; controller code is not visible.",
3838
+ "suggested_subtype": null,
3839
+ "suggested_cwe": null
3840
+ },
3841
+ "fingerprint": "kfp1:7a81012b63abf34531deb51addbdbb776032e07f7418a7b76a3ac7b844bf8ac7",
3842
+ "baseline_state": "new"
3843
+ },
3844
+ {
3845
+ "finding_id": "BOLA-R-0056",
3846
+ "category": "bola",
3847
+ "subtype": "missing_ownership_check",
3848
+ "title": "Needs review: POST /account/profile – ownership check unknown",
3849
+ "route_id": "R-0056",
3850
+ "endpoint": {
3851
+ "method": "POST",
3852
+ "path": "/account/profile"
3853
+ },
3854
+ "location": {
3855
+ "file": "php-laravel/routes/web.php",
3856
+ "start_line": 10
3857
+ },
3858
+ "evidence": [
3859
+ {
3860
+ "file": "php-laravel/routes/web.php",
3861
+ "start_line": 10,
3862
+ "code": "Route::post('/account/profile', [AccountController::class, 'profile']);",
3863
+ "why": "Controller code not visible; cannot confirm ownership enforcement",
3864
+ "line": 10
3865
+ }
3866
+ ],
3867
+ "severity": "high",
3868
+ "confidence": "medium",
3869
+ "cwe": [
3870
+ "CWE-639"
3871
+ ],
3872
+ "recommendation": "Verify that the profile update checks that the target profile belongs to the current user",
3873
+ "status": "likely",
3874
+ "verification": {
3875
+ "verdict": "likely",
3876
+ "reason_code": "code_not_visible",
3877
+ "checked": [
3878
+ "php-laravel/routes/web.php line 10"
3879
+ ],
3880
+ "control_found": null,
3881
+ "notes": "The route definition does not reveal any ownership or authentication check; controller code is not visible.",
3882
+ "suggested_subtype": null,
3883
+ "suggested_cwe": null
3884
+ },
3885
+ "fingerprint": "kfp1:75cfa48a403e95dbf5595e132273c39e3364707a26b0c72ec796428525b367c5",
3886
+ "baseline_state": "new"
3887
+ },
3888
+ {
3889
+ "finding_id": "BOLA-R-0057",
3890
+ "category": "bola",
3891
+ "subtype": "missing_ownership_check",
3892
+ "title": "BOLA in GET|POST /php-plain/admin.php?action=view: missing owner verification",
3893
+ "route_id": "R-0057",
3894
+ "endpoint": {
3895
+ "method": "GET|POST",
3896
+ "path": "/php-plain/admin.php?action=view"
3897
+ },
3898
+ "location": {
3899
+ "file": "php-plain/admin.php",
3900
+ "start_line": 6
3901
+ },
3902
+ "evidence": [
3903
+ {
3904
+ "file": "php-plain/admin.php",
3905
+ "start_line": 7,
3906
+ "code": "$uid = (int)$_GET['uid'];",
3907
+ "why": "ID comes from request",
3908
+ "line": 7
3909
+ },
3910
+ {
3911
+ "file": "php-plain/admin.php",
3912
+ "start_line": 8,
3913
+ "code": "$r = mysql_query(\"SELECT * FROM users WHERE id = \" . $uid);",
3914
+ "why": "No owner check; any logged‑in user can view any user",
3915
+ "line": 8
3916
+ }
3917
+ ],
3918
+ "severity": "high",
3919
+ "confidence": "high",
3920
+ "cwe": [
3921
+ "CWE-639",
3922
+ "CWE-284"
3923
+ ],
3924
+ "recommendation": "Bind query to current session user",
3925
+ "status": "confirmed",
3926
+ "verification": {
3927
+ "verdict": "confirmed",
3928
+ "reason_code": "traced",
3929
+ "checked": [
3930
+ "php-plain/admin.php: lines 6-8",
3931
+ "php-plain/inc/auth.php: lines 1-7"
3932
+ ],
3933
+ "control_found": null,
3934
+ "notes": "The view case retrieves a user by uid from GET without checking that the uid matches the logged‑in user. No ownership check is present.",
3935
+ "suggested_subtype": null,
3936
+ "suggested_cwe": null
3937
+ },
3938
+ "fingerprint": "kfp1:8b88f1fc9bd485912baa4d3f171534073a43ee33ae6e47d9c7c0c767a1391f4c",
3939
+ "baseline_state": "new"
3940
+ },
3941
+ {
3942
+ "finding_id": "BOLA-R-0058",
3943
+ "category": "bola",
3944
+ "subtype": "missing_ownership_check",
3945
+ "title": "BOLA in GET|POST /php-plain/admin.php?action=delete: missing owner verification",
3946
+ "route_id": "R-0058",
3947
+ "endpoint": {
3948
+ "method": "GET|POST",
3949
+ "path": "/php-plain/admin.php?action=delete"
3950
+ },
3951
+ "location": {
3952
+ "file": "php-plain/admin.php",
3953
+ "start_line": 10
3954
+ },
3955
+ "evidence": [
3956
+ {
3957
+ "file": "php-plain/admin.php",
3958
+ "start_line": 11,
3959
+ "code": "$id = $_POST['id'];",
3960
+ "why": "ID comes from request",
3961
+ "line": 11
3962
+ },
3963
+ {
3964
+ "file": "php-plain/admin.php",
3965
+ "start_line": 12,
3966
+ "code": "mysql_query(\"DELETE FROM users WHERE id = $id\");",
3967
+ "why": "No owner check; any logged‑in user can delete any user",
3968
+ "line": 12
3969
+ }
3970
+ ],
3971
+ "severity": "high",
3972
+ "confidence": "high",
3973
+ "cwe": [
3974
+ "CWE-639",
3975
+ "CWE-284"
3976
+ ],
3977
+ "recommendation": "Bind delete to current session user",
3978
+ "status": "confirmed",
3979
+ "verification": {
3980
+ "verdict": "confirmed",
3981
+ "reason_code": "traced",
3982
+ "checked": [
3983
+ "php-plain/admin.php: lines 10-12",
3984
+ "php-plain/inc/auth.php: lines 1-7"
3985
+ ],
3986
+ "control_found": null,
3987
+ "notes": "The delete case deletes a user by id from POST without verifying ownership. No ownership check is present.",
3988
+ "suggested_subtype": null,
3989
+ "suggested_cwe": null
3990
+ },
3991
+ "fingerprint": "kfp1:ec0e594b3da0f4ab8e7ba60745c7f867f447dfc20d1ff118e2c0f9798193abfa",
3992
+ "baseline_state": "new"
3993
+ },
3994
+ {
3995
+ "finding_id": "BOLA-R-0059",
3996
+ "category": "bola",
3997
+ "subtype": "missing_ownership_check",
3998
+ "title": "BOLA in POST /php-plain/manage_users.php: missing owner verification",
3999
+ "route_id": "R-0059",
4000
+ "endpoint": {
4001
+ "method": "POST",
4002
+ "path": "/php-plain/manage_users.php"
4003
+ },
4004
+ "location": {
4005
+ "file": "php-plain/manage_users.php",
4006
+ "start_line": 5
4007
+ },
4008
+ "evidence": [
4009
+ {
4010
+ "file": "php-plain/manage_users.php",
4011
+ "start_line": 5,
4012
+ "code": "if ($_SERVER['REQUEST_METHOD'] === 'POST') {",
4013
+ "why": "ID comes from request",
4014
+ "line": 5
4015
+ },
4016
+ {
4017
+ "file": "php-plain/manage_users.php",
4018
+ "start_line": 6,
4019
+ "code": "$stmt = $db->prepare(\"DELETE FROM users WHERE id = ?\");",
4020
+ "why": "No owner check; any logged‑in user can delete any user",
4021
+ "line": 6
4022
+ }
4023
+ ],
4024
+ "severity": "high",
4025
+ "confidence": "high",
4026
+ "cwe": [
4027
+ "CWE-639",
4028
+ "CWE-284"
4029
+ ],
4030
+ "recommendation": "Bind delete to current session user",
4031
+ "status": "confirmed",
4032
+ "verification": {
4033
+ "verdict": "confirmed",
4034
+ "reason_code": "traced",
4035
+ "checked": [
4036
+ "php-plain/manage_users.php"
4037
+ ],
4038
+ "control_found": null,
4039
+ "notes": "The POST handler deletes a user by id without any ownership or role check; only authentication is enforced by the included auth.php.",
4040
+ "suggested_subtype": null,
4041
+ "suggested_cwe": null
4042
+ },
4043
+ "fingerprint": "kfp1:08e7e40b1898b061e12415cfde4fc28a2ba729418d4c548f7e22b68a4056e0cc",
4044
+ "baseline_state": "new"
4045
+ },
4046
+ {
4047
+ "finding_id": "BOLA-R-0061",
4048
+ "category": "bola",
4049
+ "subtype": "missing_ownership_check",
4050
+ "title": "BOLA in GET /php-plain/order_detail.php: missing owner verification",
4051
+ "route_id": "R-0061",
4052
+ "endpoint": {
4053
+ "method": "GET",
4054
+ "path": "/php-plain/order_detail.php"
4055
+ },
4056
+ "location": {
4057
+ "file": "php-plain/order_detail.php",
4058
+ "start_line": 5
4059
+ },
4060
+ "evidence": [
4061
+ {
4062
+ "file": "php-plain/order_detail.php",
4063
+ "start_line": 5,
4064
+ "code": "$id = $_GET['id'];",
4065
+ "why": "ID comes from request",
4066
+ "line": 5
4067
+ },
4068
+ {
4069
+ "file": "php-plain/order_detail.php",
4070
+ "start_line": 6,
4071
+ "code": "$res = mysql_query(\"SELECT * FROM orders WHERE id = \" . $id);",
4072
+ "why": "No owner check; any logged‑in user can view any order",
4073
+ "line": 6
4074
+ }
4075
+ ],
4076
+ "severity": "high",
4077
+ "confidence": "high",
4078
+ "cwe": [
4079
+ "CWE-639",
4080
+ "CWE-284"
4081
+ ],
4082
+ "recommendation": "Bind query to current session user",
4083
+ "status": "confirmed",
4084
+ "verification": {
4085
+ "verdict": "confirmed",
4086
+ "reason_code": "traced",
4087
+ "checked": [
4088
+ "php-plain/order_detail.php"
4089
+ ],
4090
+ "control_found": null,
4091
+ "notes": "The order detail page queries orders by id directly from $_GET without verifying that the order belongs to the current session user.",
4092
+ "suggested_subtype": null,
4093
+ "suggested_cwe": null
4094
+ },
4095
+ "fingerprint": "kfp1:140efc93b08c193dd167db59f6a495c4cda56c967489cf32705bb8e227ed82e4",
4096
+ "baseline_state": "new"
4097
+ },
4098
+ {
4099
+ "finding_id": "BOLA-R-0066",
4100
+ "category": "bola",
4101
+ "subtype": "missing_ownership_check",
4102
+ "title": "BOLA in POST /php-plain/admin/delete_user.php: missing owner verification",
4103
+ "route_id": "R-0066",
4104
+ "endpoint": {
4105
+ "method": "POST",
4106
+ "path": "/php-plain/admin/delete_user.php"
4107
+ },
4108
+ "location": {
4109
+ "file": "php-plain/admin/delete_user.php",
4110
+ "start_line": 5
4111
+ },
4112
+ "evidence": [
4113
+ {
4114
+ "file": "php-plain/admin/delete_user.php",
4115
+ "start_line": 5,
4116
+ "code": "$id = (int)$_POST['id'];",
4117
+ "why": "ID comes from request",
4118
+ "line": 5
4119
+ },
4120
+ {
4121
+ "file": "php-plain/admin/delete_user.php",
4122
+ "start_line": 6,
4123
+ "code": "$stmt = $db->prepare(\"DELETE FROM users WHERE id = ?\");",
4124
+ "why": "No owner check; any logged‑in user can delete any user",
4125
+ "line": 6
4126
+ }
4127
+ ],
4128
+ "severity": "high",
4129
+ "confidence": "high",
4130
+ "cwe": [
4131
+ "CWE-639",
4132
+ "CWE-284"
4133
+ ],
4134
+ "recommendation": "Bind delete to current session user",
4135
+ "status": "confirmed",
4136
+ "verification": {
4137
+ "verdict": "confirmed",
4138
+ "reason_code": "traced",
4139
+ "checked": [
4140
+ "php-plain/admin/delete_user.php"
4141
+ ],
4142
+ "control_found": null,
4143
+ "notes": "The file contains only a login check via require_once '../inc/auth.php'; no ownership or role verification is performed before executing the DELETE statement.",
4144
+ "suggested_subtype": null,
4145
+ "suggested_cwe": null
4146
+ },
4147
+ "fingerprint": "kfp1:0da2f858297a3d4ebd54b94ece77760ab41c73280cf69a320b15b12ae8d88b7f",
4148
+ "baseline_state": "new"
4149
+ },
4150
+ {
4151
+ "finding_id": "BOLA-R-0067",
4152
+ "category": "bola",
4153
+ "subtype": "missing_ownership_check",
4154
+ "title": "BOLA in POST /php-plain/admin/promote.php: missing owner verification",
4155
+ "route_id": "R-0067",
4156
+ "endpoint": {
4157
+ "method": "POST",
4158
+ "path": "/php-plain/admin/promote.php"
4159
+ },
4160
+ "location": {
4161
+ "file": "php-plain/admin/promote.php",
4162
+ "start_line": 5
4163
+ },
4164
+ "evidence": [
4165
+ {
4166
+ "file": "php-plain/admin/promote.php",
4167
+ "start_line": 5,
4168
+ "code": "if ($_POST['is_admin'] == '1') {",
4169
+ "why": "ID comes from request",
4170
+ "line": 5
4171
+ },
4172
+ {
4173
+ "file": "php-plain/admin/promote.php",
4174
+ "start_line": 6,
4175
+ "code": "$stmt = $db->prepare(\"UPDATE users SET role = 'admin' WHERE id = ?\");",
4176
+ "why": "No owner check; any logged‑in user can promote any user",
4177
+ "line": 6
4178
+ }
4179
+ ],
4180
+ "severity": "high",
4181
+ "confidence": "high",
4182
+ "cwe": [
4183
+ "CWE-639",
4184
+ "CWE-284"
4185
+ ],
4186
+ "recommendation": "Bind role change to current session user",
4187
+ "status": "confirmed",
4188
+ "verification": {
4189
+ "verdict": "confirmed",
4190
+ "reason_code": "traced",
4191
+ "checked": [
4192
+ "php-plain/admin/promote.php"
4193
+ ],
4194
+ "control_found": null,
4195
+ "notes": "Only a login check is performed; the UPDATE statement changes a user's role based solely on the supplied id, with no ownership or role guard.",
4196
+ "suggested_subtype": null,
4197
+ "suggested_cwe": null
4198
+ },
4199
+ "fingerprint": "kfp1:c015ee6be1af117790c78fc9a97374926e8a34a36361142150be94c318ff9dd8",
4200
+ "baseline_state": "new"
4201
+ },
4202
+ {
4203
+ "finding_id": "BOLA-R-0069",
4204
+ "category": "bola",
4205
+ "subtype": "missing_ownership_check",
4206
+ "title": "BOLA in GET /orders/<int:order_id>: missing owner verification",
4207
+ "route_id": "R-0069",
4208
+ "endpoint": {
4209
+ "method": "GET",
4210
+ "path": "/orders/<int:order_id>"
4211
+ },
4212
+ "location": {
4213
+ "file": "python-flask/app.py",
4214
+ "start_line": 12
4215
+ },
4216
+ "evidence": [
4217
+ {
4218
+ "file": "python-flask/app.py",
4219
+ "start_line": 12,
4220
+ "code": "cur.execute(\"SELECT * FROM orders WHERE id = %s\" % order_id)",
4221
+ "why": "No owner check; any logged‑in user can view any order",
4222
+ "line": 12
4223
+ }
4224
+ ],
4225
+ "severity": "high",
4226
+ "confidence": "high",
4227
+ "cwe": [
4228
+ "CWE-639",
4229
+ "CWE-284"
4230
+ ],
4231
+ "recommendation": "Bind query to current user",
4232
+ "status": "confirmed",
4233
+ "verification": {
4234
+ "verdict": "confirmed",
4235
+ "reason_code": "traced",
4236
+ "checked": [
4237
+ "python-flask/app.py"
4238
+ ],
4239
+ "control_found": null,
4240
+ "notes": "The route '/orders/<int:order_id>' executes a raw SQL query with the id interpolated directly; no ownership check is performed before returning the result.",
4241
+ "suggested_subtype": null,
4242
+ "suggested_cwe": null
4243
+ },
4244
+ "fingerprint": "kfp1:8cba56db899ed30b4e1dab440f085921515c324f8d9fff2d15ee38eb60afa641",
4245
+ "baseline_state": "new"
4246
+ },
4247
+ {
4248
+ "finding_id": "BOLA-R-0073",
4249
+ "category": "bola",
4250
+ "subtype": "no_authentication",
4251
+ "title": "BOLA in POST /users/<int:uid>/name: missing owner verification",
4252
+ "route_id": "R-0073",
4253
+ "endpoint": {
4254
+ "method": "POST",
4255
+ "path": "/users/<int:uid>/name"
4256
+ },
4257
+ "location": {
4258
+ "file": "python-flask/profile.py",
4259
+ "start_line": 16
4260
+ },
4261
+ "evidence": [
4262
+ {
4263
+ "file": "python-flask/profile.py",
4264
+ "start_line": 16,
4265
+ "code": "def rename(uid):\n user = User.query.get(uid)\n user.name = request.json[\"name\"]\n db.session.commit()\n return jsonify(ok=True)",
4266
+ "why": "The user ID comes from the URL and is used directly to load and update a user record without any check that the ID belongs to the authenticated user.",
4267
+ "line": 16
4268
+ }
4269
+ ],
4270
+ "severity": "high",
4271
+ "confidence": "high",
4272
+ "cwe": [
4273
+ "CWE-284",
4274
+ "CWE-639"
4275
+ ],
4276
+ "recommendation": "Bind the update to the current session user and reject mismatches.",
4277
+ "status": "confirmed",
4278
+ "verification": {
4279
+ "verdict": "confirmed",
4280
+ "reason_code": "traced",
4281
+ "checked": [
4282
+ "python-flask/profile.py lines 16-20"
4283
+ ],
4284
+ "control_found": null,
4285
+ "notes": "The handler directly loads a user by the URL‑supplied UID and updates the name without any authentication or ownership verification.",
4286
+ "suggested_subtype": null,
4287
+ "suggested_cwe": null
4288
+ },
4289
+ "fingerprint": "kfp1:13e05b9a7b3333a47043d9e63d83eb1f331ab20f5dc9e639468aee4c41cc37bd",
4290
+ "baseline_state": "new"
4291
+ },
4292
+ {
4293
+ "finding_id": "BOLA-R-0074",
4294
+ "category": "bola",
4295
+ "subtype": "no_authentication",
4296
+ "title": "BOLA in PATCH /users/<int:uid>: missing owner verification",
4297
+ "route_id": "R-0074",
4298
+ "endpoint": {
4299
+ "method": "PATCH",
4300
+ "path": "/users/<int:uid>"
4301
+ },
4302
+ "location": {
4303
+ "file": "python-flask/profile.py",
4304
+ "start_line": 24
4305
+ },
4306
+ "evidence": [
4307
+ {
4308
+ "file": "python-flask/profile.py",
4309
+ "start_line": 24,
4310
+ "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()\n return jsonify(ok=True)",
4311
+ "why": "The user ID is taken from the URL and used to load a user record without verifying that the ID belongs to the authenticated user.",
4312
+ "line": 24
4313
+ }
4314
+ ],
4315
+ "severity": "high",
4316
+ "confidence": "medium",
4317
+ "cwe": [
4318
+ "CWE-284",
4319
+ "CWE-639"
4320
+ ],
4321
+ "recommendation": "Verify that the target user ID matches the current session user before applying changes.",
4322
+ "status": "likely",
4323
+ "verification": {
4324
+ "verdict": "likely",
4325
+ "reason_code": "code_not_visible",
4326
+ "checked": [
4327
+ "python-flask/profile.py lines 24-30"
4328
+ ],
4329
+ "control_found": null,
4330
+ "notes": "The PATCH endpoint loads a user by ID and updates it without any visible authentication or ownership check. The Auth Model does not cover the python‑flask sub‑application, and no global filter or middleware is shown in the code_context.",
4331
+ "suggested_subtype": null,
4332
+ "suggested_cwe": null
4333
+ },
4334
+ "fingerprint": "kfp1:489270bd0d234692c056a3cd3a9172890b9f9812278cff70e446bfade7f7de41",
4335
+ "baseline_state": "new"
4336
+ },
4337
+ {
4338
+ "finding_id": "INJ-I-0005",
4339
+ "category": "sql_injection",
4340
+ "subtype": "string_concatenation",
4341
+ "title": "SQL Injection in classic-asp/shop/order.asp:12",
4342
+ "candidate_id": "I-0005",
4343
+ "location": {
4344
+ "file": "classic-asp/shop/order.asp",
4345
+ "start_line": 12
4346
+ },
4347
+ "evidence": [
4348
+ {
4349
+ "file": "classic-asp/shop/order.asp",
4350
+ "start_line": 12,
4351
+ "code": "Set rs2 = conn.Execute(\"SELECT * FROM orders WHERE id = \" & sid & \" AND user_id = \" & CLng(Session(\"UserID\")))",
4352
+ "why": "Unsanitized input concatenated into query",
4353
+ "line": 12
4354
+ }
4355
+ ],
4356
+ "severity": "critical",
4357
+ "confidence": "high",
4358
+ "cwe": [
4359
+ "CWE-89"
4360
+ ],
4361
+ "recommendation": "Use parameterized queries or stored procedures",
4362
+ "status": "rejected",
4363
+ "verification": {
4364
+ "verdict": "rejected",
4365
+ "reason_code": "control_found",
4366
+ "checked": [
4367
+ "classic-asp/shop/order.asp:10-12",
4368
+ "classic-asp/shop/inc/auth.asp:1-3",
4369
+ "classic-asp/shop/inc/conn.asp:1-4"
4370
+ ],
4371
+ "control_found": {
4372
+ "file": "classic-asp/shop/order.asp",
4373
+ "line": 10,
4374
+ "code": "sid = CLng(Request.QueryString(\"sid\"))"
4375
+ },
4376
+ "notes": "The sid value is cast to a long integer before concatenation, preventing SQL injection. The user_id is also cast to CLng(Session(\"UserID\")).",
4377
+ "suggested_subtype": null,
4378
+ "suggested_cwe": null
4379
+ },
4380
+ "fingerprint": "kfp1:e2716780282320839bea274168fbf79466e379ba46017b4d17ab8ce1703c7742"
4381
+ }
4382
+ ]
4383
+ }