Files
ui/_docs/05_security/security_report.md
T
Oleksandr Bezdieniezhnykh 09449bda2c
ci/woodpecker/push/build-arm Pipeline failed
[AZ-510][AZ-511][AZ-512][AZ-513] Cycle 3 Steps 12-15 + admin prereq
Wrap up cycle 3 across the autodev existing-code Phase B steps that
follow Implement (Steps 12-15), plus the cross-workspace prerequisite
ticket filed for AZ-512.

Step 12 - Test-Spec Sync:
- Un-quarantine FT-P-01 in traceability-matrix (closed by AZ-510)
- Add AZ-510 chained /users/me failure-path test reference under AC-23
- Note AZ-512 deferral status under O9 (P12 Phase B target)

Step 13 - Update Docs (task mode):
- Refresh src__auth__AuthContext module doc with AZ-510 wire shape
  (POST refresh + chained /users/me + bootstrapInflight guard)
- Add usersMe() to src__api__endpoints module doc + consumer note
- Rename src__features__annotations__classColors module doc to
  src__class-colors__classColors (matches AZ-511 git mv); refresh header
- Refresh src__components__DetectionClasses + src__features__annotations
  module group doc for the new class-colors barrel import path
- Update components/11_class-colors Module Inventory to point at the
  renamed module doc filename
- Rewrite system-flows.md Flow F2 (Bearer auto-refresh) with the AZ-510
  POST + chained /users/me sequence; close Finding B3 references
- Generate ripple_log_cycle3 documenting all changed source files,
  their reverse-dependency search results, and the docs touched

Step 14 - Security Audit (cycle-3 delta):
- Resume mode against cycle-2 baseline; cycle-2 artifacts untouched
- Re-run bun audit on both roots: clean (cycle-2 inline fix held)
- Re-rate OWASP A06: FAIL -> PASS; A07: PASS_WITH_KNOWN -> PASS (B3
  closed by AZ-510)
- New finding F-SAST-CY3-1 (LOW): __resetBootstrapInflightForTests
  exposed via src/auth public barrel; defer to hygiene cycle
- Verdict: FAIL -> PASS_WITH_WARNINGS; one HIGH (F-SAST-1
  mission-planner git-history key, unchanged) remains
- Add amendment banner to cycle-2 security_report.md

Step 15 - Performance Test:
- Static profile NFT-PERF-01 PASS (290 575 B gzipped vs 2 MB budget;
  ~14% of budget; no regression from AZ-510 surface additions)
- E2E profile SKIP (Playwright perf project still pending AZ-457..AZ-482);
  legitimate skip per test-run skill, gap acknowledged in report
- AZ-510 200ms p95 chain NFR verified at spec level only - no CI gate
  yet (covered by future AZ-457..AZ-482 work)

Cross-workspace prerequisite (AZ-513 just filed):
- Updated _docs/_process_leftovers/2026-05-13_az-512-admin-classes-prereq.md
  to reflect AZ-513 filing on admin/ workspace (parent epic AZ-509,
  Blocks link to AZ-512). Companion task spec added in admin/ repo
  (separate commit there, owned by admin/ workspace).

State file: advanced to Step 16 (Deploy) per autodev existing-code flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 03:58:21 +03:00

12 KiB
Raw Blame History

Security Audit Report — Azaion UI

AMENDMENT 2026-05-13 — verdict superseded by cycle-3 delta report. See _docs/05_security/security_report_cycle3_delta.md. Current verdict (post AZ-510 + cycle-2-tail bun update vite): PASS_WITH_WARNINGS (was FAIL). All HIGH-severity dependency advisories closed; OWASP A06 → PASS, A07 → PASS. The HIGH-severity F-SAST-1 (mission-planner/ Google Geocode API key in git history) remains open but does not affect the production browser bundle. The cycle-2 evidence below is preserved verbatim as the audit history of record.

