Problem
The JSON read endpoints are not authenticated or owner-gated — anyone who knows a site ID can read its traffic:
GET /api/sites/{id}/stats|timeseries|pages|referrers(routes/analytics.ts:545-595) have noauthmiddleware and norequireSiteOwnercheck.- The server-rendered dashboard does gate reads (
resources/views/dashboard.stx:252-279) andrequireSiteOwnerexists (routes/analytics.ts:342-353) — the API just does not use it.
Why it matters (privacy-first)
This is a live data-exposure hole: a site owner’s analytics leak to anyone who can guess/enumerate a site ID. Privacy-first has to include the owner’s data, not only the visitor’s.
Proposed fix
Apply the same auth + requireSiteOwner gate to the four read endpoints, OR require a scoped read token. Preserve the existing ?share=<token> public path for intentionally-shared dashboards.
Priority: P0 — small change, closes an active exposure.
From the 2026-07-20 privacy-first competitive audit (vs. Plausible / Fathom / Simple Analytics / Umami).