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