The HTTP hardening REPO_POLICIES requires before a 1.0 tag is missing: security headers, trusted proxies for forwarded headers, generic error messages #108

Closed
opened 2026-10-19 22:35:15 +02:00 by clawbot · 1 comment
Collaborator

Where: setupRoutes in internal/server/routes.go (the middleware chain); writeJSONError and the JSON handlers in internal/server/handlers.go.

REPO_POLICIES.md says HTTP services "must be hardened for production internet exposure before tagging 1.0" and lists what that means; #86 is about the 1.0 release candidate. Three items of the list are missing:

  • Security headers: no response carries Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy or Permissions-Policy. The pages use inline style and script blocks, so a CSP needs nonces or hashes, or a documented reason for unsafe-inline.
  • Forwarded headers: chi's middleware.RealIP rewrites RemoteAddr from True-Client-IP, X-Real-IP or the first X-Forwarded-For entry sent by any client; the policy allows them only from configured trusted proxies. Today the request log's remote_addr and the /ip/ self-lookup use an address the client chooses.
  • Error messages: handleASDetailJSON, handlePrefixDetailJSON and handleIPInfo send the database driver's error text in 500 and 404 answers, handleIPInfo sends the resolver's text including the DNS server address, and the health check sends the ping error. The policy wants generic messages, which the HTML pages already use.

Severity: medium (policy items tied to the 1.0 tag; no present failure).

Definition of done

  • Every response carries the six headers; the CSP's handling of inline content is documented in README.
  • Forwarded headers are honoured only from a configured trusted-proxy list (an environment variable, documented in README "Configuration" and "Running under upaas"); otherwise RemoteAddr is the TCP peer.
  • The JSON routes and the health check send fixed messages for anything but database.ErrNoRoute and database.ErrInvalidIP, logging the detail.
  • Tests, failing before the fix: / and /api/v1/stats carry each header; a request with X-Forwarded-For from an untrusted address keeps the TCP peer; a store returning errors.New("disk I/O error") yields a 500 whose body lacks "disk I/O".
  • make check passes.

Model: fable-5-1

Where: `setupRoutes` in `internal/server/routes.go` (the middleware chain); `writeJSONError` and the JSON handlers in `internal/server/handlers.go`. REPO_POLICIES.md says HTTP services "must be hardened for production internet exposure before tagging 1.0" and lists what that means; https://git.eeqj.de/sneak/routewatch/issues/86 is about the 1.0 release candidate. Three items of the list are missing: - Security headers: no response carries `Strict-Transport-Security`, `Content-Security-Policy`, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy` or `Permissions-Policy`. The pages use inline `style` and `script` blocks, so a CSP needs nonces or hashes, or a documented reason for `unsafe-inline`. - Forwarded headers: chi's `middleware.RealIP` rewrites `RemoteAddr` from `True-Client-IP`, `X-Real-IP` or the first `X-Forwarded-For` entry sent by any client; the policy allows them only from configured trusted proxies. Today the request log's `remote_addr` and the `/ip/` self-lookup use an address the client chooses. - Error messages: `handleASDetailJSON`, `handlePrefixDetailJSON` and `handleIPInfo` send the database driver's error text in 500 and 404 answers, `handleIPInfo` sends the resolver's text including the DNS server address, and the health check sends the ping error. The policy wants generic messages, which the HTML pages already use. Severity: medium (policy items tied to the 1.0 tag; no present failure). ## Definition of done - Every response carries the six headers; the CSP's handling of inline content is documented in README. - Forwarded headers are honoured only from a configured trusted-proxy list (an environment variable, documented in README "Configuration" and "Running under upaas"); otherwise `RemoteAddr` is the TCP peer. - The JSON routes and the health check send fixed messages for anything but `database.ErrNoRoute` and `database.ErrInvalidIP`, logging the detail. - Tests, failing before the fix: `/` and `/api/v1/stats` carry each header; a request with `X-Forwarded-For` from an untrusted address keeps the TCP peer; a store returning `errors.New("disk I/O error")` yields a 500 whose body lacks "disk I/O". - `make check` passes. Model: fable-5-1
clawbot self-assigned this 2026-10-19 22:35:15 +02:00
Author
Collaborator

Implemented in #132: every answer carries the six security headers, and the pages' inline blocks are allowed by a nonce made for each answer rather than unsafe-inline. Forwarded addresses are believed only from the proxies listed in TRUSTED_PROXIES, and the JSON routes and the health check send fixed error messages and log the detail.

Model: opus-5-5

Implemented in https://git.eeqj.de/sneak/routewatch/pulls/132: every answer carries the six security headers, and the pages' inline blocks are allowed by a nonce made for each answer rather than `unsafe-inline`. Forwarded addresses are believed only from the proxies listed in `TRUSTED_PROXIES`, and the JSON routes and the health check send fixed error messages and log the detail. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#108