Skip to Content
Security

Security

Content Security Policy

Configured in next.config.ts:

/embed route

Content-Security-Policy: frame-ancestors 'self' https://bttpirineus.org https://www.bttpirineus.org

Only allows the embed to be loaded in iframes from the BTT Pirineus WordPress site and the app itself.

All other routes

X-Frame-Options: DENY

Prevents any other page from being embedded in an iframe.

GPX proxy validation

The /api/gpx proxy only allows GPX files from trusted hosts:

const ALLOWED_HOSTS = ["www.bttpirineus.org", "bttpirineus.org"];

Requests for any other hostname return 403. Relative URLs are resolved against https://www.bttpirineus.org.

PostHog reverse proxy

PostHog events are sent through /ingest/* rewrites to https://eu.i.posthog.com/*. This:

  • Avoids ad-blocker interference (events go to your own domain)
  • Avoids CORS issues
  • Keeps PostHog API keys client-side only (public project key, not secret)

Analytics password

The /analytics dashboard and /api/analytics/dashboard endpoint require a password matching the ANALYTICS_PASSWORD environment variable. The password is:

  • Stored in sessionStorage (lost on browser close)
  • Sent as a query parameter (acceptable since the dashboard is internal-only and served over HTTPS)

Internal user filtering

Internal/admin IPs are detected via /api/analytics/ip-check:

  • Reads x-forwarded-for header
  • Checks against a hardcoded IP allowlist
  • If internal, PostHog registers is_internal: true on the person
  • Dashboard queries exclude is_internal = true events

Cross-origin iframe safety

When embedded in bttpirineus.org:

  • localStorage/cookies may be blocked by the browser — PostHog falls back to persistence: "memory"
  • sessionStorage still works for view deduplication within the iframe session
  • The allow="clipboard-write" attribute on iframes enables the share copy-link feature