# OWASP Top 10 Review (Cycle 7)

**Date**: 2026-05-22
**Mode**: Delta scan against OWASP Top 10:2021 (current at time of audit per https://owasp.org/www-project-top-ten/)
**Scope**: Cycle-7 delta only — AZ-794 wire-format rename, AZ-795 strict-validation infrastructure, AZ-796 inventory-endpoint validator. Earlier cycles' OWASP reviews remain authoritative for their respective surfaces; this file does NOT re-walk the full cycle-5 surface.

## A01 — Broken Access Control

**Status**: PASS

- `.RequireAuthorization()` is preserved on every existing endpoint and is chained on the cycle-7 inventory endpoint at `Program.cs:217` ahead of `.WithValidation<TileInventoryRequest>()` on line 218.
- Endpoint-filter execution order is governed by ASP.NET Core's middleware → routing → endpoint-filter pipeline. `UseAuthorization()` (line 201) reads the endpoint metadata produced by `.RequireAuthorization()` and short-circuits anonymous callers with 401 BEFORE the endpoint dispatch reaches any endpoint filter. Cycle-7 verification: `TileInventoryValidationTests` does not include a "no token → 400" case because the framework prevents that path; the suite's `TileInventoryTests.UnauthenticatedRequestReturns401_AC6` already covers it.
- No new CORS policy in cycle 7. `TilesCors` (cycle-6 baseline) is unchanged.
- No new IDOR paths — the inventory endpoint operates on caller-supplied identifiers but does not couple them to any tenant or owner field; tiles are globally-scoped in the post-AZ-484 model.

## A02 — Cryptographic Failures

**Status**: N/A (cycle 7)

- Cycle 7 has no cryptographic operations. JWT validation is unchanged from cycle 4 (HS256 with ≥ 32-byte secret, `ValidateLifetime + ValidateIssuer + ValidateAudience = true`, ClockSkew = 30s).
- The cycle-5 UUIDv5 SHA-1 surface is unaffected.
- TLS posture (Kestrel `Http1AndHttp2` with self-signed dev cert / ingress termination in prod) — unchanged from cycle 6.

## A03 — Injection

**Status**: PASS

- No SQL / Dapper / Npgsql usage in any cycle-7 new file.
- No `Process.Start` / shell-out / `eval` in any cycle-7 new file.
- All inputs reaching the validator are strongly typed (`int`, `Guid`, `IReadOnlyList<TileCoord>`) — System.Text.Json has already parsed and rejected anything malformed before the validator runs.
- The cycle-7 deserializer hardening (`UnmappedMemberHandling.Disallow`) raises the bar for the entire HTTP JSON surface by rejecting mass-assignment / property-injection attempts at parse time.

## A04 — Insecure Design

**Status**: PASS (improvement)

- AZ-795 / AZ-796 are themselves a *design fix* for ad-hoc validation. Pre-cycle-7, endpoints used inline `try/catch` blocks and per-handler defensive logic — easy to miss a path, easy to drift the shape of 4xx bodies. Cycle 7 centralises validation behind one `ValidationEndpointFilter<T>` + one `GlobalExceptionHandler`, both honouring a single contract (`error-shape.md` v1.0.0).
- The architecture doc (`_docs/02_document/architecture.md` § 9) now carries a coverage table that names every public endpoint and its validation status — making future drift visible.

## A05 — Security Misconfiguration

**Status**: PASS

- `UnmappedMemberHandling.Disallow` is a defense-in-depth hardening (mass-assignment prevention).
- `Swagger` exposure is still gated by `app.Environment.IsDevelopment()` (unchanged).
- `appsettings.Development.json` clearly tags DEV-ONLY JWT iss/aud values; `appsettings.json` ships empty so production fail-fast triggers if env vars are missing (unchanged from cycle 4).
- The new `AddProblemDetails()` registration is benign — it only standardises ProblemDetails generation for endpoints that explicitly return them.
- Note: `AddValidatorsFromAssemblyContaining<Program>()` is scoped to `SatelliteProvider.Api.dll` only — it cannot pick up `IValidator<T>` definitions from any other assembly (deliberate; the validators MUST live in the API project where the endpoint contract lives).

## A06 — Vulnerable & Outdated Components

**Status**: PASS_WITH_WARNINGS (Low)

- See `dependency_scan_cycle7.md` for the full table. Summary:
  - FluentValidation 12.0.0 — no known CVEs; latest is 12.1.1 (hardening). Low/Hardening recommendation only.
  - FluentValidation.DependencyInjectionExtensions 12.0.0 — same.
  - All other packages unchanged from cycle 5.

## A07 — Identification and Authentication Failures

**Status**: PASS

- JWT validation parameters unchanged from cycle 4 (`AddSatelliteJwt`).
- No new auth-bypass paths introduced by cycle 7. The new endpoint filter cannot run for anonymous callers (see A01).
- The integration test `TileInventoryValidationTests` mints a valid token via the shared `JwtTokenFactory` — proves the happy path is properly auth-gated and not relying on any test-only bypass.

## A08 — Software and Data Integrity Failures

**Status**: N/A (cycle 7)

- No CI/CD changes, no artifact-signing changes, no auto-update paths touched in cycle 7.

## A09 — Security Logging and Monitoring Failures

**Status**: PASS_WITH_WARNINGS

- `GlobalExceptionHandler` 5xx branch logs `Method`, `Path`, `correlationId`, and the exception object (via Serilog default). This is the appropriate level — enough to debug, with correlationId for cross-referencing.
- The 4xx branch (cycle-7 new logic) does NOT log the exception. This is intentional and correct: malformed request bodies would otherwise create a noisy log signal and could push PII / token content into the log file if attached unwisely. The cost of "no log of the 400" is acceptable because the response itself carries the field path and a deterministic error message, so the client can self-debug.
- The Low information-disclosure findings (F-AZ795-1, F-AZ795-2) from `static_analysis_cycle7.md` belong here as well, but the impact is limited to a Low because the leaked content is type-name metadata, not credentials or PII.

## A10 — Server-Side Request Forgery (SSRF)

**Status**: N/A (cycle 7)

- No URL-input fields, no outbound HTTP calls triggered by the cycle-7 surface. (Pre-existing: `GoogleMapsDownloaderV2` makes outbound calls to Google Maps; not modified by cycle 7.)

## Cross-Reference with `security_approach.md`

The repo does not contain `_docs/00_problem/security_approach.md` (the pre-existing security audit cycles never produced one). The OWASP review proceeds against the cycle-5 + cycle-6 architectural decisions documented in `_docs/02_document/architecture.md` § 7 (Security Architecture) — which cycle-7 input-validation work cleanly extends rather than contradicts.

## Verdict (Phase 3)

**PASS_WITH_WARNINGS** — 1 dependency-hardening Low (D-AZ795-1: 12.0.0 → 12.1.1) + 2 information-disclosure Lows (F-AZ795-1, F-AZ795-2). Zero Critical / High / Medium findings.
