mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-22 03:31:14 +00:00
[AZ-794] [AZ-795] [AZ-796] Cycle 7 Steps 12-15 sync (test-spec / docs / security / perf)
Step 12 (Test-Spec Sync): adds BT-27 for the AZ-796 9-rule validation surface and 12 cycle-7 AC rows + Coverage Summary update to traceability-matrix.md. Step 13 (Update Docs): module-layout + module docs for the new SatelliteProvider.Api/Validators namespace + GlobalExceptionHandler + updated TileInventory DTO; tests_unit + tests_integration document the new InventoryRequestValidatorTests (16 unit tests covering all 9 rules) + TileInventoryValidationTests (16 integration tests) + ProblemDetailsAssertions support; glossary entries for Validation Problem Details / FluentValidation / Unmapped Member Handling; system-flows F8 (Tile Inventory Bulk Lookup) expanded with deserializer + validator gates and a 13-row Validation Surface table; data_parameters § Tile Inventory documents the v2 input schema + constraints; ripple_log_cycle7 captures the doc-side ripple decisions. Step 14 (Security Audit): 5-phase audit ran; verdict PASS_WITH_WARNINGS (3 Low findings — D-AZ795-1 FluentValidation 12.0.0 -> 12.1.1 recommended bump, F-AZ795-1 JsonException.Message leak in 400 detail, F-AZ795-2 BadHttpRequestException.Message leak). No Critical / High; auth runs before validation (confirmed in Program.cs); two NuGet additions (FluentValidation 12.0.0 + .DependencyInjectionExtensions 12.0.0) both CVE-clean. Per-phase reports plus consolidated security_report_cycle7.md. Step 15 (Performance Test): docker compose stack used for perf run, scripts/run-performance-tests.sh exited 0 with 8/8 scenarios PASS (second consecutive clean exit-0); added PT-09 cycle-7 smoke probe (v2 z/x/y schema, 2500-tile all-miss batch) measuring min=27ms median=44ms p95=73ms max=86ms (13.7x under AZ-505 AC-4 1000ms budget). PT-07/08 improvements traced to the cycle-6 TLS handshake-overhead identification, not application-side change. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Security Audit Report (Cycle 7)
|
||||
|
||||
**Date**: 2026-05-22
|
||||
**Scope**: Cycle-7 delta over the cycle-5 audit (`_docs/05_security/security_report_cycle5.md`); cycle 6 produced no security report, so cycle 5 is the last full baseline. Cycle-7 surface = AZ-794 (`tileZoom/tileX/tileY` → `z/x/y` rename) + AZ-795 (strict-validation epic: FluentValidation, `UnmappedMemberHandling.Disallow`, GlobalExceptionHandler, error-shape contract) + AZ-796 (inventory-endpoint 9-rule validator).
|
||||
**Trigger**: `/autodev` Step 14 (Security Audit) — feature cycle 7, post-implementation, post-test-spec-sync, post-docs-update.
|
||||
**Verdict (cycle-7 delta)**: **PASS_WITH_WARNINGS** (3 Low findings; no Critical/High/Medium).
|
||||
**Verdict (cumulative)**: **PASS_WITH_WARNINGS** (carries forward 1 cycle-4 Medium dep finding via D2-cy4 + 2 cycle-5 Low informational notes + cycle-7's 3 Lows).
|
||||
|
||||
## Summary
|
||||
|
||||
| Severity | Cycle 5 delta | Cycle 7 delta | Cumulative |
|
||||
|----------|---------------|---------------|------------|
|
||||
| Critical | 0 | 0 | 0 |
|
||||
| High | 0 | 0 | 0 |
|
||||
| Medium | 0 | 0 | 1 (D2-cy4 carry — `Microsoft.NET.Test.Sdk 17.8.0` transitive `NuGet.Frameworks`; test-runtime exposure only) |
|
||||
| Low | 2 informational notes | **3 NEW** (F-AZ795-1, F-AZ795-2, D-AZ795-1) | 5+ |
|
||||
|
||||
## OWASP Top 10:2021 Assessment
|
||||
|
||||
| Category | Status (cycle-7 delta) | Findings |
|
||||
|----------|------------------------|----------|
|
||||
| A01 — Broken Access Control | PASS | — |
|
||||
| A02 — Cryptographic Failures | N/A | No crypto in cycle 7 |
|
||||
| A03 — Injection | PASS | — |
|
||||
| A04 — Insecure Design | PASS (improvement) | AZ-795 / AZ-796 centralise validation behind one filter + one error handler — direct improvement |
|
||||
| A05 — Security Misconfiguration | PASS | `UnmappedMemberHandling.Disallow` is defense-in-depth (mass-assignment prevention) |
|
||||
| A06 — Vulnerable Components | PASS_WITH_WARNINGS | D-AZ795-1 (Low; bump 12.0.0 → 12.1.1 hardening release) |
|
||||
| A07 — Auth Failures | PASS | JWT validation unchanged; new endpoint filter cannot run for anonymous callers |
|
||||
| A08 — Data Integrity Failures | N/A | No CI/CD or artifact-signing surface in cycle 7 |
|
||||
| A09 — Logging Failures | PASS_WITH_WARNINGS | F-AZ795-1 + F-AZ795-2 (Lows; `JsonException.Message` / `BadHttpRequestException.Message` echoed to client) |
|
||||
| A10 — SSRF | N/A | No URL-input fields in cycle 7 |
|
||||
|
||||
## Findings
|
||||
|
||||
| # | Severity | Category | Location | Title |
|
||||
|---|----------|----------|----------|-------|
|
||||
| F-AZ795-1 | Low | Information Disclosure (A09) | `SatelliteProvider.Api/GlobalExceptionHandler.cs:108–117` | `JsonException.Message` propagated to client in 400 response (type-name + parse-position leak) |
|
||||
| F-AZ795-2 | Low | Information Disclosure (A09) | `SatelliteProvider.Api/GlobalExceptionHandler.cs:88–93` | Generic `BadHttpRequestException.Message` propagated as `Detail` for non-JSON 400 paths |
|
||||
| D-AZ795-1 | Low | Vulnerable & Outdated Components (A06) | NuGet | `FluentValidation` + `FluentValidation.DependencyInjectionExtensions` 12.0.0 → 12.1.1 (hardening release; no published CVE) |
|
||||
|
||||
### Finding Details
|
||||
|
||||
**F-AZ795-1: `JsonException.Message` propagated to client in 400 response** (Low / A09 — Information Disclosure)
|
||||
|
||||
- Location: `SatelliteProvider.Api/GlobalExceptionHandler.cs:108–117` (`TryExtractDeserializationErrors`)
|
||||
- Description: `System.Text.Json.JsonException.Message` is echoed in the 400 `ValidationProblemDetails.errors[fieldPath]` array. The default message includes the offending .NET type (`System.Int32`, `System.Guid`, …), the JSON path (already separately captured as the key), and the byte position / line number in the payload — e.g. *"The JSON value could not be converted to System.Int32. Path: $.tiles[0].z | LineNumber: 0 | BytePositionInLine: 27."*.
|
||||
- Impact: Low. The `UseAuthentication` + `UseAuthorization` middleware short-circuits anonymous callers with 401 before any endpoint filter runs, so the leak is only reachable by authenticated callers. The leaked content (type names, parse positions, `System.Text.Json` fingerprint) is already inferable from the OpenAPI spec at `/swagger/v1/swagger.json`; this finding narrows the attack surface for an authenticated tenant operator but does not expose secrets, PII, or pivot vectors.
|
||||
- Remediation: Sanitise the response message to a generic string (e.g. `"Could not deserialize value at this field path."`) while continuing to log the raw `jsonEx.Message` server-side under the request's `correlationId`. Update `error-shape.md` test case `validation-type-mismatch` and the integration tests to assert no `System.*` substring appears in any `errors[]` value.
|
||||
- Status: filed for next cycle.
|
||||
|
||||
**F-AZ795-2: Generic `BadHttpRequestException.Message` propagated as `Detail`** (Low / A09 — Information Disclosure)
|
||||
|
||||
- Location: `SatelliteProvider.Api/GlobalExceptionHandler.cs:88–93` (fallback 400 path when there is no `JsonException` inner exception)
|
||||
- Description: When `BadHttpRequestException` has no `JsonException` inner exception (e.g. framework model-binding failures, unsupported `Content-Type`, oversized request bodies), the framework-provided `Message` is echoed back as `ProblemDetails.Detail`. ASP.NET Core message strings for these paths can include parameter names and (rarely) framework version hints.
|
||||
- Impact: Same severity as F-AZ795-1. Pre-existing-class issue (model-binding messages were always shaped this way under ASP.NET Core); cycle 7 didn't introduce or worsen it.
|
||||
- Remediation: Same as F-AZ795-1 — sanitise the `Detail` to a generic string and log the raw `Message` server-side. Best done in tandem with F-AZ795-1.
|
||||
- Status: filed for next cycle.
|
||||
|
||||
**D-AZ795-1: FluentValidation 12.0.0 → 12.1.1 hardening refresh** (Low / A06 — Vulnerable & Outdated Components)
|
||||
|
||||
- Location: `SatelliteProvider.Api/SatelliteProvider.Api.csproj` (`FluentValidation` + `FluentValidation.DependencyInjectionExtensions`)
|
||||
- Description: 12.0.0 has no known CVEs (verified against GitHub Security Advisories, NVD, ReversingLabs Spectra Assure). 12.1.1 is the latest version (~5 months newer at audit time) and is a hardening release — minor upstream fixes, no security advisories.
|
||||
- Impact: Low. Pure forward-compatibility hardening.
|
||||
- Remediation: Bump both packages to 12.1.1 in a future minor-dependency-roll cycle.
|
||||
- Status: filed for next cycle. Not release-blocking.
|
||||
|
||||
## Dependency Vulnerabilities
|
||||
|
||||
| Package | CVE | Severity | Fix Version | Status |
|
||||
|---------|-----|----------|-------------|--------|
|
||||
| FluentValidation 12.0.0 | — (hardening only) | Low | 12.1.1 | D-AZ795-1 — filed |
|
||||
| FluentValidation.DependencyInjectionExtensions 12.0.0 | — (hardening only) | Low | 12.1.1 | D-AZ795-1 — filed (same item) |
|
||||
| Microsoft.NET.Test.Sdk 17.8.0 (transitive `NuGet.Frameworks`) | — (cycle-4 carry-over D2-cy4) | Medium | TBD (next Test SDK refresh cycle) | carry-over from cycle 4 — owned by a separate unscheduled task |
|
||||
|
||||
## Recommendations
|
||||
|
||||
### Immediate (Critical/High)
|
||||
|
||||
None.
|
||||
|
||||
### Short-term (Medium)
|
||||
|
||||
None new in cycle 7. Cycle-4 carry-over D2-cy4 (`Microsoft.NET.Test.Sdk` Medium) remains in the backlog.
|
||||
|
||||
### Long-term (Low / Hardening)
|
||||
|
||||
1. **Sanitise client-visible 400 messages** (F-AZ795-1 + F-AZ795-2). Single change in `GlobalExceptionHandler.WriteClientErrorAsync` + matching test assertion. Estimated 1 hour of effort. Should be filed as a small follow-up child of AZ-795 (or as a standalone task under the same epic).
|
||||
2. **Bump FluentValidation 12.0.0 → 12.1.1** (D-AZ795-1). Single `.csproj` edit + a regression test pass; no API surface change in 12.0.0 → 12.1.1 per the upstream changelog.
|
||||
|
||||
### Cumulative reminders (carry-overs)
|
||||
|
||||
- Cycle-4 D2-cy4 — `Microsoft.NET.Test.Sdk 17.8.0` transitive `NuGet.Frameworks` Medium-severity finding, test-runtime exposure only. Owned by the next Test SDK refresh.
|
||||
|
||||
## Cycle-7 Architectural Wins
|
||||
|
||||
The audit specifically wants to record three improvements introduced this cycle:
|
||||
|
||||
1. **Mass-assignment prevention by default** — `UnmappedMemberHandling.Disallow` on the global JSON pipeline rejects any unknown root or nested field across every public endpoint. The cycle-7 acceptance criteria explicitly enumerate this for the inventory endpoint; the protection is in force for every other endpoint that consumes a JSON body too.
|
||||
2. **Uniform 4xx contract** — `error-shape.md` v1.0.0 unifies the wire shape across two failure layers (deserializer + FluentValidation). Future child tickets reuse `ValidationEndpointFilter<T>`, `ProblemDetailsAssertions`, and the contract without adding new infrastructure. This dramatically reduces the chance of future endpoints drifting into their own bespoke error shapes.
|
||||
3. **Auth-before-validation invariant verified** — endpoint filters added via `WithValidation<T>()` cannot run for unauthenticated callers (the routing pipeline runs `UseAuthorization` BEFORE the endpoint filter chain). The audit explicitly verified the cycle-7 inventory endpoint and re-asserted the invariant in this report.
|
||||
|
||||
## Verdict
|
||||
|
||||
**PASS_WITH_WARNINGS** — 3 Lows, 0 Mediums (cycle-7 delta), 0 Highs, 0 Criticals. Cycle 7 is **safe to release**. The 3 Lows are filed for follow-up cycles and do not block release.
|
||||
|
||||
Cumulative posture: PASS_WITH_WARNINGS (1 cycle-4 Medium carry-over via D2-cy4 + Lows above). No regression of the cycle-5 PASS posture.
|
||||
Reference in New Issue
Block a user