## Security findings - **Important — Mapping/check-in writes are not bound to the authenticated browser session.** `/api/v1/action-csrf` requires a valid API session when issuing the token (`scripts/health/health_dashboard_server.py:1646-1654`), but the resulting POST validates only Origin and the one-time CSRF token (`:1212-1216`, `:1239-1253`). Session authentication is enforced only for document review (`:1209-1211`), not nutrition mapping or symptom check-in. The session cookie is also scoped to `/api/v1` (`:1483-1485`), so it cannot accompany `/health-actions/...`. Since session and CSRF lifetimes are independently configurable (`:189-193`, `:219-221`), a CSRF token can remain usable after its issuing session expires. Require continuing principal/session authorization at the write endpoint without weakening Origin or CSRF checks. - **Important — “Idempotency” silently accepts conflicting payloads and ends after queue consumption.** Deduplication uses only `(action, queue_key)` for mappings or `(action, date)` for check-ins (`scripts/health/health_dashboard_server.py:1006-1012`) and returns the existing action ID without comparing payloads (`:1015-1049`). A second mapping decision or changed symptom scores/notes therefore receives `202 queued` while the original payload remains pending. After the worker removes the queue file, the same request creates another action, so this is not request-level retry idempotency. Tests cover only identical payloads while pending (`tests/test_dashboard_v5_sprint6k_a.py:117-145`). Same key plus changed payload should conflict; stable retry identity must survive queue processing. - **Important for HTTPS deployments — Exact-Origin handling remains hard-coded to HTTP, while the new CSRF cookie is never `Secure`.** The shared Origin validator rejects every HTTPS origin (`scripts/health/health_dashboard_server.py:533-557`, especially `:542`), affecting the new fetch submission at `scripts/health/assets/health-assets/dashboard-v5.js:64-73`. Conversely, `/api/v1/action-csrf` sets `health_csrf` without a configurable `Secure` attribute (`scripts/health/health_dashboard_server.py:1661-1669`). Do not solve this by accepting arbitrary schemes or forwarded origins; use one explicitly configured canonical public origin and require `Secure` for HTTPS deployments. - **Low — New JSON responses expose unnecessary internal and demographic metadata.** Successful action responses disclose the private queue filename stem as `action_id` and repeat `queue_key` (`scripts/health/health_dashboard_server.py:1294-1305`), although the frontend ignores the response body. Nutrient responses expose exact derived age and sex in addition to the UI-required reference-group label (`scripts/health/dashboard_v5/nutrition_references.py:372-377`). Minimize these contracts unless consumers demonstrably require the fields. ## Coverage/verification - Reviewed the uncommitted tracked and untracked Sprint 6K-A files, including CSRF/session/origin flow, queue writes, API additions, bundled reference-file reads, and browser/unit tests. - Focused Sprint test: **6 passed**. - A guessed server-test path did not exist; no such suite was run. - **Files modified or created:** none. No new unsafe path traversal, symlink-following, upload, or direct database-write behavior was found in this diff.