Why headers matter for small apps
HTTP security headers are instructions your server sends with every page, telling the browser what it may do. They cost nothing, take minutes to add, and switch on protections that otherwise stay off. They are also the most skipped step we see: in our study of 99 launched vibe-coded apps, 91% had no Content-Security-Policy and 88% could be framed by any website.
The headers this tool checks
Content-Security-Policy (CSP) lists where scripts, styles, images and connections may come from. If an AI-generated component ever renders user input as HTML, a strict CSP stops an injected script from running or sending data to an attacker's server. It's the single most valuable header and the one most likely to be missing.
Strict-Transport-Security (HSTS) tells browsers to always use HTTPS for your domain, closing the window where a first request over plain HTTP could be intercepted. Vercel, Netlify and most platforms add it automatically on their domains.
X-Frame-Options or CSP frame-ancestors stops other sites from loading yours in an invisible iframe and tricking users into clicking buttons (clickjacking). Use X-Frame-Options: DENY or frame-ancestors 'none' unless you need to be embedded.
X-Content-Type-Options: nosniff stops browsers from guessing file types, so an uploaded "image" can't be run as a script.
Referrer-Policy controls how much of your URL is sent to other sites when users click links. strict-origin-when-cross-origin avoids leaking paths and query strings such as reset tokens.
X-Powered-By is the opposite: a header you should remove. It advertises your framework and version, which helps attackers pick exploits.
How to add them
Vercel (vercel.json):
{ "headers": [{ "source": "/(.*)", "headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Content-Security-Policy-Report-Only", "value": "default-src 'self'" }
]}]}
Netlify: put the same pairs in a _headers file under /*. Next.js: return them from async headers() in next.config.js and set poweredByHeader: false. Express: use the helmet package and app.disable('x-powered-by'). Firebase Hosting: add a headers array in firebase.json.
Rolling out CSP without breaking your app
A CSP that's too strict will block your own analytics, fonts or Supabase calls. Start with Content-Security-Policy-Report-Only, which logs violations in the browser console without blocking anything. Click through your app, note each blocked origin, and add only those: for example connect-src 'self' https://<project>.supabase.co, img-src 'self' data: https:. Avoid 'unsafe-inline' in script-src; move inline scripts into files instead, as this site does. When the console is quiet, rename the header to Content-Security-Policy.
What headers don't do
How to read your results
Each header shows as present (with its value) or missing, with a severity. Missing CSP, HSTS and clickjacking protection are rated medium; nosniff, Referrer-Policy and X-Powered-By are low. That reflects how much each one reduces real-world risk for a typical app, not how hard it is to add. Note that we check the headers on your homepage response; if your host sets different headers for API routes or other paths, check those separately with curl -I https://your-app.com/path. A CDN or proxy in front of your app can also add or strip headers, so always test the live production domain.
Headers harden the browser side. They won't fix an open database, a leaked key or a missing auth check on an API route. Run the full scan to check those too.