@hoanghainh/komagu 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/LICENSE +202 -0
- package/README.md +1 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/ai-run-stats.json +87 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/auth-model.md +120 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/index.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/injection-001.json +383 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/injection-002.json +205 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/privilege-001.json +838 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/privilege-002.json +124 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-001.json +778 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-002.json +546 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-003.json +661 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-004.json +659 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-005.json +612 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/batches/routes-006.json +106 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/coverage.json +19 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-001.json +516 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-002.json +332 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-003.json +218 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-004.json +561 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-005.json +316 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/bola-routes-006.json +14 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/inj-injection-001.json +782 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/inj-injection-002.json +418 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/priv-privilege-001.json +627 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/priv-privilege-002.json +253 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-1.json +68 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-10.json +68 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-11.json +61 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-12.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-13.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-14.json +66 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-15.json +69 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-16.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-17.json +61 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-18.json +69 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-19.json +64 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-2.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-20.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-21.json +61 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-22.json +50 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-3.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-4.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-5.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-6.json +70 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-7.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-8.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings/verified-9.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/findings.json +4857 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/report.ja.md +2112 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/report.md +2112 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/score.json +82 -0
- package/assess/lsa/examples/eval-run-6/gptoss-a/stack-profile.json +225 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/ai-run-stats.json +91 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/auth-model.md +120 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/index.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/injection-001.json +383 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/injection-002.json +205 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/privilege-001.json +838 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/privilege-002.json +124 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-001.json +778 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-002.json +546 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-003.json +661 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-004.json +659 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-005.json +612 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/batches/routes-006.json +106 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/coverage.json +21 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-001.json +593 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-002.json +367 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-003.json +207 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-004.json +477 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-005.json +341 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/bola-routes-006.json +14 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/inj-injection-001.json +821 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/inj-injection-002.json +410 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/priv-privilege-001.json +649 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/priv-privilege-002.json +222 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-1.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-10.json +67 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-11.json +68 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-12.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-13.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-14.json +64 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-15.json +70 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-16.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-17.json +61 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-18.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-19.json +65 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-2.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-20.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-21.json +62 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-22.json +50 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-3.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-4.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-5.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-6.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-7.json +64 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-8.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings/verified-9.json +60 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/findings.json +4966 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/score.json +87 -0
- package/assess/lsa/examples/eval-run-6/gptoss-b/stack-profile.json +225 -0
- package/assess/lsa/examples/eval-run-6/ground-truth.json +851 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/ai-run-stats.json +96 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/auth-model.md +191 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/index.json +60 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/injection-001.json +383 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/injection-002.json +205 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/privilege-001.json +838 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/privilege-002.json +124 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-001.json +778 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-002.json +546 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-003.json +661 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-004.json +659 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-005.json +612 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/batches/routes-006.json +106 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/coverage.json +31 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-001.json +527 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-002.json +568 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-003.json +467 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-004.json +342 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-005.json +693 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/bola-routes-006.json +16 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/inj-injection-001.json +1123 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/inj-injection-002.json +391 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/priv-privilege-001.json +726 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/priv-privilege-002.json +306 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-1.json +137 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-10.json +106 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-11.json +81 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-12.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-13.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-14.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-15.json +110 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-16.json +116 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-17.json +141 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-18.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-19.json +140 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-2.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-20.json +82 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-21.json +74 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-22.json +99 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-3.json +140 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-4.json +145 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-5.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-6.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-7.json +87 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-8.json +125 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings/verified-9.json +135 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/findings.json +6989 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/mass-assignment.candidates.json +232 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/memory.log +36 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-001.json +425 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-002.json +333 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-003.json +400 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-004.json +403 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-005.json +398 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/routes/routes-006.json +63 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/score.json +106 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-nothink/stack-profile.json +225 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/auth-model.md +517 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-001.json +5 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-002.json +428 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-003.json +388 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-004.json +463 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-005.json +5 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/bola-routes-006.json +67 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings/inj-injection-001.json +964 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/findings.partial.json +1872 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/memory.log +194 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/score.partial.json +108 -0
- package/assess/lsa/examples/eval-run-6/qwen-16k-partial/stack-profile.json +225 -0
- package/assess/lsa/scripts/detect_stack.py +13 -5
- package/assess/lsa/scripts/find_injection.py +35 -2
- package/assess/lsa/scripts/java_routes.py +323 -0
- package/assess/lsa/scripts/laravel_routes.py +102 -0
- package/assess/lsa/scripts/lsa_common.py +72 -2
- package/assess/lsa/scripts/map_routes.py +40 -161
- package/assess/lsa/scripts/merge_findings.py +2 -0
- package/assess/lsa/tests/EVAL-RESULTS.md +126 -0
- package/assess/lsa/tests/test_eval_run_6.py +104 -0
- package/assess/lsa/tests/test_java_legacy_realistic.py +453 -0
- package/assess/lsa/tests/test_laravel_routes.py +95 -0
- package/contracts/schemas/persona-suite.schema.json +38 -2
- package/examples/member-portal/backend-dotnet/Dockerfile +2 -1
- package/examples/member-portal/backend-spring/Dockerfile +2 -0
- package/examples/member-portal/docker-compose.yml +1 -1
- package/examples/member-portal/frontend/Dockerfile +3 -2
- package/examples/member-portal/frontend/package-lock.json +24 -656
- package/examples/member-portal/frontend/package.json +1 -1
- package/operate/ai/client.py +22 -9
- package/operate/ai/runner.py +24 -4
- package/operate/cli/__init__.py +1 -1
- package/operate/cli/commands/fix.py +4 -0
- package/operate/cli/commands/leak_check.py +75 -0
- package/operate/cli/commands/protect.py +32 -3
- package/operate/cli/commands/scan.py +8 -1
- package/operate/cli/commands/test.py +131 -15
- package/operate/cli/main.py +5 -3
- package/operate/cross_user_tester/persona_matrix.py +118 -25
- package/operate/cross_user_tester/runner.py +190 -7
- package/operate/cross_user_tester/session_config.py +180 -0
- package/operate/cross_user_tester/session_http.py +288 -0
- package/operate/devsecops/leak_check.py +314 -0
- package/operate/remediator/runner.py +18 -1
- package/operate/remediator/strategies.py +2 -2
- package/operate/simulate/scenarios.py +2 -2
- package/operate/tests/mock_legacy_session_app.py +160 -0
- package/operate/tests/test_ai_reasoning_effort.py +65 -0
- package/operate/tests/test_ai_route_inventory.py +53 -0
- package/operate/tests/test_cross_user_session.py +565 -0
- package/operate/tests/test_docker_packaging.py +3 -3
- package/operate/tests/test_headless_ai.py +6 -0
- package/operate/tests/test_leak_check.py +250 -0
- package/operate/tests/test_legacy_session_edge.py +192 -0
- package/operate/tests/test_pilot_safeguards.py +245 -0
- package/operate/tests/test_remediator_java_legacy.py +330 -0
- package/package.json +2 -1
- package/remediate/authz/patcher.py +120 -11
- package/remediate/authz/tests/test_bola_patcher.py +4 -1
- package/remediate/edge/coraza/Caddyfile +1 -1
- package/remediate/edge/coraza/Dockerfile +9 -0
- package/remediate/edge/coraza/rules/coraza-crs-custom.conf +12 -0
- package/remediate/edge/coraza/virtual_patcher.py +24 -0
- package/remediate/edge/docker-compose.yml +7 -2
- package/remediate/edge/kong/kong-legacy-session.yaml +51 -0
- package/remediate/edge/mock-backend/Dockerfile +2 -0
- package/remediate/edge/tests/test_edge_security.py +21 -1
- package/remediate/resilience/terraform/backup_worm.tf +39 -1
- package/remediate/resilience/terraform/main.tf +15 -3
- package/remediate/resilience/terraform/variables.tf +11 -0
- package/remediate/resilience/tests/test_resilience.py +16 -0
|
@@ -0,0 +1,1872 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generated_by": "partial (no verifier)",
|
|
3
|
+
"summary": {},
|
|
4
|
+
"findings": [
|
|
5
|
+
{
|
|
6
|
+
"finding_id": "BOLA-R-0020-1",
|
|
7
|
+
"category": "bola",
|
|
8
|
+
"subtype": "missing_ownership_check",
|
|
9
|
+
"title": "Account save missing ownership verification",
|
|
10
|
+
"route_id": "R-0020",
|
|
11
|
+
"endpoint": {
|
|
12
|
+
"method": "POST",
|
|
13
|
+
"path": "/account/save"
|
|
14
|
+
},
|
|
15
|
+
"location": {
|
|
16
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
17
|
+
"start_line": 13,
|
|
18
|
+
"end_line": 16
|
|
19
|
+
},
|
|
20
|
+
"evidence": [
|
|
21
|
+
{
|
|
22
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
23
|
+
"line": 14,
|
|
24
|
+
"code": "public String save(@ModelAttribute Account account) {",
|
|
25
|
+
"why": "ID comes from request model binding (form/body), not verified against session user"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
29
|
+
"line": 15,
|
|
30
|
+
"code": "accountDao.save(account);",
|
|
31
|
+
"why": "No ownership check (e.g. WHERE user_id = ?) before save"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"attack_scenario": "User A sends POST /account/save with account.id set to User B's ID and modifies the data.",
|
|
35
|
+
"impact": "Modify another customer's account details (name, email, etc.).",
|
|
36
|
+
"severity": "high",
|
|
37
|
+
"confidence": "high",
|
|
38
|
+
"cwe": [
|
|
39
|
+
"CWE-639"
|
|
40
|
+
],
|
|
41
|
+
"owasp": [
|
|
42
|
+
"API1:2023"
|
|
43
|
+
],
|
|
44
|
+
"recommendation": "Add ownership verification in the DAO or controller to ensure the account belongs to the current user before saving.",
|
|
45
|
+
"status": "unverified",
|
|
46
|
+
"attack_vector": {
|
|
47
|
+
"target_param": "id"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"finding_id": "BOLA-R-0021-1",
|
|
52
|
+
"category": "bola",
|
|
53
|
+
"subtype": "missing_ownership_check",
|
|
54
|
+
"title": "Account rename missing ownership verification",
|
|
55
|
+
"route_id": "R-0021",
|
|
56
|
+
"endpoint": {
|
|
57
|
+
"method": "POST",
|
|
58
|
+
"path": "/account/rename"
|
|
59
|
+
},
|
|
60
|
+
"location": {
|
|
61
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
62
|
+
"start_line": 19,
|
|
63
|
+
"end_line": 22
|
|
64
|
+
},
|
|
65
|
+
"evidence": [
|
|
66
|
+
{
|
|
67
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
68
|
+
"line": 20,
|
|
69
|
+
"code": "public String rename(@ModelAttribute RenameForm form) {",
|
|
70
|
+
"why": "ID comes from request model binding (form), not verified against session user"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
74
|
+
"line": 21,
|
|
75
|
+
"code": "accountDao.rename(form.getId(), form.getName());",
|
|
76
|
+
"why": "No ownership check (e.g. WHERE user_id = ?) before rename"
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"attack_scenario": "User A sends POST /account/rename with form.id set to User B's ID and a new name.",
|
|
80
|
+
"impact": "Modify another customer's account name.",
|
|
81
|
+
"severity": "high",
|
|
82
|
+
"confidence": "high",
|
|
83
|
+
"cwe": [
|
|
84
|
+
"CWE-639"
|
|
85
|
+
],
|
|
86
|
+
"owasp": [
|
|
87
|
+
"API1:2023"
|
|
88
|
+
],
|
|
89
|
+
"recommendation": "Add ownership verification in the DAO or controller to ensure the account belongs to the current user before renaming.",
|
|
90
|
+
"status": "unverified",
|
|
91
|
+
"attack_vector": {
|
|
92
|
+
"target_param": "id"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"finding_id": "BOLA-R-0022-1",
|
|
97
|
+
"category": "bola",
|
|
98
|
+
"subtype": "missing_ownership_check",
|
|
99
|
+
"title": "Account API update missing ownership verification",
|
|
100
|
+
"route_id": "R-0022",
|
|
101
|
+
"endpoint": {
|
|
102
|
+
"method": "PUT",
|
|
103
|
+
"path": "/account/api"
|
|
104
|
+
},
|
|
105
|
+
"location": {
|
|
106
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
107
|
+
"start_line": 25,
|
|
108
|
+
"end_line": 28
|
|
109
|
+
},
|
|
110
|
+
"evidence": [
|
|
111
|
+
{
|
|
112
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
113
|
+
"line": 26,
|
|
114
|
+
"code": "public Account update(@RequestBody Account account) {",
|
|
115
|
+
"why": "ID comes from request body, not verified against session user"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"file": "java-legacy/src/com/acme/web/AccountController.java",
|
|
119
|
+
"line": 27,
|
|
120
|
+
"code": "return accountDao.save(account);",
|
|
121
|
+
"why": "No ownership check (e.g. WHERE user_id = ?) before save"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"attack_scenario": "User A sends PUT /account/api with account.id set to User B's ID and modified data.",
|
|
125
|
+
"impact": "Modify another customer's account details via API.",
|
|
126
|
+
"severity": "high",
|
|
127
|
+
"confidence": "high",
|
|
128
|
+
"cwe": [
|
|
129
|
+
"CWE-639"
|
|
130
|
+
],
|
|
131
|
+
"owasp": [
|
|
132
|
+
"API1:2023"
|
|
133
|
+
],
|
|
134
|
+
"recommendation": "Add ownership verification in the DAO or controller to ensure the account belongs to the current user before saving.",
|
|
135
|
+
"status": "unverified",
|
|
136
|
+
"attack_vector": {
|
|
137
|
+
"target_param": "id"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"finding_id": "BOLA-R-0023-1",
|
|
142
|
+
"category": "bola",
|
|
143
|
+
"subtype": "missing_role_check",
|
|
144
|
+
"title": "Admin user delete missing role check",
|
|
145
|
+
"route_id": "R-0023",
|
|
146
|
+
"endpoint": {
|
|
147
|
+
"method": "POST",
|
|
148
|
+
"path": "/admin/users/{id}/delete"
|
|
149
|
+
},
|
|
150
|
+
"location": {
|
|
151
|
+
"file": "java-legacy/src/com/acme/web/AdminUserController.java",
|
|
152
|
+
"start_line": 13,
|
|
153
|
+
"end_line": 16
|
|
154
|
+
},
|
|
155
|
+
"evidence": [
|
|
156
|
+
{
|
|
157
|
+
"file": "java-legacy/src/com/acme/web/AdminUserController.java",
|
|
158
|
+
"line": 14,
|
|
159
|
+
"code": "public String delete(@PathVariable(\"id\") Long id) {",
|
|
160
|
+
"why": "No @PreAuthorize annotation restricting access to ADMIN role"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"file": "java-legacy/src/com/acme/web/AdminUserController.java",
|
|
164
|
+
"line": 15,
|
|
165
|
+
"code": "userDao.deleteById(id);",
|
|
166
|
+
"why": "Allows deletion of any user ID without verifying admin status or ownership"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
"attack_scenario": "User A sends POST /admin/users/{id}/delete with User B's ID. If no role check, User A can delete User B.",
|
|
170
|
+
"impact": "Delete another user's account (Privilege Escalation / BOLA).",
|
|
171
|
+
"severity": "high",
|
|
172
|
+
"confidence": "high",
|
|
173
|
+
"cwe": [
|
|
174
|
+
"CWE-285"
|
|
175
|
+
],
|
|
176
|
+
"owasp": [
|
|
177
|
+
"API5:2023"
|
|
178
|
+
],
|
|
179
|
+
"recommendation": "Add @PreAuthorize(\"hasRole('ADMIN')\") to restrict access to authorized administrators only.",
|
|
180
|
+
"status": "unverified",
|
|
181
|
+
"attack_vector": {
|
|
182
|
+
"target_param": "id"
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"finding_id": "BOLA-R-0025-1",
|
|
187
|
+
"category": "bola",
|
|
188
|
+
"subtype": "missing_ownership_check",
|
|
189
|
+
"title": "Invoice read missing ownership verification",
|
|
190
|
+
"route_id": "R-0025",
|
|
191
|
+
"endpoint": {
|
|
192
|
+
"method": "GET",
|
|
193
|
+
"path": "/invoices/{id}"
|
|
194
|
+
},
|
|
195
|
+
"location": {
|
|
196
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
197
|
+
"start_line": 15,
|
|
198
|
+
"end_line": 18
|
|
199
|
+
},
|
|
200
|
+
"evidence": [
|
|
201
|
+
{
|
|
202
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
203
|
+
"line": 16,
|
|
204
|
+
"code": "public String show(@PathVariable(\"id\") Long id, Model model) {",
|
|
205
|
+
"why": "ID comes from path parameter, not verified against session user"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
209
|
+
"line": 17,
|
|
210
|
+
"code": "model.addAttribute(\"invoice\", invoiceDao.findById(id));",
|
|
211
|
+
"why": "No ownership check (e.g. findByIdAndOwner) before returning data"
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
"attack_scenario": "User A sends GET /invoices/{id} with User B's Invoice ID.",
|
|
215
|
+
"impact": "Read another customer's invoice details (amount, items, etc.).",
|
|
216
|
+
"severity": "high",
|
|
217
|
+
"confidence": "high",
|
|
218
|
+
"cwe": [
|
|
219
|
+
"CWE-639"
|
|
220
|
+
],
|
|
221
|
+
"owasp": [
|
|
222
|
+
"API1:2023"
|
|
223
|
+
],
|
|
224
|
+
"recommendation": "Add ownership verification in the DAO or controller to ensure the invoice belongs to the current user before returning data.",
|
|
225
|
+
"status": "unverified",
|
|
226
|
+
"attack_vector": {
|
|
227
|
+
"target_param": "id"
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"finding_id": "BOLA-R-0028-1",
|
|
232
|
+
"category": "bola",
|
|
233
|
+
"subtype": "missing_ownership_check",
|
|
234
|
+
"title": "Order view missing ownership verification",
|
|
235
|
+
"route_id": "R-0028",
|
|
236
|
+
"endpoint": {
|
|
237
|
+
"method": "GET",
|
|
238
|
+
"path": "/order/view"
|
|
239
|
+
},
|
|
240
|
+
"location": {
|
|
241
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
242
|
+
"start_line": 8,
|
|
243
|
+
"end_line": 21
|
|
244
|
+
},
|
|
245
|
+
"evidence": [
|
|
246
|
+
{
|
|
247
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
248
|
+
"line": 11,
|
|
249
|
+
"code": "String id = request.getParameter(\"orderId\");",
|
|
250
|
+
"why": "ID comes from query parameter (request-controlled)"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"file": "java-legacy/src/com/acme/web/OrderServlet.java",
|
|
254
|
+
"line": 15,
|
|
255
|
+
"code": "ResultSet rs = stmt.executeQuery(\"SELECT * FROM orders WHERE id = '\" + id + \"'\");",
|
|
256
|
+
"why": "No ownership check (e.g. AND user_id = ?) in SQL query"
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
"attack_scenario": "User A sends GET /order/view?orderId=<User B's Order ID>.",
|
|
260
|
+
"impact": "Read another customer's order details (items, address, etc.).",
|
|
261
|
+
"severity": "high",
|
|
262
|
+
"confidence": "high",
|
|
263
|
+
"cwe": [
|
|
264
|
+
"CWE-639"
|
|
265
|
+
],
|
|
266
|
+
"owasp": [
|
|
267
|
+
"API1:2023"
|
|
268
|
+
],
|
|
269
|
+
"recommendation": "Add ownership verification in the query to ensure the order belongs to the current user before returning data.",
|
|
270
|
+
"status": "unverified",
|
|
271
|
+
"attack_vector": {
|
|
272
|
+
"target_param": "orderId"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"finding_id": "BOLA-R-0030-1",
|
|
277
|
+
"category": "bola",
|
|
278
|
+
"subtype": "missing_role_check",
|
|
279
|
+
"title": "Admin user delete missing role check",
|
|
280
|
+
"route_id": "R-0030",
|
|
281
|
+
"endpoint": {
|
|
282
|
+
"method": "POST",
|
|
283
|
+
"path": "/admin/users/:id/delete"
|
|
284
|
+
},
|
|
285
|
+
"location": {
|
|
286
|
+
"file": "node-express/routes/admin.js",
|
|
287
|
+
"start_line": 8,
|
|
288
|
+
"end_line": 10
|
|
289
|
+
},
|
|
290
|
+
"evidence": [
|
|
291
|
+
{
|
|
292
|
+
"file": "node-express/routes/admin.js",
|
|
293
|
+
"line": 9,
|
|
294
|
+
"code": "User.deleteOne({ _id: req.params.id }, function () { res.sendStatus(204); });",
|
|
295
|
+
"why": "No role check (e.g. requireAdmin) before deletion"
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
"attack_scenario": "User A sends POST /admin/users/:id/delete with User B's ID. If no role check, User A can delete User B.",
|
|
299
|
+
"impact": "Delete another user's account (Privilege Escalation / BOLA).",
|
|
300
|
+
"severity": "high",
|
|
301
|
+
"confidence": "high",
|
|
302
|
+
"cwe": [
|
|
303
|
+
"CWE-285"
|
|
304
|
+
],
|
|
305
|
+
"owasp": [
|
|
306
|
+
"API5:2023"
|
|
307
|
+
],
|
|
308
|
+
"recommendation": "Add role check middleware (e.g. requireAdmin) to restrict access to authorized administrators only.",
|
|
309
|
+
"status": "unverified",
|
|
310
|
+
"attack_vector": {
|
|
311
|
+
"target_param": "id"
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"finding_id": "BOLA-R-0032-1",
|
|
316
|
+
"category": "bola",
|
|
317
|
+
"subtype": "missing_role_check",
|
|
318
|
+
"title": "Report export missing role check",
|
|
319
|
+
"route_id": "R-0032",
|
|
320
|
+
"endpoint": {
|
|
321
|
+
"method": "GET",
|
|
322
|
+
"path": "/reports/export"
|
|
323
|
+
},
|
|
324
|
+
"location": {
|
|
325
|
+
"file": "node-express/routes/admin.js",
|
|
326
|
+
"start_line": 16,
|
|
327
|
+
"end_line": 18
|
|
328
|
+
},
|
|
329
|
+
"evidence": [
|
|
330
|
+
{
|
|
331
|
+
"file": "node-express/routes/admin.js",
|
|
332
|
+
"line": 17,
|
|
333
|
+
"code": "if (req.query.isAdmin === 'true') { res.json([]); }",
|
|
334
|
+
"why": "Only checks query param for isAdmin, does not verify user role"
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
"attack_scenario": "User A sends GET /reports/export?isAdmin=false. If no role check, User A can export all data.",
|
|
338
|
+
"impact": "Export all users' data (including other customers).",
|
|
339
|
+
"severity": "high",
|
|
340
|
+
"confidence": "high",
|
|
341
|
+
"cwe": [
|
|
342
|
+
"CWE-285"
|
|
343
|
+
],
|
|
344
|
+
"owasp": [
|
|
345
|
+
"API5:2023"
|
|
346
|
+
],
|
|
347
|
+
"recommendation": "Add role check middleware (e.g. requireAdmin) to restrict access to authorized administrators only.",
|
|
348
|
+
"status": "unverified"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"finding_id": "BOLA-R-0033-1",
|
|
352
|
+
"category": "bola",
|
|
353
|
+
"subtype": "missing_ownership_check",
|
|
354
|
+
"title": "Order detail readable by any authenticated user via id parameter",
|
|
355
|
+
"route_id": "R-0033",
|
|
356
|
+
"endpoint": {
|
|
357
|
+
"method": "GET",
|
|
358
|
+
"path": "/orders/:id"
|
|
359
|
+
},
|
|
360
|
+
"location": {
|
|
361
|
+
"file": "node-express/routes/orders.js",
|
|
362
|
+
"start_line": 8,
|
|
363
|
+
"end_line": 10
|
|
364
|
+
},
|
|
365
|
+
"evidence": [
|
|
366
|
+
{
|
|
367
|
+
"file": "node-express/routes/orders.js",
|
|
368
|
+
"line": 8,
|
|
369
|
+
"code": "router.get('/orders/:id', ensureLoggedIn, function (req, res) {",
|
|
370
|
+
"why": "Route protected by login check only"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"file": "node-express/routes/orders.js",
|
|
374
|
+
"line": 9,
|
|
375
|
+
"code": "Order.findById(req.params.id, function (err, order) { res.json(order); });",
|
|
376
|
+
"why": "Query fetches order by id without filtering by owner/user_id"
|
|
377
|
+
}
|
|
378
|
+
],
|
|
379
|
+
"attack_scenario": "User A sends GET /orders/:id?id=<order id of user B> and receives B's order data.",
|
|
380
|
+
"impact": "Read other customers' orders (name, address, amount).",
|
|
381
|
+
"severity": "high",
|
|
382
|
+
"confidence": "high",
|
|
383
|
+
"cwe": [
|
|
384
|
+
"CWE-284",
|
|
385
|
+
"CWE-639"
|
|
386
|
+
],
|
|
387
|
+
"owasp": [
|
|
388
|
+
"API1:2023"
|
|
389
|
+
],
|
|
390
|
+
"recommendation": "Add owner verification by filtering query with user_id from session/token or load order then compare owner and return 404 on mismatch.",
|
|
391
|
+
"status": "unverified",
|
|
392
|
+
"attack_vector": {
|
|
393
|
+
"target_param": "id"
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"finding_id": "BOLA-R-0035-1",
|
|
398
|
+
"category": "bola",
|
|
399
|
+
"subtype": "missing_ownership_check",
|
|
400
|
+
"title": "Reports readable by any authenticated user without ownership filter",
|
|
401
|
+
"route_id": "R-0035",
|
|
402
|
+
"endpoint": {
|
|
403
|
+
"method": "GET",
|
|
404
|
+
"path": "/reports"
|
|
405
|
+
},
|
|
406
|
+
"location": {
|
|
407
|
+
"file": "node-express/routes/orders.js",
|
|
408
|
+
"start_line": 16,
|
|
409
|
+
"end_line": 18
|
|
410
|
+
},
|
|
411
|
+
"evidence": [
|
|
412
|
+
{
|
|
413
|
+
"file": "node-express/routes/orders.js",
|
|
414
|
+
"line": 16,
|
|
415
|
+
"code": "router.get('/reports', ensureLoggedIn, function (req, res) {",
|
|
416
|
+
"why": "Route protected by login check only"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"file": "node-express/routes/orders.js",
|
|
420
|
+
"line": 17,
|
|
421
|
+
"code": "db.query(\"SELECT * FROM reports WHERE month = '\" + req.query.month + \"'\", function (e, rows) { res.json(rows); });",
|
|
422
|
+
"why": "Query fetches all reports without filtering by user_id or owner"
|
|
423
|
+
}
|
|
424
|
+
],
|
|
425
|
+
"attack_scenario": "User A sends GET /reports?month=2024-01 and receives all users' report data.",
|
|
426
|
+
"impact": "Read other customers' reports (financial, operational data).",
|
|
427
|
+
"severity": "high",
|
|
428
|
+
"confidence": "high",
|
|
429
|
+
"cwe": [
|
|
430
|
+
"CWE-284",
|
|
431
|
+
"CWE-639"
|
|
432
|
+
],
|
|
433
|
+
"owasp": [
|
|
434
|
+
"API1:2023"
|
|
435
|
+
],
|
|
436
|
+
"recommendation": "Add owner verification by filtering query with user_id from session/token or load reports then compare owner and return 404 on mismatch.",
|
|
437
|
+
"status": "unverified"
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"finding_id": "BOLA-R-0037-1",
|
|
441
|
+
"category": "bola",
|
|
442
|
+
"subtype": "missing_ownership_check",
|
|
443
|
+
"title": "Item search returns all items without ownership filter",
|
|
444
|
+
"route_id": "R-0037",
|
|
445
|
+
"endpoint": {
|
|
446
|
+
"method": "GET",
|
|
447
|
+
"path": "/search"
|
|
448
|
+
},
|
|
449
|
+
"location": {
|
|
450
|
+
"file": "node-express/routes/orders.js",
|
|
451
|
+
"start_line": 24,
|
|
452
|
+
"end_line": 26
|
|
453
|
+
},
|
|
454
|
+
"evidence": [
|
|
455
|
+
{
|
|
456
|
+
"file": "node-express/routes/orders.js",
|
|
457
|
+
"line": 24,
|
|
458
|
+
"code": "router.get('/search', ensureLoggedIn, function (req, res) {",
|
|
459
|
+
"why": "Route protected by login check only"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"file": "node-express/routes/orders.js",
|
|
463
|
+
"line": 25,
|
|
464
|
+
"code": "db.collection('items').find({ $where: \"this.name == '\" + req.query.n + \"'\" }).toArray(function (e, r) { res.json(r); });",
|
|
465
|
+
"why": "Query searches all items by name without filtering by user_id or owner"
|
|
466
|
+
}
|
|
467
|
+
],
|
|
468
|
+
"attack_scenario": "User A sends GET /search?name=product and receives all users' item data.",
|
|
469
|
+
"impact": "Read other customers' items (names, details).",
|
|
470
|
+
"severity": "high",
|
|
471
|
+
"confidence": "high",
|
|
472
|
+
"cwe": [
|
|
473
|
+
"CWE-284",
|
|
474
|
+
"CWE-639"
|
|
475
|
+
],
|
|
476
|
+
"owasp": [
|
|
477
|
+
"API1:2023"
|
|
478
|
+
],
|
|
479
|
+
"recommendation": "Add owner verification by filtering query with user_id from session/token or load items then compare owner and return 404 on mismatch.",
|
|
480
|
+
"status": "unverified"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"finding_id": "BOLA-R-0038-1",
|
|
484
|
+
"category": "bola",
|
|
485
|
+
"subtype": "no_authentication",
|
|
486
|
+
"title": "Stats endpoint lacks authentication guard and exposes order data",
|
|
487
|
+
"route_id": "R-0038",
|
|
488
|
+
"endpoint": {
|
|
489
|
+
"method": "GET",
|
|
490
|
+
"path": "/stats"
|
|
491
|
+
},
|
|
492
|
+
"location": {
|
|
493
|
+
"file": "node-express/routes/orders.js",
|
|
494
|
+
"start_line": 28,
|
|
495
|
+
"end_line": 30
|
|
496
|
+
},
|
|
497
|
+
"evidence": [
|
|
498
|
+
{
|
|
499
|
+
"file": "node-express/routes/orders.js",
|
|
500
|
+
"line": 28,
|
|
501
|
+
"code": "router.get('/stats', function (req, res) {",
|
|
502
|
+
"why": "No authentication middleware applied"
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"file": "node-express/routes/orders.js",
|
|
506
|
+
"line": 29,
|
|
507
|
+
"code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
|
|
508
|
+
"why": "Query accesses order data without verifying user identity"
|
|
509
|
+
}
|
|
510
|
+
],
|
|
511
|
+
"attack_scenario": "Any user sends GET /stats?shop=123 and receives order statistics for that shop.",
|
|
512
|
+
"impact": "Read order statistics without authentication (potential sensitive business data).",
|
|
513
|
+
"severity": "high",
|
|
514
|
+
"confidence": "high",
|
|
515
|
+
"cwe": [
|
|
516
|
+
"CWE-285",
|
|
517
|
+
"CWE-639"
|
|
518
|
+
],
|
|
519
|
+
"owasp": [
|
|
520
|
+
"API5:2023"
|
|
521
|
+
],
|
|
522
|
+
"recommendation": "Add authentication guard middleware and verify user identity before accessing order data.",
|
|
523
|
+
"status": "unverified"
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
"finding_id": "BOLA-R-0043-1",
|
|
527
|
+
"category": "bola",
|
|
528
|
+
"subtype": "missing_ownership_check",
|
|
529
|
+
"title": "Perl CGI order endpoint fetches orders without ownership verification",
|
|
530
|
+
"route_id": "R-0043",
|
|
531
|
+
"endpoint": {
|
|
532
|
+
"method": "ANY",
|
|
533
|
+
"path": "/perl-cgi/cgi-bin/order.cgi"
|
|
534
|
+
},
|
|
535
|
+
"location": {
|
|
536
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
537
|
+
"start_line": 13,
|
|
538
|
+
"end_line": 15
|
|
539
|
+
},
|
|
540
|
+
"evidence": [
|
|
541
|
+
{
|
|
542
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
543
|
+
"line": 9,
|
|
544
|
+
"code": "my $uid = $session->param('user_id');",
|
|
545
|
+
"why": "User ID from session"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
549
|
+
"line": 13,
|
|
550
|
+
"code": "my $sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");",
|
|
551
|
+
"why": "Query fetches order by id without filtering by user_id"
|
|
552
|
+
}
|
|
553
|
+
],
|
|
554
|
+
"attack_scenario": "User A sends request with different order id and receives another user's order data.",
|
|
555
|
+
"impact": "Read other customers' orders (name, address, amount).",
|
|
556
|
+
"severity": "high",
|
|
557
|
+
"confidence": "high",
|
|
558
|
+
"cwe": [
|
|
559
|
+
"CWE-284",
|
|
560
|
+
"CWE-639"
|
|
561
|
+
],
|
|
562
|
+
"owasp": [
|
|
563
|
+
"API1:2023"
|
|
564
|
+
],
|
|
565
|
+
"recommendation": "Add ownership verification by filtering query with user_id from session or load order then compare owner and return 404 on mismatch.",
|
|
566
|
+
"status": "unverified",
|
|
567
|
+
"attack_vector": {
|
|
568
|
+
"target_param": "user_id"
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
"finding_id": "BOLA-R-0044-1",
|
|
573
|
+
"category": "bola",
|
|
574
|
+
"subtype": "missing_ownership_check",
|
|
575
|
+
"title": "Invoice view endpoint fetches invoice without ownership verification",
|
|
576
|
+
"route_id": "R-0044",
|
|
577
|
+
"endpoint": {
|
|
578
|
+
"method": "ANY",
|
|
579
|
+
"path": "/invoice/view/{id}"
|
|
580
|
+
},
|
|
581
|
+
"location": {
|
|
582
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
583
|
+
"start_line": 9,
|
|
584
|
+
"end_line": 12
|
|
585
|
+
},
|
|
586
|
+
"evidence": [
|
|
587
|
+
{
|
|
588
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
589
|
+
"line": 9,
|
|
590
|
+
"code": "public function view($id) {",
|
|
591
|
+
"why": "Method takes id parameter"
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
595
|
+
"line": 10,
|
|
596
|
+
"code": "$q = $this->db->query(\"SELECT * FROM invoices WHERE id = $id\");",
|
|
597
|
+
"why": "Query fetches invoice by id without filtering by user_id"
|
|
598
|
+
}
|
|
599
|
+
],
|
|
600
|
+
"attack_scenario": "User A sends request with different invoice id and receives another user's invoice data.",
|
|
601
|
+
"impact": "Read other customers' invoices (name, address, amount).",
|
|
602
|
+
"severity": "high",
|
|
603
|
+
"confidence": "high",
|
|
604
|
+
"cwe": [
|
|
605
|
+
"CWE-284",
|
|
606
|
+
"CWE-639"
|
|
607
|
+
],
|
|
608
|
+
"owasp": [
|
|
609
|
+
"API1:2023"
|
|
610
|
+
],
|
|
611
|
+
"recommendation": "Add ownership verification by filtering query with user_id from session or load invoice then compare owner and return 404 on mismatch.",
|
|
612
|
+
"status": "unverified",
|
|
613
|
+
"attack_vector": {
|
|
614
|
+
"target_param": "id"
|
|
615
|
+
}
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
"finding_id": "BOLA-R-0046-1",
|
|
619
|
+
"category": "bola",
|
|
620
|
+
"subtype": "missing_ownership_check",
|
|
621
|
+
"title": "Invoice update endpoint modifies invoice without ownership verification",
|
|
622
|
+
"route_id": "R-0046",
|
|
623
|
+
"endpoint": {
|
|
624
|
+
"method": "ANY",
|
|
625
|
+
"path": "/invoice/update"
|
|
626
|
+
},
|
|
627
|
+
"location": {
|
|
628
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
629
|
+
"start_line": 20,
|
|
630
|
+
"end_line": 24
|
|
631
|
+
},
|
|
632
|
+
"evidence": [
|
|
633
|
+
{
|
|
634
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
635
|
+
"line": 21,
|
|
636
|
+
"code": "$id = $this->input->post('invoice_id');",
|
|
637
|
+
"why": "ID from POST parameter"
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
"file": "php-codeigniter/application/controllers/Invoice.php",
|
|
641
|
+
"line": 23,
|
|
642
|
+
"code": "$this->db->query(\"UPDATE invoices SET note = ? WHERE id = ?\", array($note, $id));",
|
|
643
|
+
"why": "Update query modifies invoice by id without filtering by user_id"
|
|
644
|
+
}
|
|
645
|
+
],
|
|
646
|
+
"attack_scenario": "User A sends POST with different invoice_id and modifies another user's invoice.",
|
|
647
|
+
"impact": "Modify other customers' invoices (notes, data).",
|
|
648
|
+
"severity": "high",
|
|
649
|
+
"confidence": "high",
|
|
650
|
+
"cwe": [
|
|
651
|
+
"CWE-284",
|
|
652
|
+
"CWE-639"
|
|
653
|
+
],
|
|
654
|
+
"owasp": [
|
|
655
|
+
"API1:2023"
|
|
656
|
+
],
|
|
657
|
+
"recommendation": "Add ownership verification by filtering update query with user_id from session or load invoice then compare owner and return 404 on mismatch.",
|
|
658
|
+
"status": "unverified",
|
|
659
|
+
"attack_vector": {
|
|
660
|
+
"target_param": "invoice_id"
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
"finding_id": "BOLA-R-0057-1",
|
|
665
|
+
"category": "bola",
|
|
666
|
+
"subtype": "missing_ownership_check",
|
|
667
|
+
"title": "User view endpoint allows any authenticated user to view another user's record via uid parameter",
|
|
668
|
+
"route_id": "R-0057",
|
|
669
|
+
"endpoint": {
|
|
670
|
+
"method": "GET|POST",
|
|
671
|
+
"path": "/php-plain/admin.php?action=view"
|
|
672
|
+
},
|
|
673
|
+
"location": {
|
|
674
|
+
"file": "php-plain/admin.php",
|
|
675
|
+
"start_line": 6,
|
|
676
|
+
"end_line": 8
|
|
677
|
+
},
|
|
678
|
+
"evidence": [
|
|
679
|
+
{
|
|
680
|
+
"file": "php-plain/admin.php",
|
|
681
|
+
"line": 7,
|
|
682
|
+
"code": "$uid = (int)$_GET['uid'];",
|
|
683
|
+
"why": "ID from query string"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"file": "php-plain/admin.php",
|
|
687
|
+
"line": 8,
|
|
688
|
+
"code": "SELECT * FROM users WHERE id = $uid;",
|
|
689
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
690
|
+
}
|
|
691
|
+
],
|
|
692
|
+
"attack_scenario": "User A sends GET /admin.php?action=view&uid=<user id of user B> and receives B's user record.",
|
|
693
|
+
"impact": "Read other users' personal data (name, email, role).",
|
|
694
|
+
"severity": "high",
|
|
695
|
+
"confidence": "high",
|
|
696
|
+
"cwe": [
|
|
697
|
+
"CWE-284",
|
|
698
|
+
"CWE-639"
|
|
699
|
+
],
|
|
700
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the record then compare owner and return 404 on mismatch.",
|
|
701
|
+
"status": "unverified",
|
|
702
|
+
"attack_vector": {
|
|
703
|
+
"target_param": "uid"
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"finding_id": "BOLA-R-0058-1",
|
|
708
|
+
"category": "bola",
|
|
709
|
+
"subtype": "missing_ownership_check",
|
|
710
|
+
"title": "User delete endpoint allows any authenticated user to delete another user's record via id parameter",
|
|
711
|
+
"route_id": "R-0058",
|
|
712
|
+
"endpoint": {
|
|
713
|
+
"method": "GET|POST",
|
|
714
|
+
"path": "/php-plain/admin.php?action=delete"
|
|
715
|
+
},
|
|
716
|
+
"location": {
|
|
717
|
+
"file": "php-plain/admin.php",
|
|
718
|
+
"start_line": 10,
|
|
719
|
+
"end_line": 12
|
|
720
|
+
},
|
|
721
|
+
"evidence": [
|
|
722
|
+
{
|
|
723
|
+
"file": "php-plain/admin.php",
|
|
724
|
+
"line": 11,
|
|
725
|
+
"code": "$id = $_POST['id'];",
|
|
726
|
+
"why": "ID from POST body"
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"file": "php-plain/admin.php",
|
|
730
|
+
"line": 12,
|
|
731
|
+
"code": "DELETE FROM users WHERE id = $id;",
|
|
732
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
733
|
+
}
|
|
734
|
+
],
|
|
735
|
+
"attack_scenario": "User A sends POST /admin.php?action=delete&id=<user id of user B> and deletes B's account.",
|
|
736
|
+
"impact": "Delete other users' accounts (account takeover, data loss).",
|
|
737
|
+
"severity": "high",
|
|
738
|
+
"confidence": "high",
|
|
739
|
+
"cwe": [
|
|
740
|
+
"CWE-284",
|
|
741
|
+
"CWE-639"
|
|
742
|
+
],
|
|
743
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the record then compare owner and return 404 on mismatch.",
|
|
744
|
+
"status": "unverified",
|
|
745
|
+
"attack_vector": {
|
|
746
|
+
"target_param": "uid"
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
"finding_id": "BOLA-R-0066-1",
|
|
751
|
+
"category": "bola",
|
|
752
|
+
"subtype": "missing_ownership_check",
|
|
753
|
+
"title": "User delete endpoint allows any authenticated user to delete another user's record via id parameter",
|
|
754
|
+
"route_id": "R-0066",
|
|
755
|
+
"endpoint": {
|
|
756
|
+
"method": "POST",
|
|
757
|
+
"path": "/php-plain/admin/delete_user.php"
|
|
758
|
+
},
|
|
759
|
+
"location": {
|
|
760
|
+
"file": "php-plain/admin/delete_user.php",
|
|
761
|
+
"start_line": 5,
|
|
762
|
+
"end_line": 7
|
|
763
|
+
},
|
|
764
|
+
"evidence": [
|
|
765
|
+
{
|
|
766
|
+
"file": "php-plain/admin/delete_user.php",
|
|
767
|
+
"line": 5,
|
|
768
|
+
"code": "$id = (int)$_POST['id'];",
|
|
769
|
+
"why": "ID from POST body"
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
"file": "php-plain/admin/delete_user.php",
|
|
773
|
+
"line": 6,
|
|
774
|
+
"code": "DELETE FROM users WHERE id = ?;",
|
|
775
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
776
|
+
}
|
|
777
|
+
],
|
|
778
|
+
"attack_scenario": "User A sends POST /admin/delete_user.php?id=<user id of user B> and deletes B's account.",
|
|
779
|
+
"impact": "Delete other users' accounts (account takeover, data loss).",
|
|
780
|
+
"severity": "high",
|
|
781
|
+
"confidence": "high",
|
|
782
|
+
"cwe": [
|
|
783
|
+
"CWE-284",
|
|
784
|
+
"CWE-639"
|
|
785
|
+
],
|
|
786
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the record then compare owner and return 404 on mismatch.",
|
|
787
|
+
"status": "unverified",
|
|
788
|
+
"attack_vector": {
|
|
789
|
+
"target_param": "id"
|
|
790
|
+
}
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"finding_id": "BOLA-R-0067-1",
|
|
794
|
+
"category": "bola",
|
|
795
|
+
"subtype": "missing_ownership_check",
|
|
796
|
+
"title": "User promote endpoint allows any authenticated user to promote another user to admin via uid parameter",
|
|
797
|
+
"route_id": "R-0067",
|
|
798
|
+
"endpoint": {
|
|
799
|
+
"method": "POST",
|
|
800
|
+
"path": "/php-plain/admin/promote.php"
|
|
801
|
+
},
|
|
802
|
+
"location": {
|
|
803
|
+
"file": "php-plain/admin/promote.php",
|
|
804
|
+
"start_line": 5,
|
|
805
|
+
"end_line": 7
|
|
806
|
+
},
|
|
807
|
+
"evidence": [
|
|
808
|
+
{
|
|
809
|
+
"file": "php-plain/admin/promote.php",
|
|
810
|
+
"line": 6,
|
|
811
|
+
"code": "$stmt = $db->prepare(\"UPDATE users SET role = 'admin' WHERE id = ?\");",
|
|
812
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"file": "php-plain/admin/promote.php",
|
|
816
|
+
"line": 7,
|
|
817
|
+
"code": "$stmt->execute(array((int)$_POST['uid']));",
|
|
818
|
+
"why": "ID from POST body used directly"
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
"attack_scenario": "User A sends POST /admin/promote.php with uid=<user id of user B> and promotes B to admin.",
|
|
822
|
+
"impact": "Elevate privileges for other users (privilege escalation).",
|
|
823
|
+
"severity": "high",
|
|
824
|
+
"confidence": "high",
|
|
825
|
+
"cwe": [
|
|
826
|
+
"CWE-284",
|
|
827
|
+
"CWE-639"
|
|
828
|
+
],
|
|
829
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the record then compare owner and return 404 on mismatch.",
|
|
830
|
+
"status": "unverified",
|
|
831
|
+
"attack_vector": {
|
|
832
|
+
"target_param": "uid"
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
{
|
|
836
|
+
"finding_id": "BOLA-R-0059-1",
|
|
837
|
+
"category": "bola",
|
|
838
|
+
"subtype": "missing_ownership_check",
|
|
839
|
+
"title": "User delete endpoint allows any authenticated user to delete another user's record via id parameter",
|
|
840
|
+
"route_id": "R-0059",
|
|
841
|
+
"endpoint": {
|
|
842
|
+
"method": "POST",
|
|
843
|
+
"path": "/php-plain/manage_users.php"
|
|
844
|
+
},
|
|
845
|
+
"location": {
|
|
846
|
+
"file": "php-plain/manage_users.php",
|
|
847
|
+
"start_line": 6,
|
|
848
|
+
"end_line": 7
|
|
849
|
+
},
|
|
850
|
+
"evidence": [
|
|
851
|
+
{
|
|
852
|
+
"file": "php-plain/manage_users.php",
|
|
853
|
+
"line": 6,
|
|
854
|
+
"code": "$stmt = $db->prepare(\"DELETE FROM users WHERE id = ?\");",
|
|
855
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
"file": "php-plain/manage_users.php",
|
|
859
|
+
"line": 7,
|
|
860
|
+
"code": "$stmt->execute(array($_POST['id']));",
|
|
861
|
+
"why": "ID from POST body used directly"
|
|
862
|
+
}
|
|
863
|
+
],
|
|
864
|
+
"attack_scenario": "User A sends POST /manage_users.php?id=<user id of user B> and deletes B's account.",
|
|
865
|
+
"impact": "Delete other users' accounts (account takeover, data loss).",
|
|
866
|
+
"severity": "high",
|
|
867
|
+
"confidence": "high",
|
|
868
|
+
"cwe": [
|
|
869
|
+
"CWE-284",
|
|
870
|
+
"CWE-639"
|
|
871
|
+
],
|
|
872
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the record then compare owner and return 404 on mismatch.",
|
|
873
|
+
"status": "unverified",
|
|
874
|
+
"attack_vector": {
|
|
875
|
+
"target_param": "id"
|
|
876
|
+
}
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
"finding_id": "BOLA-R-0061-1",
|
|
880
|
+
"category": "bola",
|
|
881
|
+
"subtype": "missing_ownership_check",
|
|
882
|
+
"title": "Order detail endpoint allows any authenticated user to view another user's order via id parameter",
|
|
883
|
+
"route_id": "R-0061",
|
|
884
|
+
"endpoint": {
|
|
885
|
+
"method": "GET",
|
|
886
|
+
"path": "/php-plain/order_detail.php"
|
|
887
|
+
},
|
|
888
|
+
"location": {
|
|
889
|
+
"file": "php-plain/order_detail.php",
|
|
890
|
+
"start_line": 5,
|
|
891
|
+
"end_line": 8
|
|
892
|
+
},
|
|
893
|
+
"evidence": [
|
|
894
|
+
{
|
|
895
|
+
"file": "php-plain/order_detail.php",
|
|
896
|
+
"line": 5,
|
|
897
|
+
"code": "$id = $_GET['id'];",
|
|
898
|
+
"why": "ID from query string"
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
"file": "php-plain/order_detail.php",
|
|
902
|
+
"line": 6,
|
|
903
|
+
"code": "SELECT * FROM orders WHERE id = $id;",
|
|
904
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
905
|
+
}
|
|
906
|
+
],
|
|
907
|
+
"attack_scenario": "User A sends GET /order_detail.php?id=<order id of user B> and receives B's order details.",
|
|
908
|
+
"impact": "Read other customers' orders (name, address, amount).",
|
|
909
|
+
"severity": "high",
|
|
910
|
+
"confidence": "high",
|
|
911
|
+
"cwe": [
|
|
912
|
+
"CWE-284",
|
|
913
|
+
"CWE-639"
|
|
914
|
+
],
|
|
915
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the order then compare owner and return 404 on mismatch.",
|
|
916
|
+
"status": "unverified",
|
|
917
|
+
"attack_vector": {
|
|
918
|
+
"target_param": "id"
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
"finding_id": "BOLA-R-0069-1",
|
|
923
|
+
"category": "bola",
|
|
924
|
+
"subtype": "missing_ownership_check",
|
|
925
|
+
"title": "Order detail endpoint allows any authenticated user to view another user's order via order_id parameter",
|
|
926
|
+
"route_id": "R-0069",
|
|
927
|
+
"endpoint": {
|
|
928
|
+
"method": "GET",
|
|
929
|
+
"path": "/orders/<int:order_id>"
|
|
930
|
+
},
|
|
931
|
+
"location": {
|
|
932
|
+
"file": "python-flask/app.py",
|
|
933
|
+
"start_line": 11,
|
|
934
|
+
"end_line": 13
|
|
935
|
+
},
|
|
936
|
+
"evidence": [
|
|
937
|
+
{
|
|
938
|
+
"file": "python-flask/app.py",
|
|
939
|
+
"line": 11,
|
|
940
|
+
"code": "def order(order_id):",
|
|
941
|
+
"why": "order_id from URL path"
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
"file": "python-flask/app.py",
|
|
945
|
+
"line": 12,
|
|
946
|
+
"code": "cur.execute(\"SELECT * FROM orders WHERE id = %s\" % order_id)",
|
|
947
|
+
"why": "No user_id ownership check in WHERE clause"
|
|
948
|
+
}
|
|
949
|
+
],
|
|
950
|
+
"attack_scenario": "User A sends GET /orders/<order id of user B> and receives B's order details.",
|
|
951
|
+
"impact": "Read other customers' orders (name, address, amount).",
|
|
952
|
+
"severity": "high",
|
|
953
|
+
"confidence": "high",
|
|
954
|
+
"cwe": [
|
|
955
|
+
"CWE-284",
|
|
956
|
+
"CWE-639"
|
|
957
|
+
],
|
|
958
|
+
"recommendation": "Add AND user_id = :session_user_id to the query or load the order then compare owner and return 404 on mismatch.",
|
|
959
|
+
"status": "unverified",
|
|
960
|
+
"attack_vector": {
|
|
961
|
+
"target_param": "order_id"
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
"finding_id": "BOLA-R-0055-verdict",
|
|
966
|
+
"category": "bola",
|
|
967
|
+
"subtype": "missing_ownership_check",
|
|
968
|
+
"title": "Missing ownership check at php-laravel/routes/web.php:9 (from auditor verdict)",
|
|
969
|
+
"route_id": "R-0055",
|
|
970
|
+
"location": {
|
|
971
|
+
"file": "php-laravel/routes/web.php",
|
|
972
|
+
"start_line": 9
|
|
973
|
+
},
|
|
974
|
+
"evidence": [
|
|
975
|
+
{
|
|
976
|
+
"file": "php-laravel/routes/web.php",
|
|
977
|
+
"line": 9,
|
|
978
|
+
"why": "The auditor judged this route 'needs_review' but wrote no finding"
|
|
979
|
+
}
|
|
980
|
+
],
|
|
981
|
+
"impact": "Generated from the auditor's 'needs_review' verdict; the model wrote no finding for it.",
|
|
982
|
+
"severity": "medium",
|
|
983
|
+
"confidence": "low",
|
|
984
|
+
"cwe": [
|
|
985
|
+
"CWE-284"
|
|
986
|
+
],
|
|
987
|
+
"recommendation": "Bind the object lookup to the current user or tenant, or check ownership before using it.",
|
|
988
|
+
"status": "unverified",
|
|
989
|
+
"endpoint": {
|
|
990
|
+
"method": "POST",
|
|
991
|
+
"path": "/account/rename"
|
|
992
|
+
},
|
|
993
|
+
"attack_vector": {
|
|
994
|
+
"target_param": "id"
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
"finding_id": "BOLA-R-0056-verdict",
|
|
999
|
+
"category": "bola",
|
|
1000
|
+
"subtype": "missing_ownership_check",
|
|
1001
|
+
"title": "Missing ownership check at php-laravel/routes/web.php:10 (from auditor verdict)",
|
|
1002
|
+
"route_id": "R-0056",
|
|
1003
|
+
"location": {
|
|
1004
|
+
"file": "php-laravel/routes/web.php",
|
|
1005
|
+
"start_line": 10
|
|
1006
|
+
},
|
|
1007
|
+
"evidence": [
|
|
1008
|
+
{
|
|
1009
|
+
"file": "php-laravel/routes/web.php",
|
|
1010
|
+
"line": 10,
|
|
1011
|
+
"why": "The auditor judged this route 'needs_review' but wrote no finding"
|
|
1012
|
+
}
|
|
1013
|
+
],
|
|
1014
|
+
"impact": "Generated from the auditor's 'needs_review' verdict; the model wrote no finding for it.",
|
|
1015
|
+
"severity": "medium",
|
|
1016
|
+
"confidence": "low",
|
|
1017
|
+
"cwe": [
|
|
1018
|
+
"CWE-284"
|
|
1019
|
+
],
|
|
1020
|
+
"recommendation": "Bind the object lookup to the current user or tenant, or check ownership before using it.",
|
|
1021
|
+
"status": "unverified",
|
|
1022
|
+
"endpoint": {
|
|
1023
|
+
"method": "POST",
|
|
1024
|
+
"path": "/account/profile"
|
|
1025
|
+
},
|
|
1026
|
+
"attack_vector": {
|
|
1027
|
+
"target_param": "id"
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
"finding_id": "BOLA-R-0065-1",
|
|
1032
|
+
"category": "bola",
|
|
1033
|
+
"subtype": "missing_ownership_check",
|
|
1034
|
+
"title": "Product search returns all products without user ownership verification",
|
|
1035
|
+
"route_id": "R-0065",
|
|
1036
|
+
"endpoint": {
|
|
1037
|
+
"method": "GET",
|
|
1038
|
+
"path": "/php-plain/search.php"
|
|
1039
|
+
},
|
|
1040
|
+
"location": {
|
|
1041
|
+
"file": "php-plain/search.php",
|
|
1042
|
+
"start_line": 7,
|
|
1043
|
+
"end_line": 15
|
|
1044
|
+
},
|
|
1045
|
+
"evidence": [
|
|
1046
|
+
{
|
|
1047
|
+
"file": "php-plain/search.php",
|
|
1048
|
+
"line": 7,
|
|
1049
|
+
"code": "$sql = \"SELECT id, name FROM products WHERE 1=1\";",
|
|
1050
|
+
"why": "Query starts without user_id filter"
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
"file": "php-plain/search.php",
|
|
1054
|
+
"line": 8,
|
|
1055
|
+
"code": "$sql .= \" AND name LIKE '%\" . $kw . \"%'\";",
|
|
1056
|
+
"why": "Only filters by search term, no ownership check"
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
"file": "php-plain/search.php",
|
|
1060
|
+
"line": 14,
|
|
1061
|
+
"code": "WHERE category = '{$_GET['cat']}'",
|
|
1062
|
+
"why": "Category filter only, no user_id or owner binding"
|
|
1063
|
+
}
|
|
1064
|
+
],
|
|
1065
|
+
"attack_scenario": "Authenticated User A sends GET /search.php?q=widget&cat=electronics with another user's product ID in results and receives products they don't own.",
|
|
1066
|
+
"impact": "Read other customers' product data (names, categories, potentially prices if returned).",
|
|
1067
|
+
"severity": "high",
|
|
1068
|
+
"confidence": "high",
|
|
1069
|
+
"cwe": [
|
|
1070
|
+
"CWE-639"
|
|
1071
|
+
],
|
|
1072
|
+
"owasp": [
|
|
1073
|
+
"API1:2023"
|
|
1074
|
+
],
|
|
1075
|
+
"recommendation": "Add AND user_id = :current_user_id to all product queries, or load products then compare owner and return 404 on mismatch",
|
|
1076
|
+
"status": "unverified"
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
"finding_id": "INJ-I-0001",
|
|
1080
|
+
"category": "sql_injection",
|
|
1081
|
+
"subtype": "string_concatenation",
|
|
1082
|
+
"title": "SQL Injection in member.asp via string concatenation",
|
|
1083
|
+
"candidate_id": "I-0001",
|
|
1084
|
+
"location": {
|
|
1085
|
+
"file": "classic-asp/shop/member.asp",
|
|
1086
|
+
"start_line": 6
|
|
1087
|
+
},
|
|
1088
|
+
"evidence": [
|
|
1089
|
+
{
|
|
1090
|
+
"file": "classic-asp/shop/member.asp",
|
|
1091
|
+
"line": 6,
|
|
1092
|
+
"code": "sql = \"UPDATE members SET name = '\" & Replace(Request.Form(\"name\"), \"'\", \"''\") & \"'\"",
|
|
1093
|
+
"why": "User input concatenated into SQL"
|
|
1094
|
+
},
|
|
1095
|
+
{
|
|
1096
|
+
"file": "classic-asp/shop/member.asp",
|
|
1097
|
+
"line": 7,
|
|
1098
|
+
"code": "sql = sql & \" WHERE member_id = \" & Request.Form(\"member_id\")",
|
|
1099
|
+
"why": "User input concatenated into SQL"
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
"file": "classic-asp/shop/member.asp",
|
|
1103
|
+
"line": 8,
|
|
1104
|
+
"code": "conn.Execute sql",
|
|
1105
|
+
"why": "Sink executes constructed query"
|
|
1106
|
+
}
|
|
1107
|
+
],
|
|
1108
|
+
"data_flow": [
|
|
1109
|
+
"Request.Form (name)",
|
|
1110
|
+
"$u",
|
|
1111
|
+
"sql (member.asp:6-7)",
|
|
1112
|
+
"conn.Execute (member.asp:8)"
|
|
1113
|
+
],
|
|
1114
|
+
"attack_scenario": "A crafted name or member_id changes the WHERE clause and bypasses the password check.",
|
|
1115
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1116
|
+
"severity": "critical",
|
|
1117
|
+
"confidence": "high",
|
|
1118
|
+
"cwe": [
|
|
1119
|
+
"CWE-89"
|
|
1120
|
+
],
|
|
1121
|
+
"owasp": [
|
|
1122
|
+
"A03:2021"
|
|
1123
|
+
],
|
|
1124
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1125
|
+
"status": "unverified"
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
"finding_id": "INJ-I-0003",
|
|
1129
|
+
"category": "sql_injection",
|
|
1130
|
+
"subtype": "string_concatenation",
|
|
1131
|
+
"title": "SQL Injection in member.asp DELETE query",
|
|
1132
|
+
"candidate_id": "I-0003",
|
|
1133
|
+
"location": {
|
|
1134
|
+
"file": "classic-asp/shop/member.asp",
|
|
1135
|
+
"start_line": 10
|
|
1136
|
+
},
|
|
1137
|
+
"evidence": [
|
|
1138
|
+
{
|
|
1139
|
+
"file": "classic-asp/shop/member.asp",
|
|
1140
|
+
"line": 10,
|
|
1141
|
+
"code": "conn.Execute \"DELETE FROM members WHERE member_id = \" & Request.QueryString(\"member_id\")",
|
|
1142
|
+
"why": "User input concatenated into SQL"
|
|
1143
|
+
}
|
|
1144
|
+
],
|
|
1145
|
+
"data_flow": [
|
|
1146
|
+
"Request.QueryString (member_id)",
|
|
1147
|
+
"sql string",
|
|
1148
|
+
"conn.Execute"
|
|
1149
|
+
],
|
|
1150
|
+
"attack_scenario": "A crafted member_id changes the WHERE clause and bypasses the password check.",
|
|
1151
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1152
|
+
"severity": "critical",
|
|
1153
|
+
"confidence": "high",
|
|
1154
|
+
"cwe": [
|
|
1155
|
+
"CWE-89"
|
|
1156
|
+
],
|
|
1157
|
+
"owasp": [
|
|
1158
|
+
"A03:2021"
|
|
1159
|
+
],
|
|
1160
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1161
|
+
"status": "unverified"
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
"finding_id": "INJ-I-0004",
|
|
1165
|
+
"category": "sql_injection",
|
|
1166
|
+
"subtype": "string_concatenation",
|
|
1167
|
+
"title": "SQL Injection in order.asp.vb via string concatenation",
|
|
1168
|
+
"candidate_id": "I-0004",
|
|
1169
|
+
"location": {
|
|
1170
|
+
"file": "classic-asp/shop/order.asp",
|
|
1171
|
+
"start_line": 6
|
|
1172
|
+
},
|
|
1173
|
+
"evidence": [
|
|
1174
|
+
{
|
|
1175
|
+
"file": "classic-asp/shop/order.asp",
|
|
1176
|
+
"line": 6,
|
|
1177
|
+
"why": "Location taken from the Tier 1 inventory"
|
|
1178
|
+
}
|
|
1179
|
+
],
|
|
1180
|
+
"data_flow": [
|
|
1181
|
+
"Request (id)",
|
|
1182
|
+
"sql string",
|
|
1183
|
+
"conn.Execute"
|
|
1184
|
+
],
|
|
1185
|
+
"attack_scenario": "A crafted id changes the WHERE clause and bypasses the password check.",
|
|
1186
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1187
|
+
"severity": "critical",
|
|
1188
|
+
"confidence": "high",
|
|
1189
|
+
"cwe": [
|
|
1190
|
+
"CWE-89"
|
|
1191
|
+
],
|
|
1192
|
+
"owasp": [
|
|
1193
|
+
"A03:2021"
|
|
1194
|
+
],
|
|
1195
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1196
|
+
"status": "unverified"
|
|
1197
|
+
},
|
|
1198
|
+
{
|
|
1199
|
+
"finding_id": "INJ-I-0006",
|
|
1200
|
+
"category": "sql_injection",
|
|
1201
|
+
"subtype": "template_placeholder",
|
|
1202
|
+
"title": "SQL Injection in OrderService.cfc via ColdFusion interpolation",
|
|
1203
|
+
"candidate_id": "I-0006",
|
|
1204
|
+
"location": {
|
|
1205
|
+
"file": "coldfusion/app/OrderService.cfc",
|
|
1206
|
+
"start_line": 5
|
|
1207
|
+
},
|
|
1208
|
+
"evidence": [
|
|
1209
|
+
{
|
|
1210
|
+
"file": "coldfusion/app/OrderService.cfc",
|
|
1211
|
+
"line": 5,
|
|
1212
|
+
"code": "SELECT * FROM orders WHERE id = #arguments.orderId#",
|
|
1213
|
+
"why": "User input interpolated into SQL without cfqueryparam"
|
|
1214
|
+
}
|
|
1215
|
+
],
|
|
1216
|
+
"data_flow": [
|
|
1217
|
+
"arguments.orderId",
|
|
1218
|
+
"sql string",
|
|
1219
|
+
"<cfquery>"
|
|
1220
|
+
],
|
|
1221
|
+
"attack_scenario": "A crafted orderId changes the WHERE clause and bypasses the password check.",
|
|
1222
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1223
|
+
"severity": "critical",
|
|
1224
|
+
"confidence": "high",
|
|
1225
|
+
"cwe": [
|
|
1226
|
+
"CWE-89"
|
|
1227
|
+
],
|
|
1228
|
+
"owasp": [
|
|
1229
|
+
"A03:2021"
|
|
1230
|
+
],
|
|
1231
|
+
"recommendation": "Use cfqueryparam or parameterized queries instead of string interpolation.",
|
|
1232
|
+
"status": "unverified"
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
"finding_id": "INJ-I-0007",
|
|
1236
|
+
"category": "sql_injection",
|
|
1237
|
+
"subtype": "template_placeholder",
|
|
1238
|
+
"title": "SQL Injection in order.cfm via ColdFusion interpolation",
|
|
1239
|
+
"candidate_id": "I-0007",
|
|
1240
|
+
"location": {
|
|
1241
|
+
"file": "coldfusion/app/order.cfm",
|
|
1242
|
+
"start_line": 3
|
|
1243
|
+
},
|
|
1244
|
+
"evidence": [
|
|
1245
|
+
{
|
|
1246
|
+
"file": "coldfusion/app/order.cfm",
|
|
1247
|
+
"line": 3,
|
|
1248
|
+
"code": "SELECT * FROM orders WHERE id = #url.id#",
|
|
1249
|
+
"why": "User input interpolated into SQL without cfqueryparam"
|
|
1250
|
+
}
|
|
1251
|
+
],
|
|
1252
|
+
"data_flow": [
|
|
1253
|
+
"url.id",
|
|
1254
|
+
"sql string",
|
|
1255
|
+
"<cfquery>"
|
|
1256
|
+
],
|
|
1257
|
+
"attack_scenario": "A crafted id changes the WHERE clause and bypasses the password check.",
|
|
1258
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1259
|
+
"severity": "critical",
|
|
1260
|
+
"confidence": "high",
|
|
1261
|
+
"cwe": [
|
|
1262
|
+
"CWE-89"
|
|
1263
|
+
],
|
|
1264
|
+
"owasp": [
|
|
1265
|
+
"A03:2021"
|
|
1266
|
+
],
|
|
1267
|
+
"recommendation": "Use cfqueryparam or parameterized queries instead of string interpolation.",
|
|
1268
|
+
"status": "unverified"
|
|
1269
|
+
},
|
|
1270
|
+
{
|
|
1271
|
+
"finding_id": "INJ-I-0009",
|
|
1272
|
+
"category": "sql_injection",
|
|
1273
|
+
"subtype": "string_concatenation",
|
|
1274
|
+
"title": "SQL Injection in OrderDetail.aspx.cs via string concatenation",
|
|
1275
|
+
"candidate_id": "I-0009",
|
|
1276
|
+
"location": {
|
|
1277
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
1278
|
+
"start_line": 7
|
|
1279
|
+
},
|
|
1280
|
+
"evidence": [
|
|
1281
|
+
{
|
|
1282
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1283
|
+
"line": 10,
|
|
1284
|
+
"code": "string id = Request.QueryString[\"id\"];",
|
|
1285
|
+
"why": "source: QueryString"
|
|
1286
|
+
},
|
|
1287
|
+
{
|
|
1288
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1289
|
+
"line": 13,
|
|
1290
|
+
"code": "var cmd = new SqlCommand(\"SELECT * FROM Orders WHERE OrderId = \" + id, conn);",
|
|
1291
|
+
"why": "concatenated into SQL"
|
|
1292
|
+
},
|
|
1293
|
+
{
|
|
1294
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1295
|
+
"line": 15,
|
|
1296
|
+
"code": "var r = cmd.ExecuteReader();",
|
|
1297
|
+
"why": "sink"
|
|
1298
|
+
}
|
|
1299
|
+
],
|
|
1300
|
+
"data_flow": [
|
|
1301
|
+
"Request.QueryString (id)",
|
|
1302
|
+
"id",
|
|
1303
|
+
"SqlCommand (OrderDetail.aspx.cs:13)",
|
|
1304
|
+
"cmd.ExecuteReader"
|
|
1305
|
+
],
|
|
1306
|
+
"attack_scenario": "A crafted id changes the WHERE clause and bypasses the password check.",
|
|
1307
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1308
|
+
"severity": "critical",
|
|
1309
|
+
"confidence": "high",
|
|
1310
|
+
"cwe": [
|
|
1311
|
+
"CWE-89"
|
|
1312
|
+
],
|
|
1313
|
+
"owasp": [
|
|
1314
|
+
"A03:2021"
|
|
1315
|
+
],
|
|
1316
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1317
|
+
"status": "unverified"
|
|
1318
|
+
},
|
|
1319
|
+
{
|
|
1320
|
+
"finding_id": "INJ-I-0010",
|
|
1321
|
+
"category": "sql_injection",
|
|
1322
|
+
"subtype": "format_string",
|
|
1323
|
+
"title": "SQL Injection in OrderDetail.aspx.cs via string.Format",
|
|
1324
|
+
"candidate_id": "I-0010",
|
|
1325
|
+
"location": {
|
|
1326
|
+
"file": "dotnet-legacy/Web/Orders/EditOrder.aspx.vb",
|
|
1327
|
+
"start_line": 8
|
|
1328
|
+
},
|
|
1329
|
+
"evidence": [
|
|
1330
|
+
{
|
|
1331
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1332
|
+
"line": 19,
|
|
1333
|
+
"code": "string sql2 = string.Format(\"SELECT * FROM Logs WHERE Ref = '{0}'\", Request[\"ref\"]);",
|
|
1334
|
+
"why": "concatenated into SQL"
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1338
|
+
"line": 21,
|
|
1339
|
+
"code": "new SqlCommand(sql2, conn).ExecuteReader();",
|
|
1340
|
+
"why": "sink"
|
|
1341
|
+
}
|
|
1342
|
+
],
|
|
1343
|
+
"data_flow": [
|
|
1344
|
+
"Request (ref)",
|
|
1345
|
+
"sql2",
|
|
1346
|
+
"SqlCommand"
|
|
1347
|
+
],
|
|
1348
|
+
"attack_scenario": "A crafted ref changes the WHERE clause and bypasses the password check.",
|
|
1349
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1350
|
+
"severity": "critical",
|
|
1351
|
+
"confidence": "high",
|
|
1352
|
+
"cwe": [
|
|
1353
|
+
"CWE-89"
|
|
1354
|
+
],
|
|
1355
|
+
"owasp": [
|
|
1356
|
+
"A03:2021"
|
|
1357
|
+
],
|
|
1358
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1359
|
+
"status": "unverified"
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
"finding_id": "INJ-I-0011",
|
|
1363
|
+
"category": "sql_injection",
|
|
1364
|
+
"subtype": "string_interpolation",
|
|
1365
|
+
"title": "SQL Injection in OrderDetail.aspx.cs via string interpolation",
|
|
1366
|
+
"candidate_id": "I-0011",
|
|
1367
|
+
"location": {
|
|
1368
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1369
|
+
"start_line": 13
|
|
1370
|
+
},
|
|
1371
|
+
"evidence": [
|
|
1372
|
+
{
|
|
1373
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1374
|
+
"line": 20,
|
|
1375
|
+
"code": "string sql3 = $\"DELETE FROM Carts WHERE CartId = {Request.Form[\"cart\"]}\";",
|
|
1376
|
+
"why": "concatenated into SQL"
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1380
|
+
"line": 22,
|
|
1381
|
+
"code": "new SqlCommand(sql3, conn).ExecuteNonQuery();",
|
|
1382
|
+
"why": "sink"
|
|
1383
|
+
}
|
|
1384
|
+
],
|
|
1385
|
+
"data_flow": [
|
|
1386
|
+
"Request.Form (cart)",
|
|
1387
|
+
"sql3",
|
|
1388
|
+
"SqlCommand"
|
|
1389
|
+
],
|
|
1390
|
+
"attack_scenario": "A crafted cart changes the WHERE clause and bypasses the password check.",
|
|
1391
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1392
|
+
"severity": "critical",
|
|
1393
|
+
"confidence": "high",
|
|
1394
|
+
"cwe": [
|
|
1395
|
+
"CWE-89"
|
|
1396
|
+
],
|
|
1397
|
+
"owasp": [
|
|
1398
|
+
"A03:2021"
|
|
1399
|
+
],
|
|
1400
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1401
|
+
"status": "unverified"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
"finding_id": "INJ-I-0012",
|
|
1405
|
+
"category": "sql_injection",
|
|
1406
|
+
"subtype": "string_concatenation",
|
|
1407
|
+
"title": "SQL Injection in detail.jsp via string concatenation",
|
|
1408
|
+
"candidate_id": "I-0012",
|
|
1409
|
+
"location": {
|
|
1410
|
+
"file": "dotnet-legacy/Web/Orders/OrderDetail.aspx.cs",
|
|
1411
|
+
"start_line": 19
|
|
1412
|
+
},
|
|
1413
|
+
"evidence": [
|
|
1414
|
+
{
|
|
1415
|
+
"file": "java-legacy/WebContent/order/detail.jsp",
|
|
1416
|
+
"line": 5,
|
|
1417
|
+
"code": "ResultSet rs = c.createStatement().executeQuery(\"SELECT * FROM orders WHERE order_no = '\" + no + \"'\");",
|
|
1418
|
+
"why": "User input concatenated into SQL"
|
|
1419
|
+
}
|
|
1420
|
+
],
|
|
1421
|
+
"data_flow": [
|
|
1422
|
+
"request.getParameter (no)",
|
|
1423
|
+
"sql string",
|
|
1424
|
+
"executeQuery"
|
|
1425
|
+
],
|
|
1426
|
+
"attack_scenario": "A crafted no changes the WHERE clause and bypasses the password check.",
|
|
1427
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1428
|
+
"severity": "critical",
|
|
1429
|
+
"confidence": "high",
|
|
1430
|
+
"cwe": [
|
|
1431
|
+
"CWE-89"
|
|
1432
|
+
],
|
|
1433
|
+
"owasp": [
|
|
1434
|
+
"A03:2021"
|
|
1435
|
+
],
|
|
1436
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1437
|
+
"status": "unverified"
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
"finding_id": "INJ-I-0016",
|
|
1441
|
+
"category": "sql_injection",
|
|
1442
|
+
"subtype": "string_concatenation",
|
|
1443
|
+
"title": "SQL Injection in EditUserAction.java via string concatenation",
|
|
1444
|
+
"candidate_id": "I-0016",
|
|
1445
|
+
"location": {
|
|
1446
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1447
|
+
"start_line": 13
|
|
1448
|
+
},
|
|
1449
|
+
"evidence": [
|
|
1450
|
+
{
|
|
1451
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1452
|
+
"line": 10,
|
|
1453
|
+
"code": "String email = request.getParameter(\"email\");",
|
|
1454
|
+
"why": "source: Request"
|
|
1455
|
+
},
|
|
1456
|
+
{
|
|
1457
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1458
|
+
"line": 13,
|
|
1459
|
+
"code": "PreparedStatement ps = conn.prepareStatement(\"UPDATE users SET email = '\" + email + \"' WHERE id = \" + userId);",
|
|
1460
|
+
"why": "concatenated into SQL"
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
"file": "java-legacy/src/com/acme/struts/EditUserAction.java",
|
|
1464
|
+
"line": 14,
|
|
1465
|
+
"code": "ps.executeUpdate();",
|
|
1466
|
+
"why": "sink"
|
|
1467
|
+
}
|
|
1468
|
+
],
|
|
1469
|
+
"data_flow": [
|
|
1470
|
+
"request.getParameter (email)",
|
|
1471
|
+
"sql string",
|
|
1472
|
+
"prepareStatement"
|
|
1473
|
+
],
|
|
1474
|
+
"attack_scenario": "A crafted email changes the WHERE clause and bypasses the password check.",
|
|
1475
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1476
|
+
"severity": "critical",
|
|
1477
|
+
"confidence": "high",
|
|
1478
|
+
"cwe": [
|
|
1479
|
+
"CWE-89"
|
|
1480
|
+
],
|
|
1481
|
+
"owasp": [
|
|
1482
|
+
"A03:2021"
|
|
1483
|
+
],
|
|
1484
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1485
|
+
"status": "unverified"
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
"finding_id": "INJ-I-0017",
|
|
1489
|
+
"category": "sql_injection",
|
|
1490
|
+
"subtype": "string_concatenation",
|
|
1491
|
+
"title": "HQL Injection in InvoiceController.java via string concatenation",
|
|
1492
|
+
"candidate_id": "I-0017",
|
|
1493
|
+
"location": {
|
|
1494
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
1495
|
+
"start_line": 29
|
|
1496
|
+
},
|
|
1497
|
+
"evidence": [
|
|
1498
|
+
{
|
|
1499
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
1500
|
+
"line": 28,
|
|
1501
|
+
"code": "public String search(@RequestParam(\"customer\") String customer, Model model) {",
|
|
1502
|
+
"why": "source: Request"
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
"file": "java-legacy/src/com/acme/web/InvoiceController.java",
|
|
1506
|
+
"line": 29,
|
|
1507
|
+
"code": "model.addAttribute(\"list\", session.createQuery(\"from Invoice i where i.customer = '\" + customer + \"'\").list());",
|
|
1508
|
+
"why": "concatenated into SQL"
|
|
1509
|
+
}
|
|
1510
|
+
],
|
|
1511
|
+
"data_flow": [
|
|
1512
|
+
"@RequestParam (customer)",
|
|
1513
|
+
"sql string",
|
|
1514
|
+
"session.createQuery"
|
|
1515
|
+
],
|
|
1516
|
+
"attack_scenario": "A crafted customer changes the WHERE clause and bypasses the password check.",
|
|
1517
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1518
|
+
"severity": "critical",
|
|
1519
|
+
"confidence": "high",
|
|
1520
|
+
"cwe": [
|
|
1521
|
+
"CWE-89"
|
|
1522
|
+
],
|
|
1523
|
+
"owasp": [
|
|
1524
|
+
"A03:2021"
|
|
1525
|
+
],
|
|
1526
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1527
|
+
"status": "unverified"
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
"finding_id": "INJ-I-0020",
|
|
1531
|
+
"category": "sql_injection",
|
|
1532
|
+
"subtype": "string_concatenation",
|
|
1533
|
+
"title": "SQL Injection in orders.js via string concatenation",
|
|
1534
|
+
"candidate_id": "I-0020",
|
|
1535
|
+
"location": {
|
|
1536
|
+
"file": "node-express/routes/orders.js",
|
|
1537
|
+
"start_line": 17
|
|
1538
|
+
},
|
|
1539
|
+
"evidence": [
|
|
1540
|
+
{
|
|
1541
|
+
"file": "node-express/routes/orders.js",
|
|
1542
|
+
"line": 17,
|
|
1543
|
+
"code": "db.query(\"SELECT * FROM reports WHERE month = '\" + req.query.month + \"'\", function (e, rows) { res.json(rows); });",
|
|
1544
|
+
"why": "User input concatenated into SQL"
|
|
1545
|
+
}
|
|
1546
|
+
],
|
|
1547
|
+
"data_flow": [
|
|
1548
|
+
"req.query.month",
|
|
1549
|
+
"sql string",
|
|
1550
|
+
"db.query"
|
|
1551
|
+
],
|
|
1552
|
+
"attack_scenario": "A crafted month changes the WHERE clause and bypasses the password check.",
|
|
1553
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1554
|
+
"severity": "critical",
|
|
1555
|
+
"confidence": "high",
|
|
1556
|
+
"cwe": [
|
|
1557
|
+
"CWE-89"
|
|
1558
|
+
],
|
|
1559
|
+
"owasp": [
|
|
1560
|
+
"A03:2021"
|
|
1561
|
+
],
|
|
1562
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1563
|
+
"status": "unverified"
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
"finding_id": "INJ-I-0021",
|
|
1567
|
+
"category": "sql_injection",
|
|
1568
|
+
"subtype": "string_interpolation",
|
|
1569
|
+
"title": "SQL Injection in orders.js via template literal interpolation",
|
|
1570
|
+
"candidate_id": "I-0021",
|
|
1571
|
+
"location": {
|
|
1572
|
+
"file": "node-express/routes/orders.js",
|
|
1573
|
+
"start_line": 29
|
|
1574
|
+
},
|
|
1575
|
+
"evidence": [
|
|
1576
|
+
{
|
|
1577
|
+
"file": "node-express/routes/orders.js",
|
|
1578
|
+
"line": 29,
|
|
1579
|
+
"code": "db.query(`SELECT COUNT(*) AS n FROM orders WHERE shop_id = ${req.query.shop}`, function (e, r) { res.json(r); });",
|
|
1580
|
+
"why": "User input interpolated into SQL"
|
|
1581
|
+
}
|
|
1582
|
+
],
|
|
1583
|
+
"data_flow": [
|
|
1584
|
+
"req.query.shop",
|
|
1585
|
+
"sql string",
|
|
1586
|
+
"db.query"
|
|
1587
|
+
],
|
|
1588
|
+
"attack_scenario": "A crafted shop changes the WHERE clause and bypasses the password check.",
|
|
1589
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1590
|
+
"severity": "critical",
|
|
1591
|
+
"confidence": "high",
|
|
1592
|
+
"cwe": [
|
|
1593
|
+
"CWE-89"
|
|
1594
|
+
],
|
|
1595
|
+
"owasp": [
|
|
1596
|
+
"A03:2021"
|
|
1597
|
+
],
|
|
1598
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1599
|
+
"status": "unverified"
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
"finding_id": "INJ-I-0022",
|
|
1603
|
+
"category": "nosql_injection",
|
|
1604
|
+
"subtype": "operator_injection",
|
|
1605
|
+
"title": "NoSQL Injection in orders.js via direct object injection",
|
|
1606
|
+
"candidate_id": "I-0022",
|
|
1607
|
+
"location": {
|
|
1608
|
+
"file": "node-express/routes/orders.js",
|
|
1609
|
+
"start_line": 21
|
|
1610
|
+
},
|
|
1611
|
+
"evidence": [
|
|
1612
|
+
{
|
|
1613
|
+
"file": "node-express/routes/orders.js",
|
|
1614
|
+
"line": 21,
|
|
1615
|
+
"code": "db.collection('users').findOne(req.body, function (e, u) { res.json(!!u); });",
|
|
1616
|
+
"why": "User input passed directly as filter object"
|
|
1617
|
+
}
|
|
1618
|
+
],
|
|
1619
|
+
"data_flow": [
|
|
1620
|
+
"req.body",
|
|
1621
|
+
"filter object",
|
|
1622
|
+
"findOne"
|
|
1623
|
+
],
|
|
1624
|
+
"attack_scenario": "A crafted req.body injects malicious operators into the query.",
|
|
1625
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1626
|
+
"severity": "critical",
|
|
1627
|
+
"confidence": "high",
|
|
1628
|
+
"cwe": [
|
|
1629
|
+
"CWE-89"
|
|
1630
|
+
],
|
|
1631
|
+
"owasp": [
|
|
1632
|
+
"A03:2021"
|
|
1633
|
+
],
|
|
1634
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1635
|
+
"status": "unverified"
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
"finding_id": "INJ-I-0023",
|
|
1639
|
+
"category": "nosql_injection",
|
|
1640
|
+
"subtype": "string_concatenation",
|
|
1641
|
+
"title": "NoSQL Injection in orders.js via $where string concatenation",
|
|
1642
|
+
"candidate_id": "I-0023",
|
|
1643
|
+
"location": {
|
|
1644
|
+
"file": "node-express/routes/orders.js",
|
|
1645
|
+
"start_line": 25
|
|
1646
|
+
},
|
|
1647
|
+
"evidence": [
|
|
1648
|
+
{
|
|
1649
|
+
"file": "node-express/routes/orders.js",
|
|
1650
|
+
"line": 25,
|
|
1651
|
+
"code": "db.collection('items').find({ $where: \"this.name == '\" + req.query.n + \"'\" }).toArray(function (e, r) { res.json(r); });",
|
|
1652
|
+
"why": "User input concatenated into SQL"
|
|
1653
|
+
}
|
|
1654
|
+
],
|
|
1655
|
+
"data_flow": [
|
|
1656
|
+
"req.query.n",
|
|
1657
|
+
"$where string",
|
|
1658
|
+
"find"
|
|
1659
|
+
],
|
|
1660
|
+
"attack_scenario": "A crafted n changes the WHERE clause and bypasses the password check.",
|
|
1661
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1662
|
+
"severity": "critical",
|
|
1663
|
+
"confidence": "high",
|
|
1664
|
+
"cwe": [
|
|
1665
|
+
"CWE-89"
|
|
1666
|
+
],
|
|
1667
|
+
"owasp": [
|
|
1668
|
+
"A03:2021"
|
|
1669
|
+
],
|
|
1670
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1671
|
+
"status": "unverified"
|
|
1672
|
+
},
|
|
1673
|
+
{
|
|
1674
|
+
"finding_id": "INJ-I-0024",
|
|
1675
|
+
"category": "sql_injection",
|
|
1676
|
+
"subtype": "string_concatenation",
|
|
1677
|
+
"title": "SQL Injection in order.cgi via string concatenation",
|
|
1678
|
+
"candidate_id": "I-0024",
|
|
1679
|
+
"location": {
|
|
1680
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1681
|
+
"start_line": 13
|
|
1682
|
+
},
|
|
1683
|
+
"evidence": [
|
|
1684
|
+
{
|
|
1685
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1686
|
+
"line": 11,
|
|
1687
|
+
"code": "my $id = $q->param('id');",
|
|
1688
|
+
"why": "source: Request"
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1692
|
+
"line": 13,
|
|
1693
|
+
"code": "my $sth = $dbh->prepare(\"SELECT * FROM orders WHERE id = $id\");",
|
|
1694
|
+
"why": "concatenated into SQL"
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1698
|
+
"line": 14,
|
|
1699
|
+
"code": "$sth->execute();",
|
|
1700
|
+
"why": "sink"
|
|
1701
|
+
}
|
|
1702
|
+
],
|
|
1703
|
+
"data_flow": [
|
|
1704
|
+
"$q->param (id)",
|
|
1705
|
+
"$id",
|
|
1706
|
+
"prepare"
|
|
1707
|
+
],
|
|
1708
|
+
"attack_scenario": "A crafted id changes the WHERE clause and bypasses the password check.",
|
|
1709
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1710
|
+
"severity": "critical",
|
|
1711
|
+
"confidence": "high",
|
|
1712
|
+
"cwe": [
|
|
1713
|
+
"CWE-89"
|
|
1714
|
+
],
|
|
1715
|
+
"owasp": [
|
|
1716
|
+
"A03:2021"
|
|
1717
|
+
],
|
|
1718
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1719
|
+
"status": "unverified"
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
"finding_id": "INJ-I-0025",
|
|
1723
|
+
"category": "sql_injection",
|
|
1724
|
+
"subtype": "string_concatenation",
|
|
1725
|
+
"title": "SQL Injection in order.cgi via string concatenation",
|
|
1726
|
+
"candidate_id": "I-0025",
|
|
1727
|
+
"location": {
|
|
1728
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1729
|
+
"start_line": 19
|
|
1730
|
+
},
|
|
1731
|
+
"evidence": [
|
|
1732
|
+
{
|
|
1733
|
+
"file": "perl-cgi/cgi-bin/order.cgi",
|
|
1734
|
+
"line": 19,
|
|
1735
|
+
"code": "$dbh->do(\"DELETE FROM carts WHERE cart_id = \" . $q->param('cart'));",
|
|
1736
|
+
"why": "User input concatenated into SQL"
|
|
1737
|
+
}
|
|
1738
|
+
],
|
|
1739
|
+
"data_flow": [
|
|
1740
|
+
"$q->param (cart)",
|
|
1741
|
+
"sql string",
|
|
1742
|
+
"do"
|
|
1743
|
+
],
|
|
1744
|
+
"attack_scenario": "A crafted cart changes the WHERE clause and bypasses the password check.",
|
|
1745
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1746
|
+
"severity": "critical",
|
|
1747
|
+
"confidence": "high",
|
|
1748
|
+
"cwe": [
|
|
1749
|
+
"CWE-89"
|
|
1750
|
+
],
|
|
1751
|
+
"owasp": [
|
|
1752
|
+
"A03:2021"
|
|
1753
|
+
],
|
|
1754
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1755
|
+
"status": "unverified"
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
"finding_id": "INJ-I-0028",
|
|
1759
|
+
"category": "sql_injection",
|
|
1760
|
+
"subtype": "string_concatenation",
|
|
1761
|
+
"title": "SQL Injection in admin.php via string concatenation",
|
|
1762
|
+
"candidate_id": "I-0028",
|
|
1763
|
+
"location": {
|
|
1764
|
+
"file": "php-plain/admin.php",
|
|
1765
|
+
"start_line": 12
|
|
1766
|
+
},
|
|
1767
|
+
"evidence": [
|
|
1768
|
+
{
|
|
1769
|
+
"file": "php-plain/admin.php",
|
|
1770
|
+
"line": 11,
|
|
1771
|
+
"code": "$id = $_POST['id'];",
|
|
1772
|
+
"why": "source: POST body"
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
"file": "php-plain/admin.php",
|
|
1776
|
+
"line": 12,
|
|
1777
|
+
"code": "mysql_query(\"DELETE FROM users WHERE id = $id\");",
|
|
1778
|
+
"why": "concatenated into SQL"
|
|
1779
|
+
}
|
|
1780
|
+
],
|
|
1781
|
+
"data_flow": [
|
|
1782
|
+
"$_POST['id']",
|
|
1783
|
+
"$id",
|
|
1784
|
+
"mysql_query"
|
|
1785
|
+
],
|
|
1786
|
+
"attack_scenario": "A crafted id changes the WHERE clause and bypasses the password check.",
|
|
1787
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1788
|
+
"severity": "critical",
|
|
1789
|
+
"confidence": "high",
|
|
1790
|
+
"cwe": [
|
|
1791
|
+
"CWE-89"
|
|
1792
|
+
],
|
|
1793
|
+
"owasp": [
|
|
1794
|
+
"A03:2021"
|
|
1795
|
+
],
|
|
1796
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1797
|
+
"status": "unverified"
|
|
1798
|
+
},
|
|
1799
|
+
{
|
|
1800
|
+
"finding_id": "INJ-I-0029",
|
|
1801
|
+
"category": "nosql_injection",
|
|
1802
|
+
"subtype": "operator_injection",
|
|
1803
|
+
"title": "NoSQL Injection in mongo_find.php via direct object injection",
|
|
1804
|
+
"candidate_id": "I-0029",
|
|
1805
|
+
"location": {
|
|
1806
|
+
"file": "php-plain/mongo_find.php",
|
|
1807
|
+
"start_line": 5
|
|
1808
|
+
},
|
|
1809
|
+
"evidence": [
|
|
1810
|
+
{
|
|
1811
|
+
"file": "php-plain/mongo_find.php",
|
|
1812
|
+
"line": 5,
|
|
1813
|
+
"code": "$doc = $coll->findOne(array('login' => $_GET['login'], 'pass' => $_GET['pass']));",
|
|
1814
|
+
"why": "User input passed directly as filter object"
|
|
1815
|
+
}
|
|
1816
|
+
],
|
|
1817
|
+
"data_flow": [
|
|
1818
|
+
"$_GET['login']",
|
|
1819
|
+
"filter object",
|
|
1820
|
+
"findOne"
|
|
1821
|
+
],
|
|
1822
|
+
"attack_scenario": "A crafted login changes the WHERE clause and bypasses the password check.",
|
|
1823
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1824
|
+
"severity": "critical",
|
|
1825
|
+
"confidence": "high",
|
|
1826
|
+
"cwe": [
|
|
1827
|
+
"CWE-89"
|
|
1828
|
+
],
|
|
1829
|
+
"owasp": [
|
|
1830
|
+
"A03:2021"
|
|
1831
|
+
],
|
|
1832
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1833
|
+
"status": "unverified"
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
"finding_id": "INJ-I-0030",
|
|
1837
|
+
"category": "nosql_injection",
|
|
1838
|
+
"subtype": "string_concatenation",
|
|
1839
|
+
"title": "NoSQL Injection in mongo_find.php via $where string concatenation",
|
|
1840
|
+
"candidate_id": "I-0030",
|
|
1841
|
+
"location": {
|
|
1842
|
+
"file": "php-plain/mongo_find.php",
|
|
1843
|
+
"start_line": 6
|
|
1844
|
+
},
|
|
1845
|
+
"evidence": [
|
|
1846
|
+
{
|
|
1847
|
+
"file": "php-plain/mongo_find.php",
|
|
1848
|
+
"line": 6,
|
|
1849
|
+
"code": "$docs = $coll->find(array('$where' => \"this.name == '\" . $_GET['n'] . \"'\"));",
|
|
1850
|
+
"why": "User input concatenated into SQL"
|
|
1851
|
+
}
|
|
1852
|
+
],
|
|
1853
|
+
"data_flow": [
|
|
1854
|
+
"$_GET['n']",
|
|
1855
|
+
"$where string",
|
|
1856
|
+
"find"
|
|
1857
|
+
],
|
|
1858
|
+
"attack_scenario": "A crafted n changes the WHERE clause and bypasses the password check.",
|
|
1859
|
+
"impact": "Authentication bypass; read/modify any table the DB user can access.",
|
|
1860
|
+
"severity": "critical",
|
|
1861
|
+
"confidence": "high",
|
|
1862
|
+
"cwe": [
|
|
1863
|
+
"CWE-89"
|
|
1864
|
+
],
|
|
1865
|
+
"owasp": [
|
|
1866
|
+
"A03:2021"
|
|
1867
|
+
],
|
|
1868
|
+
"recommendation": "Use parameterized queries or prepared statements instead of string concatenation.",
|
|
1869
|
+
"status": "unverified"
|
|
1870
|
+
}
|
|
1871
|
+
]
|
|
1872
|
+
}
|