Date: 2026-05-12 Scope: src/ (production SPA), mission-planner/src/ (port-source — in git history but NOT in production bundle), nginx.conf, Dockerfile, .woodpecker/build-arm.yml, e2e/ harness, .env.example files Cycle: Phase B / Cycle 2 (post AZ-498, AZ-499) Verdict: FAIL — 1 HIGH-severity secret leak in port-source (F-SAST-1 Google Geocode API key) plus 1 HIGH-severity dependency advisory (F-DEP-1 vite — dev-server only, no prod exposure)


Summary

Severity Count Notes
Critical 0
High 2 F-SAST-1 (production-bundle exposure: NONE today; git-history exposure: HIGH); F-DEP-1 (production exposure: NONE; dev-server: HIGH)
Medium 7 F-SAST-2, F-SAST-3, F-DEP-2, F-DEP-3, F-INF-1, F-INF-2, F-INF-3, F-INF-4
Low 2 F-SAST-4, F-INF-5

Production browser bundle is clean — no exploitable findings. All HIGH-severity items are concentrated in (a) port-source code that does not ship and (b) dev-time tooling (Vite dev server). The audit's FAIL verdict reflects:

  1. The port-source key is a real secret in real git history → must be revoked + externalized following the AZ-499 pattern.
  2. CI does not run bun audit, so the High Vite advisory shipped through Cycle 2 unflagged → procedural gap to close.

OWASP Top 10 (2021) Assessment

# Category Status Findings
A01 Broken Access Control PASS_WITH_KNOWN 1 known UX gap (/admin route, F2/AC-22 — pre-existing)
A02 Cryptographic Failures PASS_WITH_KNOWN 1 accepted trade-off (SSE bearer-in-query, ADR-008)
A03 Injection PASS
A04 Insecure Design PASS
A05 Security Misconfiguration FAIL F-INF-2 (nginx headers + log redaction missing)
A06 Vulnerable & Outdated Components FAIL F-DEP-1, F-DEP-2, F-DEP-3
A07 Identification & Authentication Failures PASS_WITH_KNOWN 1 known cold-load refresh bug (F2 — pre-existing)
A08 Software & Data Integrity Failures FAIL F-INF-1, F-INF-3, F-INF-4
A09 Security Logging & Monitoring Failures N/A Server-side concern (operator-internal SPA)
A10 Server-Side Request Forgery N/A Browser SPA has no server-side request surface

Findings (severity-ranked)

# Severity Category Location Title
F-SAST-1 HIGH Secrets in code mission-planner/src/config.ts:2 Hardcoded Google Geocode API key in port-source
F-DEP-1 HIGH Vulnerable component vite@6.4.1 (both roots) Vite Arbitrary File Read via Dev Server WebSocket (GHSA-p9ff-h696-f583) — dev-server only
F-INF-1 MEDIUM CI/CD .woodpecker/build-arm.yml bun audit not gated in CI pipeline
F-INF-2 MEDIUM Misconfiguration nginx.conf Missing CSP, X-Frame-Options, HSTS, Referrer-Policy, X-Content-Type-Options, log-redaction
F-INF-3 MEDIUM Supply chain .woodpecker/build-arm.yml No image vulnerability scan (Trivy/Grype)
F-INF-4 MEDIUM Supply chain .woodpecker/build-arm.yml No SBOM emission, no image signing (cosign)
F-DEP-2 MEDIUM Vulnerable component vite@6.4.1 Vite Path Traversal in Optimized Deps .map (GHSA-4w7w-66w2-5vf9) — dev-server only
F-DEP-3 MEDIUM Vulnerable component postcss@8.5.8 (transitive) PostCSS XSS via Unescaped </style> (GHSA-qx2v-qp2m-jg93) — low surface
F-SAST-2 MEDIUM Supply chain mission-planner/src/icons/PointIcons.tsx:7 unpkg.com CDN reference in port-source
F-SAST-3 MEDIUM Coverage gap scripts/run-tests.sh (STC-SEC2) No-CDN gate does not scan mission-planner/
F-SAST-4 LOW Future risk mission-planner/src/constants/tileUrls.ts:2-3 Port-source still uses third-party tile fallbacks
F-INF-5 LOW Container hardening Dockerfile nginx runs as root master process; no HEALTHCHECK directive

