Files
satellite-provider/_docs/05_security/infrastructure_review_cycle8.md
Oleksandr Bezdieniezhnykh ac40a8b352 [AZ-808] [AZ-809] [AZ-810] [AZ-811] [AZ-812] Cycle 8 security audit
PASS_WITH_WARNINGS. Zero Critical / High.

New cycle-8 findings:
- F-AZ809-1 (Medium / A04 Insecure Design): unbounded
  geofences.polygons enables an authenticated DoS on
  POST /api/satellite/route. Cap candidate: 50 or 500.
- F-AZ810-1 (Low / A09): JsonException.Message echoed in
  UavUploadValidationFilter (new instance of cycle-7 F-AZ795-1
  pattern in a second code path).
- F-AZ810-2 (Low / Informational): UavTileMetadata.CapturedAt
  typed DateTime not DateTimeOffset; freshness window drifts in
  non-UTC dev environments. Zero impact in UTC-deployed prod.

Carry-overs (cycle 7): F-AZ795-1, F-AZ795-2, D-AZ795-1 still
open. Cycle 4 D2-cy4 still open (test-runtime Medium).

Cycle-8 architectural wins recorded: per-endpoint validation
reached 100% coverage; three approved validation paths
formalised; OSM wire-format normalisation under strict mode
(AZ-812); UAV-handler defence-in-depth retained.

Highest-priority cycle-9 follow-up: F-AZ809-1 polygon cap.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 15:17:31 +03:00

6.2 KiB

Infrastructure & Configuration Review (Cycle 8)

Date: 2026-05-23 Mode: Delta scan Scope: Cycle-8 changes to deployment configs, CI/CD files, environment templates, and shell scripts only.

Cycle-8 Infrastructure-Layer Diff

Computed via git diff --name-only 865dfdb..b763da3 (cycle-7 tip → cycle-8 tip), filtered to infrastructure-relevant paths:

File Diff summary Security relevance
Dockerfile, Dockerfile.tests, Dockerfile.api (and any image-build file) NOT modified None — cycle 8 did not touch any image build.
docker-compose.yml, docker-compose.tests.yml, docker-compose.prod.yml (and any orchestration file) NOT modified None — cycle 8 did not touch any compose file.
.woodpecker.yml, .github/workflows/** (and any CI/CD pipeline definition) NOT modified None — cycle 8 added no automated pipeline changes.
.env, .env.example, .env.tests (and any environment template) NOT modified None — cycle 8 read no new env vars (every cycle-8 validator and filter is pure code; FluentValidation 12.0.0 has no config knobs).
appsettings.json, appsettings.Development.json, appsettings.tests.json NOT modified None — cycle 8 added no new configuration sections. The pre-existing UavQualityConfig section is unchanged.
scripts/probe_latlon_validation.sh NEW manual probe script for AZ-811 Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓
scripts/probe_region_validation.sh NEW manual probe script for AZ-808 Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓
scripts/probe_route_validation.sh NEW manual probe script for AZ-809 Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓
scripts/probe_upload_validation.sh NEW manual probe script for AZ-810 Reviewed in static_analysis_cycle8.md § Test Code Review § scripts/probe_*_validation.sh. ✓
scripts/run-performance-tests.sh Modified — diff is exclusively the AZ-812 wire-format rename (?Latitude=…&Longitude=…&ZoomLevel=…?lat=…&lon=…&zoom=… across query strings, and {"latitude":…,"longitude":…}{"lat":…,"lon":…} across JSON bodies in PT-01 through PT-08 invocations) No new credentials, no new shell-injection surface. The change is a forced wire-update made necessary by AZ-812's contract rename. ✓
.vscode/launch.json, .vscode/tasks.json, README.md Modified — developer-tooling artifacts Out of scope for security audit (not deployed; do not affect runtime).

Probe Shell Scripts — Common Safety Posture

All four new probe_*_validation.sh scripts follow the same defensive pattern (verified per static_analysis_cycle8.md):

  • #!/usr/bin/env bash with set -euo pipefail at the top — fail-fast on undefined vars, broken pipes, command failures.
  • API_URL="${API_URL:-https://localhost:8080}" default; JWT="${JWT:-}" with an explicit if [[ -z "${JWT}" ]]; then echo "ERROR: set JWT env var to a bearer token. …"; exit 2; fi guard.
  • curl -k used (justified — the dev cert is self-signed; the scripts target localhost in dev/test only — documented in each script's header).
  • Hand-built JSON payloads via shell variable interpolation — values are integer / quoted strings only, no caller-supplied shell strings.
  • No embedded secrets, no hardcoded $JWT, no .env reads.

Identical posture to the cycle-7 probe_inventory_validation.sh. ✓

Container & Image Security — Carried Forward Unchanged

Check Status (carried from cycle 5/6/7) Cycle-8 impact
Non-root container user (Dockerfile USER directive) Already in effect None — no Dockerfile change.
Minimal base image (alpine/distroless/etc.) The API image uses the .NET 10 SDK base — same as cycle 7; image hardening is still owned by a separate, unscheduled follow-up task. None.
No secrets in build args Verified cycle 5; no Dockerfile change in cycle 7 or 8 None.
Health checks Compose healthcheck block on Postgres unchanged None.

CI/CD Security — Carried Forward Unchanged

Check Status Cycle-8 impact
Secrets management (env vars / vault, not pipeline literals) Existing pattern preserved None.
No credentials in pipeline definitions .woodpecker.yml untouched in cycle 8 None.
Artifact signing Existing posture (none — owned by a separate operational improvement track) None.
Dependency-audit step in pipeline Existing posture (manual audit per dependency_scan_cycle*.md; no automated dotnet list package --vulnerable in CI due to the build-hang issue noted in AGENTS.md) None.

Environment & Secrets

  • .env.example — not modified in cycle 8. The cycle-8 code reads no new env vars.
  • appsettings.Development.json — not modified in cycle 8.
  • appsettings.json — production template; unchanged in cycle 8.
  • The cycle-7 host-port change (5432:54325433:5432) is preserved through cycle 8; not relevant to production exposure (production containers run on a private docker network without host-port mapping per the existing deployment model).

Cycle-7 + Earlier Carry-overs

No infrastructure-layer carry-overs from earlier cycles. The cycle-2 UavQualityConfig-derived KestrelServerOptions.Limits.MaxRequestBodySize = 500 MiB (set in Program.cs:41-43) is noted in owasp_review_cycle8.md § A05 as a configuration choice that contributed to the F-AZ809-1 exploit-math worst case, but it is not itself an infrastructure-layer finding — the value is correct for the UAV upload endpoint, and the proper fix is per-endpoint size narrowing (a code change, not an infra change).

Verdict (Phase 4)

PASS — zero new infrastructure-layer findings.

The four new probe scripts are dev/test only, env-driven, fail-fast under set -euo pipefail, and contain no embedded credentials. The single perf-script update is a wire-rename diff with no security impact. Cycle 8 made no Docker, compose, CI, env-template, or appsettings changes.