# OWASP Top 10 Review (Cycle 5)

**Date**: 2026-05-12
**Mode**: Delta scan
**Scope**: Cycle-5 delta over the cycle-3 OWASP review (`_docs/05_security/owasp_review.md`). Reference OWASP Top 10 version: 2021 (current as of this review). The cycle-3 review remains authoritative for categories not touched by AZ-503.

## Per-Category Cycle-5 Assessment

| # | Category | Cycle-3 baseline | Cycle-5 delta posture | New findings |
|---|----------|------------------|------------------------|--------------|
| A01 | Broken Access Control | PASS (JWT + GPS permission on UAV upload; no IDOR; tile reads are coordinate-driven, not id-driven) | PASS — AZ-503 added `metadata.flightId` but did NOT add a new endpoint, did NOT change the existing `RequiresGpsPermission` policy. The optional flight_id is **not** an authorization key; see static_analysis_cycle5.md F1-cy5 for the design-rationale Low informational. | F1-cy5 carried (Low, informational) |
| A02 | Cryptographic Failures | PASS (HS256 JWT ≥ 32-byte secret; ImageSharp's libjpeg path used only for inbound parsing) | PASS — `Uuidv5.cs` uses SHA-1 *as the RFC 9562 §5.5 algorithm*, NOT as a cryptographic primitive. `content_sha256` uses SHA-256 for content integrity. See static_analysis_cycle5.md § Cryptographic Failures for the threat-model walk-through. | none |
| A03 | Injection | PASS (Dapper parameterized SQL throughout; no shell-escaping paths) | PASS — TileRepository UPSERT remains parameterized; migration 014's PL/pgSQL helper consumes only trusted in-database column values; `UavTileUploadHandler.BuildUavTileFilePath` uses integer-typed coords + `Guid.ToString("D")` which cannot carry traversal characters. | none |
| A04 | Insecure Design | PASS (5-rule quality gate, fail-fast on missing JWT secret, JWT iss/aud strict) | PASS_WITH_NOTE — the new `metadata.flightId` is accepted from any GPS-permissioned caller without per-flight ownership verification. This is documented in the v1.1.0 contract as a deliberate design choice; see F1-cy5 in `static_analysis_cycle5.md`. | F1-cy5 carried (Low, informational) |
| A05 | Security Misconfiguration | PASS (no default creds; integration tests' DEV_ONLY JWT values explicitly named; Kestrel limits configured) | PASS — `CREATE EXTENSION IF NOT EXISTS pgcrypto` is a standard PostgreSQL operation. The extension lives in the `public` schema by default; this is acceptable for a single-tenant database. No new misconfiguration surface (no new env vars, no new ports, no new headers). | none |
| A06 | Vulnerable and Outdated Components | PASS_WITH_WARNINGS in cycle 4 (D2-cy4 Medium carry-over: Microsoft.NET.Test.Sdk 17.8.0 transitive) | PASS_WITH_WARNINGS — cycle 5 adds zero new packages; D2-cy4 carry-over is unchanged. `pgcrypto` is a Postgres-bundled extension, not a NuGet package, and the `digest(..., 'sha1')` path AZ-503 uses is unaffected by recent `pgcrypto` CVEs (CVE-2024-10977 / CVE-2025-1094 target `crypt()` and `quote_literal` respectively). | none new |
| A07 | Identification and Authentication Failures | PASS (JWT validated; expiration enforced; ClockSkew 30s; iss + aud strict via AZ-494) | PASS — unchanged. AZ-503 did not modify any auth/identity surface. | none |
| A08 | Software and Data Integrity Failures | PASS (DbUp migrations transactional; AZ-484 contract v1.0.0 frozen) | PASS — migration 014 is transactional (`BEGIN … COMMIT`) with idempotent `IF NOT EXISTS` clauses; the `pg_temp.uuidv5` helper is deterministic so partial-replay does not change `location_hash` values. The integrity invariant ("same `(z, x, y)` always yields the same `location_hash`") is verified byte-for-byte against the C# `Uuidv5Tests` reference vectors. | none |
| A09 | Security Logging and Monitoring Failures | PASS (Serilog file sink; JWT 401/403 emitted by middleware; no token logging) | PASS — `Uuidv5.cs` logs nothing. Migration 014 logs to DbUp's console sink — row counts only, never row content. `content_sha256` and `flight_id` are not written to any log line on the production path. | none |
| A10 | Server-Side Request Forgery (SSRF) | PASS (no user-controlled URL targets) | PASS — AZ-503 introduced no new outbound HTTP call. | none |

## Cumulative Posture (Cycle 1 → Cycle 5)

| Category | Cumulative status |
|----------|-------------------|
| A01 | PASS (1 Low informational accepted: F1-cy5 flight_id provenance) |
| A02 | PASS |
| A03 | PASS |
| A04 | PASS_WITH_NOTE (F1-cy5) |
| A05 | PASS |
| A06 | PASS_WITH_WARNINGS (D2-cy4 carry-over) |
| A07 | PASS |
| A08 | PASS |
| A09 | PASS |
| A10 | PASS |

## Self-verification

- [x] Every OWASP 2021 category assessed for cycle-5 delta
- [x] Carry-over findings explicitly named (D2-cy4, F1-cy5)
- [x] No NEW Critical or High findings in cycle 5

## Save action

Written to `_docs/05_security/owasp_review_cycle5.md`. The cycle-3 `owasp_review.md` remains the cumulative source-of-truth narrative for categories untouched by AZ-503.