Finding Details

F-SAST-1 — Hardcoded Google Geocode API key — HIGH

  • Location: mission-planner/src/config.ts:2
  • Value: AIzaSyAhvDeYukuyWVrQYbRhuv91bsi_jj5_Iys
  • Description: The Google Geocode API key is committed in mission-planner/ (port-source). Used by mission-planner/src/flightPlanning/LeftBoard.tsx:114 for address-to-coords lookups.
  • Production-bundle exposure: NONE today. src/ does not import from mission-planner/; Dockerfile builds only src/-rooted Vite. The key is NOT in dist/.
  • Git-history exposure: HIGH. Anyone with repo read access can extract the key. Same threat class as the OWM key resolved by AZ-499.
  • Impact: Quota theft, billing-account abuse, accelerated risk if mission-planner/ is later ported into the SPA without remediation.
  • Remediation (mirror AZ-499 / AC-42 pattern):
    1. Revoke the key at https://console.cloud.google.com/google/maps-apis/credentials (manual, OUT-OF-BAND, USER ACTION). Capture evidence.
    2. Externalize: import.meta.env.VITE_GOOGLE_GEOCODE_KEY in mission-planner/src/config.ts with fail-soft if unset.
    3. Update mission-planner/.env.example with placeholder.
    4. Extend tests/security/banned-deps.json owm_key_in_source (or add a sibling google_key_in_source) section to also block the literal Google key.
    5. Long-term: route geocoding via suite-side proxy when the SPA needs it.
  • See: static_analysis.md F-SAST-1.

F-DEP-1 — Vite Arbitrary File Read via Dev Server WebSocket — HIGH

  • Location: vite@6.4.1 (resolved in bun.lock, both ui/ and mission-planner/ roots)
  • Advisory: GHSA-p9ff-h696-f583
  • Description: WebSocket endpoint exposed by vite dev allows arbitrary local-file read via path traversal.
  • Production-bundle exposure: NONE. The Vite dev server is never present in production (Dockerfile final stage is nginx:alpine serving static dist/).
  • Developer-machine exposure: HIGH if bun run dev --host is ever used (binding to 0.0.0.0); MODERATE for the default localhost binding (still a browser-side script attack vector via DNS rebinding).
  • Remediation: bun update vite in both roots → vite >= 6.4.2. Verify build + fast tests still pass.
  • See: dependency_scan.md F-DEP-1.

(Full detail for F-INF-1 .. F-INF-5 in infrastructure_review.md; for F-DEP-2/F-DEP-3 in dependency_scan.md; for F-SAST-2/F-SAST-3/F-SAST-4 in static_analysis.md. Not duplicated here.)


Dependency Vulnerabilities

Package GHSA / Advisory Severity Installed Fix
vite GHSA-p9ff-h696-f583 HIGH 6.4.1 >= 6.4.2 (bun update vite)
vite GHSA-4w7w-66w2-5vf9 MODERATE 6.4.1 >= 6.4.2 (same upgrade)
postcss GHSA-qx2v-qp2m-jg93 MODERATE 8.5.8 >= 8.5.10 (transitive — flows through Vite upgrade)

A single bun update vite in each root fixes all three.


Recommendations

