From 623258dae7a1b27d5b51f776b20012d114b1f4e8 Mon Sep 17 00:00:00 2001 From: MAUROCERON <128849045+MAUROCERON@users.noreply.github.com> Date: Sat, 6 Jun 2026 12:01:07 -0500 Subject: [PATCH] Add DAST multi-user authorization replay gates --- skills/devsecops/dast-config/SKILL.md | 44 ++++++- .../multi-user-authz-session-edge-cases.md | 114 ++++++++++++++++++ 2 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 skills/devsecops/dast-config/tests/multi-user-authz-session-edge-cases.md diff --git a/skills/devsecops/dast-config/SKILL.md b/skills/devsecops/dast-config/SKILL.md index c37d1715..544a7a44 100644 --- a/skills/devsecops/dast-config/SKILL.md +++ b/skills/devsecops/dast-config/SKILL.md @@ -331,6 +331,35 @@ env: --- +#### 4.2 Multi-User Authorization and Session Isolation + +Authenticated scanning with a single generic user does not prove broken access control coverage. DAST authorization testing needs at least two isolated identities per relevant role so the scanner can replay discovered requests across users, roles, tenants, and ownership boundaries without contaminating cookies, CSRF tokens, or bearer tokens. + +**Required evidence:** + +| Evidence | What to verify | Risk if missing | +|---|---|---| +| Role/user matrix | Low-privilege user, peer user, elevated user, tenant B user, and negative-control unauthenticated user where applicable | IDOR/BOLA and role-escalation paths are not exercised | +| Session isolation | Separate cookie jars, bearer tokens, CSRF tokens, device/session IDs, and browser contexts for each identity | requests may pass because the scanner reused a stronger session | +| Authorization replay | Requests captured as one user are replayed as a peer/lower-privilege user with expected 401/403/404 or filtered response | object-level and function-level authorization gaps are missed | +| State reset | Test data seeded per role/tenant and reset after active scans | mutated state can hide findings or create false positives | +| Evidence capture | Baseline response, replay response, user/role, object owner, tenant, expected outcome, and actual outcome are recorded | findings cannot be validated or deduplicated safely | + +**What to verify:** + +- [ ] DAST configuration defines at least two users for each authorization boundary being tested. +- [ ] Each identity has an independent session store; scanner jobs do not share cookies or tokens across users. +- [ ] The scan includes peer-object tests such as `/users/A/orders/1` replayed as user B. +- [ ] Role tests include lower-privilege replay of admin/editor requests. +- [ ] Tenant tests include cross-tenant replay for SaaS or multi-tenant systems. +- [ ] CSRF tokens and anti-automation defenses are refreshed per identity rather than copied from the original user. +- [ ] Expected-deny responses are asserted; HTTP 200 with redacted or filtered data is evaluated against the data returned. +- [ ] Reports distinguish authorization testing coverage from general authenticated crawling coverage. + +**Finding classification:** Single-user authenticated scanning claimed as broken-access-control coverage is **High**. Shared session state across identities is **High**. No cross-user replay evidence for multi-tenant or object-owned APIs is **High**; **Critical** when the app handles regulated data or privileged operations. + +--- + ### Step 5: CI/CD DAST Integration #### 5.1 Pipeline Integration Patterns @@ -518,8 +547,15 @@ DAST tools report findings per-URL, producing hundreds of duplicate alerts for t | Passive scanning in CI | Yes/No | | | Active scanning (staging) | Yes/No | | | API scanning | Yes/No | | +| Multi-user authorization replay | Yes/No | | | Results deduplication | Yes/No | | +### Authorization Replay Evidence + +| Boundary | Source identity | Replay identity | Request/object | Expected result | Actual result | Session isolation evidence | +|----------|----------------|-----------------|----------------|-----------------|---------------|----------------------------| +| Peer object | user-a | user-b | /orders/123 | 403 or filtered | | | + ### Findings #### [F-001] @@ -578,11 +614,13 @@ DAST tools report findings per-URL, producing hundreds of duplicate alerts for t 2. **Skipping authenticated scanning because "it is hard to configure."** Unauthenticated DAST sees the login page and public content -- typically less than 10% of the application surface. The effort to configure authentication pays for itself immediately. Use browser-based authentication for SPAs and header-based for APIs. -3. **Not excluding destructive endpoints from scan scope.** ZAP's spider will follow every link and form action it finds. If a "Delete Account" or "Reset Database" endpoint is in scope, the scanner will exercise it. Explicitly exclude destructive paths in the scan context. +3. **Equating one authenticated user with authorization coverage.** A scan that logs in as a single realistic user can crawl private pages, but it cannot prove object ownership, tenant isolation, or role boundaries. Use separate identities and replay captured requests across roles/users with isolated sessions. + +4. **Not excluding destructive endpoints from scan scope.** ZAP's spider will follow every link and form action it finds. If a "Delete Account" or "Reset Database" endpoint is in scope, the scanner will exercise it. Explicitly exclude destructive paths in the scan context. -4. **Treating DAST findings as ground truth without validation.** DAST tools have significant false positive rates, especially for injection findings. Every high-severity DAST finding must be manually validated before filing a remediation ticket. Build validation into the triage workflow. +5. **Treating DAST findings as ground truth without validation.** DAST tools have significant false positive rates, especially for injection findings. Every high-severity DAST finding must be manually validated before filing a remediation ticket. Build validation into the triage workflow. -5. **Running only scheduled weekly scans instead of integrating into CI.** Weekly scans create a feedback loop measured in days. Passive baseline scans in CI (on every PR) give developers immediate feedback on security header regressions and configuration issues, while weekly full scans provide comprehensive active testing coverage. +6. **Running only scheduled weekly scans instead of integrating into CI.** Weekly scans create a feedback loop measured in days. Passive baseline scans in CI (on every PR) give developers immediate feedback on security header regressions and configuration issues, while weekly full scans provide comprehensive active testing coverage. --- diff --git a/skills/devsecops/dast-config/tests/multi-user-authz-session-edge-cases.md b/skills/devsecops/dast-config/tests/multi-user-authz-session-edge-cases.md new file mode 100644 index 00000000..fb9bc27e --- /dev/null +++ b/skills/devsecops/dast-config/tests/multi-user-authz-session-edge-cases.md @@ -0,0 +1,114 @@ +# Multi-User Authorization and Session Isolation Edge Cases + +These fixtures validate that authenticated DAST coverage is not credited as broken-access-control coverage unless the scan uses isolated identities and replay evidence across users, roles, tenants, and object ownership boundaries. + +## Case 1: Single User Credited as Authorization Coverage + +**Input evidence:** + +```yaml +zap_context: + users: + - name: standard-user + credentials: + username: ${DAST_USER} + password: ${DAST_PASSWORD} + authorization_replay: null + role_matrix: null +report_claims: + authenticated_scanning: true + broken_access_control_coverage: complete +``` + +**Expected result:** + +- Finding: single-user authenticated scan is not sufficient authorization coverage. +- Severity: High. +- Rationale: The scan can crawl private pages but cannot prove peer-object, role, or tenant isolation. + +## Case 2: Shared Session Store Contaminates Replay + +**Input evidence:** + +```yaml +authorization_test: + source_identity: admin-user + replay_identity: standard-user + session_store: shared-cookie-jar + copied_tokens: + - csrf + - session_cookie + request: GET /admin/users/42 + response_status: 200 +``` + +**Expected result:** + +- Finding: shared session state invalidates authorization replay evidence. +- Severity: High. +- Rationale: The replay may succeed because the scanner reused the admin session rather than testing the lower-privilege identity. + +## Case 3: Multi-Tenant API Without Cross-Tenant Replay + +**Input evidence:** + +```yaml +api_scan: + openapi_imported: true + users: + - tenant-a-user + - tenant-a-admin + missing_identities: + - tenant-b-user + tested_paths: + - GET /api/projects/{projectId} + - GET /api/invoices/{invoiceId} +``` + +**Expected result:** + +- Finding: no cross-tenant replay evidence for object-owned API paths. +- Severity: High, or Critical when regulated data is returned. +- Rationale: Same-tenant role checks do not prove tenant isolation. + +## Case 4: Complete Authorization Replay Evidence + +**Input evidence:** + +```yaml +authorization_replay: + role_matrix: + - unauthenticated + - tenant-a-user + - tenant-a-admin + - tenant-b-user + session_isolation: + cookie_jars: separate + bearer_tokens: separate + csrf_tokens: refreshed_per_identity + browser_contexts: separate + tests: + - boundary: peer_object + source_identity: tenant-a-user + replay_identity: tenant-a-peer + request: GET /api/orders/order-owned-by-source + expected: 403 + actual: 403 + - boundary: lower_privilege_role + source_identity: tenant-a-admin + replay_identity: tenant-a-user + request: POST /api/admin/users + expected: 403 + actual: 403 + - boundary: cross_tenant + source_identity: tenant-a-user + replay_identity: tenant-b-user + request: GET /api/invoices/tenant-a-invoice + expected: 404 + actual: 404 +``` + +**Expected result:** + +- No finding for authorization replay coverage. +- Record residual risk only for untested object classes, destructive endpoints excluded from replay, or missing manual business-logic tests.