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