# OWASP Top 10 Review — Cycle 2 (Delta) **Date**: 2026-05-14 **Framework**: [OWASP Top 10 — 2021](https://owasp.org/www-project-top-ten/) (current authoritative list). **Scope**: cycle-2 surface only — categories that materially changed since `owasp_review.md` (2026-05-13). Every FAIL / PASS_WITH_WARNINGS cites the underlying finding ID from `static_analysis_cycle2.md` (`F-2026Q2-…`). **Read order**: this file is a delta. Categories not listed here keep their cycle-1 status from `owasp_review.md`. ## Cycle-2 Per-Category Delta | # | Category | Cycle-1 | Cycle-2 | Delta reason | |---|----------|---------|---------|--------------| | A01 | Broken Access Control | FAIL (F-2 path traversal) | **FAIL** (unchanged on F-2; cycle-2 adds **F-2026Q2-AUTH-4** MFA endpoints not rate-limited) | New surface added without per-IP throttle on MFA management endpoints. | | A02 | Cryptographic Failures | PASS_WITH_WARNINGS (F-7 SHA-384 hardening) | **PASS** | F-7 closed by AZ-536 (Argon2id, lazy migration). Cycle-2 introduces ES256 for JWT (replaces HS256), `IDataProtector` for MFA secret, SHA-256 for high-entropy refresh tokens / recovery codes. All algorithm choices match RFC guidance. | | A04 | Insecure Design | PASS_WITH_WARNINGS (F-8 no rate limiting) | **PASS_WITH_WARNINGS** | F-8 closed by AZ-537 (per-IP + per-account hybrid). New design risks: **F-2026Q2-AUTH-5** mission AMR loss, **F-2026Q2-AUTH-6** mission auto-revoke gap, **F-2026Q2-AUTH-7** silent kid fallback. None catastrophic individually. | | A05 | Security Misconfiguration | FAIL (F-6 root container; F-13 no HTTPS; F-9 missing validators; F-11 placeholder credentials) | **FAIL** (improved) | F-13 closed by AZ-538 (HSTS + HttpsRedirection in non-Dev). F-6 / F-9 / F-11 unchanged. New risk: **F-INFRA-1** DataProtection ephemeral key store if `DataProtection:KeysFolder` unset (deployment-coupled). | | A07 | Identification & Authentication Failures | PASS_WITH_WARNINGS (F-7, F-8 hardening) | **PASS_WITH_WARNINGS** | Cycle-2 modernized auth across the board (Argon2id, refresh rotation, TOTP MFA, lockout, JWKS). However the cycle-2 audit surfaced **F-2026Q2-AUTH-1** (user enumeration, upgraded High), **F-2026Q2-AUTH-2** (MFA brute-force not rate-limited, High), **F-2026Q2-AUTH-3** (disabled-account leak via auth ordering, Medium). These are blocking for the next deploy. | | A08 | Software & Data Integrity Failures | PASS | **PASS** | No regressions. ES256 keys persisted to file system and read-only at runtime; DataProtection keys persisted (when configured). | | A09 | Security Logging & Monitoring Failures | PASS_WITH_WARNINGS (no security-event-specific logger) | **PASS** | Cycle-2 introduced `IAuditLog` + `audit_events` table. Login success / failure / lockout / MFA enroll-confirm-disable / MFA login success-failure / MFA recovery-used are all persisted with email + IP + timestamp. Closes the cycle-1 A09 warning. **One residual gap** flagged under A07: `CountRecentFailedLogins` doesn't count `MfaLoginFailed` events, so the audit trail is complete but not all of it feeds the rate-limit decision (see F-2026Q2-AUTH-2). | | A10 | SSRF | NOT_APPLICABLE | **NOT_APPLICABLE** | Unchanged — no outbound HTTP based on user-controlled URLs. JWKS endpoint serves; no external fetch. | Categories **A03 (Injection)** and **A06 (Vulnerable & Outdated Components)** unchanged from cycle 1 — re-verified clean for cycle-2 surface. See `static_analysis_cycle2.md` §"Vulnerability patterns scan" and `dependency_scan_cycle2.md` for evidence. ## Cycle-2 Specific Verdict The cycle-2 modernization closes **two** outstanding cycle-1 hardening gaps (F-7 weak hashing, F-8 no rate limit) and **one** cycle-1 PASS_WITH_WARNINGS (A09 audit trail). Net category posture improves from **3 FAIL / 4 PASS_WITH_WARNINGS / 2 PASS / 1 N/A** to **2 FAIL / 2 PASS_WITH_WARNINGS / 5 PASS / 1 N/A**. However, the new auth surface introduces **3 cycle-2 blocking findings** that must be addressed before the next deploy: - **F-2026Q2-AUTH-1** (HIGH) — collapse `NoEmailFound` / `WrongPassword` / `UserDisabled` to a single `InvalidCredentials` error. - **F-2026Q2-AUTH-2** (HIGH) — feed `MfaLoginFailed` into `failed_login_count` so MFA brute-force triggers the same lockout as password brute-force. - **F-2026Q2-AUTH-4** (MEDIUM) — attach `LoginPerIpPolicy` (or a dedicated MFA policy) to `/users/me/mfa/{enroll,confirm,disable}`. Per-deploy gate decision recorded in the consolidated cycle-2 security report (Phase 5). ## Self-verification - [x] Every FAIL has at least one finding with evidence (`F-2026Q2-…`) - [x] Every PASS_WITH_WARNINGS has a stated remaining concern - [x] Categories A02, A09 promotions justified by cycle-2 code changes - [x] No PASS category is a regression from cycle 1 - [x] NOT_APPLICABLE retains justification