Insecure Headers on Railway
Railway provides HTTPS and automatic TLS certificate management, but application-level security headers must be set by the application itself. Most Railway deployments serve responses without Content-Security-Policy, X-Frame-Options, or Strict-Transport-Security.
Scan Your Railway AppHow It Happens
Railway deploys Docker containers or buildpack-detected applications behind a reverse proxy that handles TLS termination. The proxy provides HTTPS but does not inject security headers into application responses. This means every header must be set by the application code. Railway's streamlined deployment experience encourages speed. Developers push code, Railway detects the framework, builds the container, and deploys it. At no point in this pipeline are security headers configured. The default Express, Flask, FastAPI, or Next.js server does not set security headers either. Railway does not have a platform-level headers configuration (like Vercel's vercel.json or Netlify's _headers file). The only way to add headers is in the application code itself, which means developers must modify their server configuration rather than a deployment config file.
Impact
Without Content-Security-Policy, XSS vulnerabilities in Railway-hosted applications are fully exploitable. CSP is the primary defense-in-depth mechanism against script injection, and its absence means any XSS vector can load external scripts, exfiltrate data, and modify page content without restriction. Missing X-Frame-Options on Railway-hosted applications allows embedding in iframes for clickjacking attacks. This is especially dangerous for SaaS applications, dashboards, and admin panels frequently deployed to Railway. Without HSTS, users who access the Railway app via HTTP (before the redirect to HTTPS) are vulnerable to man-in-the-middle attacks. Railway redirects HTTP to HTTPS, but without HSTS the browser does not remember to use HTTPS on subsequent visits.
How to Detect
Run curl -I https://your-app.up.railway.app to check the response headers from your Railway deployment. Verify the presence of Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, Referrer-Policy, and Permissions-Policy. If your Railway service runs multiple routes, check headers on several paths. API routes and page routes may have different header configurations depending on how the application is structured. Vibe App Scanner checks all security-relevant response headers on Railway-hosted applications and provides framework-specific remediation guidance for the detected runtime.
How to Fix
For Express/Node.js on Railway, use the helmet middleware. Install it with npm install helmet and add app.use(helmet()) before your routes. Helmet configures sensible defaults for all major security headers. For Python FastAPI, add a middleware that sets security headers on every response. Use app.add_middleware(SecurityHeadersMiddleware) with a custom middleware class that sets all required headers. For Next.js on Railway, configure headers in next.config.js using the async headers() function, identical to the Vercel configuration. This approach is framework-native and works regardless of the hosting platform. For Go applications, add security headers in a middleware wrapper that applies to all HTTP handlers. Set the headers on the response writer before calling the next handler in the chain.
Code Examples
Security headers for a FastAPI app on Railway
# Railway FastAPI app - no security headers
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}from fastapi import FastAPI, Request, Response
from starlette.middleware.base import (
BaseHTTPMiddleware,
RequestResponseEndpoint,
)
class SecurityHeaders(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Strict-Transport-Security"] = (
"max-age=63072000; includeSubDomains; preload"
)
response.headers["Referrer-Policy"] = (
"strict-origin-when-cross-origin"
)
return response
app = FastAPI()
app.add_middleware(SecurityHeaders)Frequently Asked Questions
Does Railway add any security headers automatically?
Railway handles HTTPS and TLS termination at the proxy level, but does not add application-level security headers. Your application code must set headers like CSP, X-Frame-Options, and HSTS explicitly.
Can I configure headers at the Railway platform level?
Unlike Vercel (vercel.json) or Netlify (_headers file), Railway does not have a platform-level header configuration. Headers must be set in your application code using framework middleware or response configuration.
Does the Railway proxy add X-Forwarded headers?
Yes. Railway's reverse proxy adds X-Forwarded-For, X-Forwarded-Proto, and similar headers. Your application can use X-Forwarded-Proto to detect HTTPS and set HSTS accordingly. But standard security headers like CSP and X-Frame-Options must be added by your application.
Related Security Resources
Is Your App Vulnerable?
VAS automatically scans for insecure headers and other security issues in Railway apps. Get actionable results with step-by-step fixes.
Scans from $5, results in minutes.