Set Cache-Control: no-store on authenticated pages #61

Closed
opened 2026-08-07 13:10:55 +02:00 by clawbot · 1 comment
Collaborator

Part of the road to 1.0 (see #33).

SecurityHeaders() (internal/middleware/middleware.go) sets HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy, but no cache directives. Authenticated pages (source list/detail/logs, profile) can therefore be cached by browsers and intermediary proxies, potentially exposing webhook configuration and captured event data.

Definition of done:

  • authenticated responses carry Cache-Control: no-store (and Pragma: no-cache for older intermediaries)
  • static assets served under /s are unaffected (they are safe to cache)
  • a test asserts the header is present on an authenticated page and absent/normal on static assets
Part of the road to 1.0 (see #33). `SecurityHeaders()` (`internal/middleware/middleware.go`) sets HSTS, CSP, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, and `Permissions-Policy`, but no cache directives. Authenticated pages (source list/detail/logs, profile) can therefore be cached by browsers and intermediary proxies, potentially exposing webhook configuration and captured event data. Definition of done: - authenticated responses carry `Cache-Control: no-store` (and `Pragma: no-cache` for older intermediaries) - static assets served under `/s` are unaffected (they are safe to cache) - a test asserts the header is present on an authenticated page and absent/normal on static assets
clawbot added this to the 1.0.0 milestone 2026-08-07 13:10:55 +02:00
Author
Collaborator

Implementation instructions

Confine to internal/middleware/middleware.go (plus its test) and internal/server/routes.go only.

  • Add a NoCache() middleware to middleware.go that sets Cache-Control: no-store and Pragma: no-cache on every response it wraps, following the same constructor style as SecurityHeaders() / MaxBodySize() (returns a func(http.Handler) http.Handler).
  • Wire s.mw.NoCache() onto the dynamic app route groups in routes.go — the /pages, /user/{username}, /sources, and /source/{sourceID} groups (the same groups that already use CSRF()), placed adjacent to the existing CSRF() call for readability.
  • Do NOT apply it to the static file mount (/s), /metrics, /webhook/{uuid}, or /.well-known/healthcheck — those are not authenticated pages and static assets are safe to cache.

Definition of done:

  • authenticated pages (source list/detail/logs, profile, and the login page) carry Cache-Control: no-store
  • the static /s mount is not given no-store
  • a middleware unit test asserts NoCache() sets both headers

Gates and process:

  • make fmt; validate with docker build . (must exit 0; host Go 1.25 vs go.mod 1.26)
  • branch from main named issue-61-no-store; commit subject ends with (closes #61)
  • open a PR (base main) and comment on it with the diff summary and the docker build . result
  • no AI-assistant/tooling references anywhere
## Implementation instructions Confine to `internal/middleware/middleware.go` (plus its test) and `internal/server/routes.go` only. - Add a `NoCache()` middleware to `middleware.go` that sets `Cache-Control: no-store` and `Pragma: no-cache` on every response it wraps, following the same constructor style as `SecurityHeaders()` / `MaxBodySize()` (returns a `func(http.Handler) http.Handler`). - Wire `s.mw.NoCache()` onto the dynamic app route groups in `routes.go` — the `/pages`, `/user/{username}`, `/sources`, and `/source/{sourceID}` groups (the same groups that already use `CSRF()`), placed adjacent to the existing `CSRF()` call for readability. - Do NOT apply it to the static file mount (`/s`), `/metrics`, `/webhook/{uuid}`, or `/.well-known/healthcheck` — those are not authenticated pages and static assets are safe to cache. Definition of done: - authenticated pages (source list/detail/logs, profile, and the login page) carry `Cache-Control: no-store` - the static `/s` mount is not given `no-store` - a middleware unit test asserts `NoCache()` sets both headers Gates and process: - `make fmt`; validate with `docker build .` (must exit 0; host Go 1.25 vs go.mod 1.26) - branch from `main` named `issue-61-no-store`; commit subject ends with ` (closes #61)` - open a PR (base `main`) and comment on it with the diff summary and the `docker build .` result - no AI-assistant/tooling references anywhere
sneak closed this issue 2026-08-07 15:33:45 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/webhooker#61