Files
satellite-provider/_docs/05_security/security_report.md
T
Oleksandr Bezdieniezhnykh 51b572108a
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-484] Cycle 1 Steps 12-16: docs, security, perf, deploy report
Captures the post-implementation autodev gates for AZ-484 multi-source
tile storage:

- Step 12 (Test-Spec Sync): added 7 AC rows (AZ-484 AC-1..AC-7) and a
  PT-07 NFR row to traceability-matrix.md; added PT-07 scenario to
  performance-tests.md.
- Step 13 (Update Docs): refreshed data_model.md (tiles columns +
  indexes + selection rule + UPSERT contract + migrations 012/013),
  module-layout.md (Common/Enums section with L-001 guidance,
  DataAccess imports-from now lists 6 sites), 6 module / component
  docs to reflect the new repo signatures, source/captured_at fields,
  and Dapper enum bypass workaround. ripple_log_cycle1.md records
  zero out-of-scope ripple.
- Step 14 (Security Audit): PASS_WITH_WARNINGS - 0 Critical, 0 High,
  5 Medium, 5 Low. AZ-484 itself added zero new findings. Hardening
  items (Postgres default creds, .env in build context, GMaps key
  rotation, ASP.NET Core 8.0.21 -> 8.0.25, rate limiter) recorded
  for separate tickets.
- Step 15 (Performance Test): all PT-01..PT-07 scenarios Unverified
  (non-blocking); PT-07 baseline-comparison harness deferred to a
  leftover for next cycle.
- Step 16 (Deploy): cycle deploy report covering migration safety,
  rollback path, post-deploy verification, security caveats.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:03:05 +03:00

9.4 KiB
Raw Blame History

Security Audit Report

Date: 2026-05-11 Scope: Satellite Provider — full repository (Api, Common, DataAccess, Services.*, Tests, infra) Trigger: /autodev Step 14 (Security Audit) — feature cycle 1, post-AZ-484 Verdict: PASS_WITH_WARNINGS

Summary

Severity Count
Critical 0
High 0
Medium 5
Low 5

