← All checks

Missing Security Headers

Medium severity

What is this?

HTTP security headers are response headers that instruct browsers how to handle your site securely. They prevent entire classes of attacks - clickjacking, cross-site scripting, protocol downgrade attacks, and MIME type confusion. Most web applications ship with none of them configured because frameworks do not set them by default.

Which headers matter

Strict-Transport-Security (HSTS) forces browsers to always use HTTPS, preventing downgrade attacks. X-Frame-Options prevents your site from being embedded in iframes, blocking clickjacking. Content-Security-Policy (CSP) controls which scripts and resources can execute, mitigating XSS. X-Content-Type-Options stops browsers from guessing MIME types, preventing script injection through file uploads. Referrer-Policy controls how much URL information leaks to other sites. Permissions-Policy restricts access to browser features like camera, microphone, and geolocation.

Why it happens

Frameworks like Express, Next.js, Django, and Rails do not include security headers out of the box. Developers focus on building features and the app works fine in the browser without them. Headers only matter when something goes wrong - an XSS vulnerability becomes exploitable, a user gets clickjacked, or a MITM attack succeeds because HSTS was not set.

What's at risk

Without CSP, any XSS vulnerability in your app can execute arbitrary JavaScript in your users' browsers. Without X-Frame-Options, attackers can embed your site in a hidden iframe and trick users into clicking buttons they cannot see. Without HSTS, users on public WiFi can be silently downgraded from HTTPS to HTTP and have their session cookies stolen.

How to fix

Add security headers at the server or framework level.

Nginx:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Express (using helmet):

const helmet = require("helmet");
app.use(helmet());

Next.js (next.config.js):

async headers() {
  return [{
    source: "/(.*)",
    headers: [
      { key: "X-Frame-Options", value: "DENY" },
      { key: "X-Content-Type-Options", value: "nosniff" },
      { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
    ],
  }];
}

How Preflyt detects it

Preflyt makes a GET request to your site and analyzes every response header against security best practices. It checks for the presence and correct configuration of HSTS, X-Frame-Options, CSP, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy.

Frequently asked questions

Do I need all security headers?

Not every header applies to every app, but HSTS, X-Frame-Options, and X-Content-Type-Options are universally recommended. Content-Security-Policy is the most impactful but also the most complex to configure. Start with the easy ones and add CSP once you understand your app's resource loading patterns.

Does Vercel add security headers automatically?

Vercel adds some basic headers but does not configure HSTS, CSP, or Permissions-Policy by default. You need to add these yourself through your framework's configuration (e.g., next.config.js headers function) or through vercel.json.

What is the most important security header?

Content-Security-Policy (CSP) provides the most protection because it prevents XSS attacks, which are the most common web vulnerability. However, HSTS is the easiest to implement and prevents protocol downgrade attacks with a single line.

Related checks

Check your site now

Free scan. No signup required.