Raypx

Security

Security headers, Content Security Policy, and best practices.

Raypx applies security headers to every response through a middleware defined in src/middleware/security.ts. This middleware runs on all requests and adds protection against common web vulnerabilities.

Security Middleware

The middleware is applied globally in the TanStack Start router configuration:

import { securityMiddleware } from "@/middleware/security"

export const createRouter = () =>
  createRouter({
    routeTree,
    defaultPreload: "intent",
    middleware: [securityMiddleware],
    // ...
  })

Response Headers

The following headers are set on every response:

HeaderValuePurpose
X-Content-Type-OptionsnosniffPrevents MIME type sniffing.
X-Frame-OptionsDENYPrevents the page from being embedded in iframes.
Referrer-Policystrict-origin-when-cross-originLimits referrer information sent with navigations.
Permissions-Policycamera=(), microphone=(), geolocation=()Disables camera, microphone, and geolocation APIs.
X-XSS-Protection0Disables the legacy XSS filter (modern browsers use CSP instead).
Strict-Transport-Securitymax-age=63072000; includeSubDomains; preloadEnforces HTTPS (production only).

Strict-Transport-Security (HSTS) is only set in production. In development, the header is omitted so you can test over HTTP without the browser blocking insecure connections.

Content Security Policy

The Content Security Policy (CSP) is the most important security header. It controls which resources the browser is allowed to load.

Policy Breakdown

default-src 'self';
script-src 'self' {origin};
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https://*.googleusercontent.com;
font-src 'self' data:;
connect-src 'self' {origin};
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
DirectiveProduction ValuePurpose
default-src'self'Fallback for any unspecified directive.
script-src'self' {origin}Only allow scripts from the same origin.
style-src'self' 'unsafe-inline'Allow inline styles (needed by Tailwind CSS).
img-src'self' data: blob: https://*.googleusercontent.comAllow images from same origin, data URIs, blobs, and Google avatar URLs.
font-src'self' data:Allow fonts from same origin and data URIs.
connect-src'self' {origin}Only allow fetch/XHR to the same origin.
frame-ancestors'none'Prevent embedding in iframes (same as X-Frame-Options: DENY).
base-uri'self'Restrict the <base> element to the same origin.
form-action'self'Only allow form submissions to the same origin.

Development Mode

In development, script-src is relaxed to allow inline scripts and eval:

script-src 'self' {origin} 'unsafe-inline' 'unsafe-eval'

This is needed for Vite's HMR (Hot Module Replacement) and React DevTools. The relaxed policy is never used in production.

Recommendations

Customizing CSP for Your Needs

If you integrate third-party services, you may need to extend the CSP:

  • Analytics: Add your analytics domain to script-src and connect-src.
  • CDN: Add your CDN domain to script-src, style-src, and font-src.
  • Payment: Add your payment provider's domain to frame-src and script-src.

Edit the CSP directives in src/middleware/security.ts to add new domains.

Removing 'unsafe-inline' from style-src

The 'unsafe-inline' in style-src is needed because Tailwind CSS generates some styles dynamically. If you want a stricter policy, you can use nonces or hashes for inline styles. However, this requires changes to the build pipeline.

OAuth Provider Domains

Google OAuth loads avatars from *.googleusercontent.com, which is already allowed in img-src. If you add other OAuth providers (e.g., Facebook, Apple), add their avatar domains to the img-src directive.

Reporting

Consider adding a Content-Security-Policy-Report-Only header during rollout to monitor CSP violations without blocking resources:

response.headers.set(
  "Content-Security-Policy-Report-Only",
  csp + "; report-uri /api/csp-report"
)

This lets you collect violation reports and fix issues before enforcing the full policy.

On this page