No Critical or High findings. The verdict is PASS_WITH_WARNINGS driven by 5 Medium findings, all of which are well-understood configuration / hardening gaps rather than exploitable vulnerabilities in the application logic itself. AZ-484 (the cycle's only feature change) introduced zero new findings — it is a pure data-layer change with no auth surface, no untrusted-input handling, and no new external dependencies.

OWASP Top 10:2025 Assessment

Category Status Findings
A01 Broken Access Control N/A (with caveat)
A02 Security Misconfiguration FAIL S1, S2/I6, I1, I2
A03 Software Supply Chain Failures PASS_WITH_WARNINGS D1, D2
A04 Cryptographic Failures N/A
A05 Injection PASS
A06 Insecure Design FAIL S3, S4, I3
A07 Authentication Failures N/A (with caveat)
A08 Software or Data Integrity Failures PASS
A09 Security Logging and Alerting Failures PASS_WITH_WARNINGS I4
A10 Mishandling of Exceptional Conditions PASS

The two N/A (with caveat) entries (A01, A07) reflect the documented architectural choice (architecture.md §7) that this is an internal/trusted-network service. The audit does not endorse that choice — it merely notes that the choice has been made deliberately. If the deployment trust boundary ever changes, A01 and A07 immediately become FAIL and every endpoint becomes an unauthenticated surface; that decision must be re-examined before any internet-facing exposure.

Findings

# Severity Category Location Title
S1 Medium A02 — Misconfiguration SatelliteProvider.Api/appsettings.json:24 Default Postgres password (postgres/postgres) committed in appsettings.json
S2 Medium A02 — Misconfiguration docker-compose.yml:6-7,30 Weak Postgres credentials in compose (mirrors S1)
S3 Low A06 — Insecure Design SatelliteProvider.Api/Program.cs:169,207,237 Latitude/longitude inputs not range-validated at API boundary
S4 Medium A06 — Insecure Design .env (workspace root) Apparent real Google Maps API key on developer filesystem; no .env.example
D1 Medium A03 — Supply Chain SatelliteProvider.Api.csprojMicrosoft.AspNetCore.OpenApi 8.0.21 CVE-2026-26130 SignalR DoS (not reachable in this app — codebase has zero SignalR use)
D2 Low A03 — Supply Chain SatelliteProvider.Tests.csprojMicrosoft.NET.Test.Sdk 17.8.0 CVE-2022-30184 transitive via NuGet.Frameworks <6.2.1 (test-only)
I1 Low A02 — Misconfiguration SatelliteProvider.Api/Dockerfile Container runs as root (no USER directive)
I2 Low A02 — Misconfiguration SatelliteProvider.Api/Program.cs No security headers middleware
I3 Medium A06 — Insecure Design SatelliteProvider.Api/Program.cs No inbound rate limiting on any HTTP endpoint
I4 Low A09 — Logging SatelliteProvider.Api/* (logging strategy) No security-event logs / alerting
I5 Medium A02 — Misconfiguration .dockerignore + Dockerfile:15 (COPY . .) .env not in .dockerignore — risk of API key being baked into image layers

I6 in the infra report is a duplicate of S2 (same root cause) and is not double-counted in the summary.

Finding Details

Full evidence and remediation for every finding lives in the per-phase reports. The detail tables there are the source of truth — this top-level report intentionally avoids restating multi-paragraph remediation steps.

  • Phase 1: _docs/05_security/dependency_scan.md — D1, D2, full dependency inventory + cross-version sanity check
  • Phase 2: _docs/05_security/static_analysis.md — S1, S2, S3, S4, plus the categories that were checked clean (SQL injection, command injection, deserialization, path traversal, log leakage, exception leakage)
  • Phase 3: _docs/05_security/owasp_review.md — OWASP Top 10:2025 per-category assessment + cross-reference table
  • Phase 4: _docs/05_security/infrastructure_review.md — I1, I2, I3, I4, I5, I6, plus the items checked clean (CI secrets handling, image attribution labels)

Dependency Vulnerabilities

Package CVE Severity Reachable? Fix Version
Microsoft.AspNetCore.OpenApi (→ ASP.NET Core 8 runtime) CVE-2026-26130 High (paper) / Low (this app) No — codebase has zero SignalR use 8.0.25
Microsoft.NET.Test.Sdk → NuGet.Frameworks CVE-2022-30184 Medium (paper) / Low (this app) Test project only — never shipped Microsoft.NET.Test.Sdk 17.9.0+

All other dependencies (Newtonsoft.Json 13.0.4, SixLabors.ImageSharp 3.1.11, Npgsql 9.0.2, Dapper 2.1.35, Swashbuckle.AspNetCore 6.6.2, Serilog.AspNetCore 8.0.3, dbup-postgresql 6.0.3, Microsoft.Extensions.* 9.0.10) are at or beyond the patched line for every CVE I could find.

AZ-484 Cycle-Specific Verdict

The reason this audit was triggered (the AZ-484 multi-source tile storage cycle) is independently clean:

  • Migration 013 is transactional and idempotent — no data loss / data integrity finding.
  • TileSourceConverter enforces a closed value space at the language layer; TileEntity.Source is string only as a Dapper-bug workaround documented in _docs/LESSONS.md L-001.
  • TileRepository queries continue to use parameterised Dapper — no new SQL injection surface.
  • No new external dependencies, no new endpoints, no new untrusted-input flows.
  • All findings in this report predate AZ-484 and are unchanged by it.

Recommendations

Immediate (Critical/High)

None — there are no Critical or High findings. The audit does not block the next deploy on its own merit.

Short-term (Medium — pick before next public-network exposure or any post-deploy hardening pass)

  1. S1 + S2 + I5 — De-default DB credentials and stop shipping the .env into the build context. One coordinated change:
    • Remove ConnectionStrings:DefaultConnection from appsettings.json (rely on env-var via the existing throw on null).
    • Add POSTGRES_USER / POSTGRES_PASSWORD to a tracked .env.example and source them from a dev .env; bind 5432 to 127.0.0.1.
    • Append .env and .env.* (with !.env.example exception) to .dockerignore.
  2. S4 — Rotate the Google Maps API key out-of-band, add .env.example, add Google Cloud key restrictions (HTTP referrer or IP allowlist + per-API quotas). The audit deliberately did not echo the key value into any artifact.
  3. D1 — Bump Microsoft.AspNetCore.OpenApi from 8.0.21 to the current 8.0.x patch (≥ 8.0.25) and rebuild the deployed image so the vulnerable SignalR code paths are physically absent.
  4. I3 — Wire Microsoft.AspNetCore.RateLimiting (built into .NET 8 — no new package). Conservative starting threshold in the per-phase report.

Long-term (Low — hardening backlog)

  1. I1 — Add a non-root USER to the API Dockerfile.
  2. I2 — Add a tiny security-headers middleware (or pull NWebsec.AspNetCore.Middleware).
  3. S3 — Add explicit lat/lon range guards at the API boundary (matches the existing SizeMeters 100-10000 pattern).
  4. D2 — Bump Microsoft.NET.Test.Sdk to ≥ 17.9.0 next time the test project's deps are touched.
  5. I4 — Defer until the trust boundary changes; if/when the API moves toward a less-trusted network, add structured 4xx logging per IP + a basic alerting rule.

Verdict Logic

  • No Critical or High findings → not FAIL
  • 5 Medium + 5 Low findings exist → not PASS
  • Therefore: PASS_WITH_WARNINGS

This satisfies the autodev gate to proceed to Step 15 (Performance Test). The recommendations above should be tracked as separate Jira tasks under a hardening epic before the first non-internal deployment.

Self-verification

  • All findings from Phases 14 included
  • No duplicate findings (I6 explicitly noted as a duplicate of S2 and not double-counted)
  • Every finding has remediation guidance (in per-phase reports)
  • Verdict matches severity logic (no Critical/High → not FAIL; >0 findings → not PASS)
  • No real secret values printed in any audit artifact (S4 described without echoing the API key)