mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-22 18:31:14 +00:00
[AZ-809] F-AZ809-1: cap geofences.polygons at 50 (security audit)
Closes the cycle-8 Medium DoS finding. Without the cap, an authenticated caller could submit millions of bbox polygons in a single 500 MiB request (Kestrel global limit) and saturate the FluentValidation allocator on the validator hot path; each polygon is ~90 bytes of JSON, so the body limit is not a useful gate. Realistic use is 1-10 polygons per route — 50 leaves 5x headroom while bounding the worst-case allocation. Layers: - CreateRouteRequestValidator: MaxPolygons = 50 + Must(...) chained before RuleForEach so the count error fires at "geofences.polygons" (not the leaf path). - Unit: Validate_GeofencePolygonsTooMany_FailsCountRule. - Integration: GeofencePolygonsTooMany_Returns400 (51 valid bbox polygons -> HTTP 400 + errors["geofences.polygons"]). - Contract: route-creation.md -> v1.0.1 patch (tightening an existing range). New Inv-10, new geofence-polygons-too-many test case, changelog row. - Test spec: BT-29 sub-case 9b + AZ-809 AC-1b row in the traceability matrix. - Security report: F-AZ809-1 marked RESOLVED in cycle 8; verdict remains PASS_WITH_WARNINGS (Lows + carry-overs unchanged). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,14 +38,14 @@
|
||||
|
||||
## A04 — Insecure Design
|
||||
|
||||
**Status**: PASS_WITH_WARNINGS (Medium — F-AZ809-1)
|
||||
**Status**: **PASS (post-follow-up)** — was PASS_WITH_WARNINGS at audit time; F-AZ809-1 was the only Medium and was resolved in the Step-14 follow-up commit (cycle 8). Post-follow-up posture is PASS.
|
||||
|
||||
- AZ-808 / AZ-809 / AZ-810 / AZ-811 are themselves a *design fix* for the remaining unprotected endpoints — completing the AZ-795 epic's per-endpoint rollout. Pre-cycle-8, four endpoints (region POST, route POST, lat/lon GET, UAV upload) used ad-hoc inline `try/catch` blocks or no input validation at all. Cycle 8 centralises every public endpoint behind one of three approved validation paths:
|
||||
1. `WithValidation<T>()` for JSON-body endpoints (RegionRequest, CreateRouteRequest).
|
||||
2. `WithValidation<T>()` + `RejectUnknownQueryParamsEndpointFilter` for query-string endpoints (GetTileByLatLonQuery).
|
||||
3. Custom `IEndpointFilter` for non-standard wire formats (`UavUploadValidationFilter` for multipart).
|
||||
- The cycle-7 architecture-doc § 9 coverage table now reaches **100% of public-facing input endpoints** with validators (region POST, route POST, lat/lon GET, inventory POST, UAV upload). Future drift visibility is high.
|
||||
- **However, F-AZ809-1** (from `static_analysis_cycle8.md`) identifies a design-level gap: `CreateRouteRequestValidator` lacks a max-count cap on `Geofences.Polygons`, in contrast to every other list-bearing field across the API (route `Points` ≤ 500, UAV `Items` ≤ 100, inventory `Tiles`/`LocationHashes` ≤ 5000). The pattern across the API is "cap every collection field"; one collection slipped past. The global `KestrelServerOptions.Limits.MaxRequestBodySize = 500 MiB` was sized for the UAV upload endpoint but applies to every route — leaving the validator as the sole gate against a million-element collection submission on the route endpoint. **Filed as Medium**.
|
||||
- **F-AZ809-1** (from `static_analysis_cycle8.md`) identified a design-level gap: `CreateRouteRequestValidator` lacked a max-count cap on `Geofences.Polygons`, in contrast to every other list-bearing field across the API (route `Points` ≤ 500, UAV `Items` ≤ 100, inventory `Tiles`/`LocationHashes` ≤ 5000). **Resolved in the Step-14 follow-up (cycle 8)**: `MaxPolygons = 50` cap added + matching unit + integration tests + `route-creation.md` v1.0.1 Inv-10. The pattern "cap every collection field" is now fully consistent across the API.
|
||||
|
||||
## A05 — Security Misconfiguration
|
||||
|
||||
@@ -106,6 +106,6 @@ The repo does not contain `_docs/00_problem/security_approach.md` (same as cycle
|
||||
|
||||
## Verdict (Phase 3)
|
||||
|
||||
**PASS_WITH_WARNINGS** — A04 (Insecure Design) is `PASS_WITH_WARNINGS` because of F-AZ809-1 (Medium); A06 + A09 are `PASS_WITH_WARNINGS` from the carry-over Lows + the new F-AZ810-1 Low. Every other OWASP category is PASS or N/A.
|
||||
**PASS_WITH_WARNINGS** (post-follow-up) — A04 (Insecure Design) is now **PASS** (F-AZ809-1 resolved in Step-14 follow-up); A06 + A09 remain `PASS_WITH_WARNINGS` from the carry-over Lows + the new F-AZ810-1 Low. Every other OWASP category is PASS or N/A.
|
||||
|
||||
Per the skill's verdict-logic, Medium severity yields PASS_WITH_WARNINGS — not FAIL (FAIL is reserved for Critical or High). The cycle-8 threat model (authenticated callers only on every relevant endpoint) contains the Medium within an auth-gated surface, but F-AZ809-1 must be the highest-priority cycle-9 follow-up because the missing collection cap is the only inconsistency across the API's otherwise-uniform "cap every collection field" pattern, and the global Kestrel body limit (500 MiB) means the validator is the sole gate against an unbounded submission today. If a future feature exposes the route endpoint to an untrusted-tenant audience, this Medium would promote without warning.
|
||||
Per the skill's verdict-logic, Medium severity yields PASS_WITH_WARNINGS — but cycle 8 resolved its only Medium in-cycle via the Step-14 follow-up commit before any production exposure. Post-follow-up posture is cleaner than the audit-time snapshot.
|
||||
|
||||
Reference in New Issue
Block a user