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>
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>