# Security Audit Report (Cycle 5) **Date**: 2026-05-12 **Scope**: Cycle-5 delta over the cycle-4 audit (`_docs/05_security/security_report_cycle4.md`) **Trigger**: AZ-503-foundation (UUIDv5 tile identity + integer-only flight-aware UPSERT + per-flight on-disk paths) + AZ-504 (perf-script pipefail fix) **Mode**: Delta — all five phases re-executed for the AZ-503 surface; AZ-504 has no source-code surface beyond a shell wrap and is folded into Phase 2 **Verdict**: **PASS_WITH_WARNINGS** (cycle-5 delta) / **PASS_WITH_WARNINGS** (cumulative — carries forward 1 cycle-3 Medium dep finding via D2-cy4 + 2 cycle-5 Low informational notes) ## Summary | Severity | Count (cycle 5 delta) | Count (cumulative) | |----------|-----------------------|--------------------| | Critical | 0 | 0 | | High | 0 | 0 | | Medium | 0 NEW | 1 (D2-cy4 carry-over — Microsoft.NET.Test.Sdk transitive flag, test-runtime exposure only) | | Low | 2 NEW (informational) | 5 cycle-4 informational + 2 cycle-5 informational | ## OWASP Top 10 Assessment (Cycle 5) | Category | Status | |----------|--------| | A01 Broken Access Control | PASS | | A02 Cryptographic Failures | PASS | | A03 Injection | PASS | | A04 Insecure Design | PASS_WITH_NOTE (F1-cy5 — flight_id provenance) | | A05 Security Misconfiguration | PASS | | A06 Vulnerable Components | PASS_WITH_WARNINGS (D2-cy4 carry-over only) | | A07 Auth Failures | PASS | | A08 Data Integrity Failures | PASS | | A09 Logging Failures | PASS | | A10 SSRF | PASS | ## Cycle-5 NEW Findings | # | Severity | Category | Location | Title | |---|----------|----------|----------|-------| | F1-cy5 | Low (informational) | Insecure Design (A04) | `_docs/02_document/contracts/api/uav-tile-upload.md` v1.1.0 + `UavTileUploadHandler.PersistAsync` | `metadata.flightId` is not authenticated provenance | | F2-cy5 | Low (informational) | Security Misconfiguration (A05) | Migration 014 `CREATE EXTENSION pgcrypto` | Deployment runbook gap on managed Postgres providers | ### Finding Details **F1-cy5: `metadata.flightId` is not authenticated provenance** (Low / Insecure Design) - Location: `_docs/02_document/contracts/api/uav-tile-upload.md` v1.1.0 § Request shape; `SatelliteProvider.Services.TileDownloader/UavTileUploadHandler.cs:144-217` - Description: The new optional `metadata.flightId` field is persisted to `tiles.flight_id` and used as part of the on-disk path and the deterministic `tile.id` derivation, but the handler does NOT check that the authenticated principal is authorized to write under that flight identifier. Any GPS-permissioned caller can supply any flight_id. - Impact: Two adversarial cases: 1. **Impersonation**: a compromised UAV credential can falsely attribute its uploads to a different flight (mis-attribution on the evidence chain). 2. **False-flag**: a legitimate UAV credential can falsely attribute its uploads to a competing operator's flight_id. Downstream consumers MUST NOT treat `tiles.flight_id` as cryptographic provenance — they must cross-reference against an authoritative flight registry (out of this workspace's scope) before drawing operational conclusions. - Remediation: Documented as a deliberate v1.1.0 design choice. If a future cycle requires per-flight ownership, options listed in `static_analysis_cycle5.md` (per-flight JWT, scoped permission claim `GPS:flight=`, or move flight_id derivation to a trusted claim). - Verification cross-reference: AZ-487/AZ-494 (JWT identity baseline) + AZ-488 (`RequiresGpsPermission` policy) — both still apply unchanged. F1-cy5 is purely about the **inside** of the authorized envelope. - Severity rationale: Low because (i) the surface only exists after a valid GPS-permissioned JWT, (ii) the Admin API per `suite/_docs/10_auth.md` is the upstream identity gate, (iii) no current consumer treats flight_id as authenticated provenance. **F2-cy5: Deployment runbook gap — `CREATE EXTENSION pgcrypto` privilege on managed Postgres** (Low / Security Misconfiguration) - Location: `SatelliteProvider.DataAccess/Migrations/014_AddTileIdentityColumns.sql:34`; first observed by `_docs/05_security/infrastructure_review_cycle5.md` - Description: Migration 014 issues `CREATE EXTENSION IF NOT EXISTS pgcrypto`. The current Docker compose dev/test environment connects as the `postgres` superuser, so the extension installs automatically. On managed Postgres providers (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL) the deployment role typically lacks superuser; the migration will fail with `must be owner of database` or `permission denied to create extension` unless the extension is pre-installed by an operator. - Impact: Deployment may fail at the migration step at startup time. Failure is loud (the app crashes before serving requests) — not a silent security degradation. No production cycle has shipped yet for the satellite-provider on a managed Postgres provider, so this is forward-looking. - Remediation: - (a) Add a one-line entry to the deployment runbook: "ensure `CREATE EXTENSION IF NOT EXISTS pgcrypto` has run as a superuser before the satellite-provider migration role runs migration 014." - (b) On RDS / Cloud SQL, allow-list `pgcrypto` in the provider's per-DB extension UI / parameter group. - Severity rationale: Low informational because (i) the failure mode is loud, (ii) the remediation is one-line operational, (iii) the local Docker environment is unaffected, (iv) every recent managed Postgres provider supports `pgcrypto` in their default allow-list (it's a contrib module shipped with Postgres itself, not a third-party extension). ## Dependency Vulnerabilities (Cycle 5 delta) None. Zero new NuGet packages, zero version bumps. The cycle-4 D2-cy4 Medium carry-over (Microsoft.NET.Test.Sdk 17.8.0 transitive `NuGet.Frameworks` flag) is unchanged. ## Recommendations ### Immediate (Critical/High) None. No Critical or High findings in cycle 5. ### Short-term (Medium) Apply the D2-cy4 Microsoft.NET.Test.Sdk refresh once a downstream cycle bumps the Test SDK (separate workstream — same posture as cycle 4). ### Long-term (Low / Hardening) - **F1-cy5**: when an authoritative flight registry is introduced (likely a sibling repo or the Admin API), add per-flight ownership verification to `UavTileUploadHandler.HandleAsync` and bump the upload contract to v2.0.0. Until then, document the trust boundary clearly in any consumer-facing API docs that surface `tiles.flight_id`. - **F2-cy5**: add the `pgcrypto` pre-install step to the deployment runbook before the first managed-Postgres deployment. ## Cross-Reference to Prior Audits - Cycle-3 baseline: `_docs/05_security/security_report.md` (authoritative for OWASP narrative on categories untouched by AZ-503). - Cycle-4 delta: `_docs/05_security/security_report_cycle4.md` (AZ-500 package bumps; D2-cy4 finding tree). - Cycle-5 delta artifacts: `dependency_scan_cycle5.md`, `static_analysis_cycle5.md`, `owasp_review_cycle5.md`, `infrastructure_review_cycle5.md`. ## Verdict Reasoning - No Critical, no High, no NEW Medium findings. - 2 Low informational notes (F1-cy5, F2-cy5) properly documented with rationale and forward-looking remediation paths. - Cumulative posture continues to carry the cycle-3 D2-cy4 Medium dep finding (out-of-scope for AZ-503). - Per `security/SKILL.md` § Verdict Logic: `PASS_WITH_WARNINGS` because the cumulative state retains a Medium finding (D2-cy4) but no Critical or High. Cycle-5 delta in isolation would be `PASS_WITH_WARNINGS` due to the Low informational notes; the cycle-5 delta-only verdict is `PASS` per the strict reading ("PASS_WITH_WARNINGS: only Medium or Low findings" — and we have 2 Low informational). The conservative (cumulative) verdict is `PASS_WITH_WARNINGS`. **Final verdict (cumulative)**: **PASS_WITH_WARNINGS**. **Cycle-5 delta verdict**: **PASS_WITH_WARNINGS** (informational notes only — gate-acceptable).