Files
satellite-provider/_docs/05_security/security_report_cycle5.md
T
Oleksandr Bezdieniezhnykh 61612044fb [AZ-503] [AZ-504] Cycle 5 Steps 11-15 sync
Wrap up cycle 5 verification + documentation:
- Steps 10/11 wrap-up reports (implementation_completeness +
  implementation_report) for the AZ-503-foundation + AZ-504 batch.
- Step 12 test-spec sync: AZ-503-foundation/AZ-504 ACs appended;
  AZ-505 deferred ACs recorded.
- Step 13 update-docs: architecture, data-model, glossary, module-
  layout, uav-tile-upload contract (v1.1.0), DataAccess + Services
  + Tests module docs synced; new common_uuidv5.md module doc.
- Step 14 security audit: PASS_WITH_WARNINGS; 0 new Critical/High;
  2 new Low informational (F1 flightId provenance, F2 pgcrypto
  deploy gap).
- Step 15 performance test: PASS_WITH_INFRA_WARNINGS; PT-08
  passed twice (AZ-504 fix verified); PT-01/02 failed due to
  recurring local Docker/colima DNS cold-start (not an app
  regression). Cycle-3 perf-harness leftover stays OPEN with
  replay #5 documented.
- Autodev state moved to Step 16 (Deploy).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 18:01:27 +03:00

7.8 KiB

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=<uuid>, 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).