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:
| Header | Value | Purpose |
|---|---|---|
X-Content-Type-Options | nosniff | Prevents MIME type sniffing. |
X-Frame-Options | DENY | Prevents the page from being embedded in iframes. |
Referrer-Policy | strict-origin-when-cross-origin | Limits referrer information sent with navigations. |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Disables camera, microphone, and geolocation APIs. |
X-XSS-Protection | 0 | Disables the legacy XSS filter (modern browsers use CSP instead). |
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | Enforces 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';| Directive | Production Value | Purpose |
|---|---|---|
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.com | Allow 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-srcandconnect-src. - CDN: Add your CDN domain to
script-src,style-src, andfont-src. - Payment: Add your payment provider's domain to
frame-srcandscript-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.