Your web app might look great and work perfectly. But if you open DevTools and check the response headers, there's a good chance several critical security configurations are missing entirely.
Security headers are instructions your server sends to the browser, telling it how to behave when loading and running your site. Without them, browsers default to permissive settings that leave your users vulnerable to cross-site scripting (XSS), clickjacking, data injection, and more.
The good news: adding them is straightforward, and checking for them takes 10 seconds with vibeGuard.
1. Content-Security-Policy (CSP)
What it does: Tells the browser which sources are allowed to load scripts, styles, images, and other resources. Without it: An attacker who finds an XSS vulnerability can inject any script from any source. With CSP, even if they find a vulnerability, the browser blocks unauthorized scripts. Basic configuration:Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
Common mistake: Setting CSP to unsafe-inline and unsafe-eval for everything, which effectively disables the protection.
2. Strict-Transport-Security (HSTS)
What it does: Forces browsers to only connect via HTTPS, even if the user typeshttp://. Prevents SSL stripping attacks.
Without it: An attacker on the network can intercept the initial HTTP request and redirect users to a malicious site.
Configuration:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Note: Only add this after you're sure HTTPS works correctly everywhere. Once set, browsers will refuse HTTP connections for the specified duration.
3. X-Content-Type-Options
What it does: Prevents browsers from MIME-sniffing a response away from the declared content type. Without it: A browser might interpret a JSON response as HTML, opening the door for injection attacks. Configuration:X-Content-Type-Options: nosniff
This one is a no-brainer. Always set it. There's no downside.
4. X-Frame-Options
What it does: Controls whether your site can be embedded in an iframe. Prevents clickjacking attacks. Without it: An attacker can embed your site in an invisible iframe and trick users into clicking buttons they can't see — like "Transfer Funds" or "Delete Account." Configuration:X-Frame-Options: DENY
Or if you need to allow framing from your own domain:
X-Frame-Options: SAMEORIGIN
5. Referrer-Policy
What it does: Controls how much referrer information is sent when navigating from your site. Without it: The full URL (including query parameters, tokens, and sensitive data) gets sent to third-party sites when users click links. Configuration:Referrer-Policy: strict-origin-when-cross-origin
This sends the origin (domain) for cross-origin requests but strips the path and query string. Good balance between functionality and privacy.
6. Permissions-Policy
What it does: Controls which browser features your site can use — camera, microphone, geolocation, etc. Without it: Third-party scripts (analytics, ads) can access device APIs without your knowledge or consent. Configuration:Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Empty parentheses mean "no one can use this feature." Be explicit about what you allow.
7. X-XSS-Protection
What it does: Enables the browser's built-in XSS filter (in older browsers). Without it: Older browsers won't activate their XSS detection heuristics. Configuration:X-XSS-Protection: 1; mode=block
Note: Modern browsers have deprecated this in favor of CSP. But it's still worth setting for users on older browsers.
How to Add These Headers
Next.js (next.config.ts)
const securityHeaders = [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-XSS-Protection', value: '1; mode=block' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
];
const nextConfig = {
async headers() {
return [{ source: '/(.)', headers: securityHeaders }];
},
};
Express
const helmet = require('helmet');
app.use(helmet());
Helmet sets sensible defaults for all security headers. You can customize each one individually.
nginx
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Checking Your Headers in 10 Seconds
You have two options:
Option A: DevTools1. Open your site
2. DevTools → Network tab
3. Click the main document request
4. Scroll through Response Headers
This works, but you need to know what to look for and what's missing.
Option B: vibeGuard1. Open your site
2. Click the vibeGuard icon
3. See exactly which headers are present, missing, or misconfigured
vibeGuard doesn't just check if* headers exist — it validates the values. A CSP header with unsafe-inline unsafe-eval everywhere gets flagged because it's effectively useless.
The Bottom Line
Security headers are free. They take minutes to configure and protect your users against entire categories of attacks. There's no reason not to set them.
If you're shipping a web app without these seven headers, you're leaving the front door unlocked. Check your headers today — it literally takes 10 seconds.