Immediate (HIGH — block deploys until done)

  • F-SAST-1 (USER ACTION + CODE): Revoke the Google Geocode API key at the Google Cloud Console, then externalize per AZ-499 pattern. Mirror the manual evidence-capture protocol used for AZ-499 AC-7. Recommended ticket: AZ-NEW — Externalize Google Geocode key in mission-planner port-source (3 SP — same shape as AZ-499 minus AC-8 misattribution).
  • F-DEP-1 / F-DEP-2 / F-DEP-3 (CODE): bun update vite in ui/ and mission-planner/. Re-run bun audit to confirm zero findings. Recommended ticket: AZ-NEW — Update Vite to fix CVE-2026 advisories (1 SP).

Short-term (MEDIUM — Phase B)

  • F-INF-1: Add bun audit --severity high step to .woodpecker/build-arm.yml so future advisory regressions fail CI (1 SP).
  • F-INF-2: Add CSP, X-Frame-Options, Referrer-Policy, X-Content-Type-Options + bearer-redaction log format to nginx.conf (2 SP). Coordinate HSTS decision with suite ingress.
  • F-INF-3: Add Trivy image-scan step to .woodpecker/build-arm.yml after docker build (2 SP).
  • F-SAST-2: Bundle Leaflet marker icon locally instead of unpkg.com CDN reference (covered by the same port-source cleanup as F-SAST-1).
  • F-SAST-3: Widen no-CDN static gate to scan mission-planner/ — move pattern into tests/security/banned-deps.json and use the existing check-banned-deps.mjs widening (2 SP).

Long-term (Suite-wide / Hardening)

  • F-INF-4: SBOM (Syft/cyclonedx) + cosign image signing — coordinate registry capability with suite team (3-5 SP).
  • F-SAST-4: Mission-planner port-source modernization will resolve the third-party tile fallbacks naturally — no separate ticket needed.
  • F-INF-5: nginxinc/nginx-unprivileged migration + HEALTHCHECK directive (1 SP, low priority).

Pre-existing (not introduced by this audit; tracked elsewhere)

  • F2 / AC-01 — bootstrap refresh missing credentials:'include' (src/auth/AuthContext.tsx:24). Quarantined-test acknowledged. Phase B fix.
  • AC-22 — /admin route lacks client-side role-gate. Server-authoritative, no exploit. Phase B UX fix.
  • ADR-008 — SSE bearer-in-query-string. Accepted trade-off; mitigation lives in F-INF-2 (nginx log redaction).
  • AZ-499 AC-7 — OWM key revocation manual deliverable. Pending USER action.

Cycle 2 — security regression check

No security regressions introduced by AZ-498 or AZ-499. Both changes pass static + fast test suites; the cookie-credentialed tile fetch is correctly scoped to SameSite=Strict and same-origin; the OWM env hardening closes the previously quarantined NFT-SEC-09 source check.

STC-SEC1C is now part of the static gate and would catch any future re-introduction of the literal OWM key in either src/ or mission-planner/.


Verdict justification

The verdict is FAIL because:

  1. F-SAST-1 is a real third-party API key in real git history. The same finding class as AZ-499 — same remediation pattern, same urgency, same need for out-of-band revocation.
  2. F-DEP-1 is a HIGH advisory against a current direct dependency. Even with no production exposure, OWASP A06 categorically fails on any actionable HIGH advisory.

Both findings have one-line remediations. Once F-SAST-1 is revoked + externalized and F-DEP-1 is upgraded, a follow-up audit cycle should re-rate the verdict to PASS_WITH_WARNINGS pending the MEDIUM infrastructure tickets.

The production browser bundle itself is not vulnerable — the SPA is well-architected (server-authoritative auth, bearer-in-memory + HttpOnly cookie, no eval/injection surface, no client-side persistence). The deficiencies are at the supply-chain, infrastructure, and port-source layers.

Self-verification

  • All findings from Phases 14 included
  • No duplicate findings (cross-references used instead)
  • Every finding has remediation guidance
  • Verdict matches severity logic (FAIL on any HIGH)
  • Production-vs-dev impact distinguished for each HIGH finding
  • Cycle 2 deltas (AZ-498, AZ-499) explicitly reviewed for regressions