← Back to Research

The 5 Security Headers Every SaaS Company Gets Wrong

When we audit web applications, the first thing we check is not the code. It is the HTTP response headers. They take seconds to inspect, and they immediately reveal how much thought an engineering team has put into security.

In our recent scan of 50 companies, missing or misconfigured security headers were the single most common finding -- present across every grade from B through F. These are not obscure best practices. They are browser-native defense mechanisms that have been available for years, are free to implement, and take less than an hour to configure correctly.

Here are the five headers that most SaaS companies get wrong, what they do, and how to fix them.


1. Strict-Transport-Security (HSTS)

What It Does

HSTS tells browsers to only connect to your site over HTTPS. Once a browser receives this header, it will automatically upgrade any HTTP request to HTTPS for the duration specified in the max-age directive -- even if the user types http:// in the address bar or clicks an HTTP link.

Why It Matters

Without HSTS, a user on a public WiFi network can be subjected to an SSL stripping attack. The attacker intercepts the initial HTTP request (before the redirect to HTTPS) and serves the site over HTTP, proxying requests to the real HTTPS backend. The user sees no lock icon but often does not notice. Every credential, session cookie, and piece of data flows through the attacker in plaintext.

The Correct Configuration

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Breaking this down:

Common Mistakes

How to Test

curl -sI https://yourdomain.com | grep -i strict-transport

Or use SecurityHeaders.com for a comprehensive scan.


2. Content-Security-Policy (CSP)

What It Does

CSP is the most powerful security header available. It tells the browser exactly which sources of content are allowed on your page -- which domains can serve JavaScript, CSS, images, fonts, frames, and other resources. If an attacker manages to inject a script tag (XSS), CSP can prevent the injected script from executing because it does not match the allowed sources.

Why It Matters

Cross-site scripting (XSS) remains one of the most common web vulnerabilities. A strong CSP is the most effective browser-side mitigation against XSS exploitation. Without it, any XSS vulnerability becomes trivially exploitable -- the attacker's injected script can load external resources, exfiltrate data, and modify the DOM without restriction.

The Problem: Most CSPs Are Useless

The vast majority of CSP implementations we encounter are so permissive that they provide no meaningful security. Common patterns we see:

# This CSP does almost nothing:
Content-Security-Policy: default-src *; script-src * 'unsafe-inline' 'unsafe-eval'

# This is only slightly better:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'

The 'unsafe-inline' directive is the most common offender. It allows inline scripts and event handlers, which is exactly what most XSS payloads use. A CSP with 'unsafe-inline' in the script-src directive blocks almost no XSS attacks.

A Better Approach

Use nonce-based CSP instead of allowing 'unsafe-inline':

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'nonce-{random}'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.yourdomain.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'

Generate a unique nonce for each page load and add it to every legitimate script tag: <script nonce="{random}">. Injected scripts will not have the nonce and will be blocked.

Deployment Strategy

Start with report-only mode to avoid breaking your application:

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report

Monitor the reports, add legitimate sources to the allowlist, and switch to enforcement when violations drop to zero for legitimate traffic.


3. X-Frame-Options

What It Does

X-Frame-Options controls whether your page can be embedded in an iframe. This is the primary defense against clickjacking attacks, where an attacker overlays your page with a transparent iframe and tricks users into clicking on elements they cannot see.

The Correct Configuration

X-Frame-Options: DENY

If your application legitimately needs to be framed (for example, embedded widgets), use:

X-Frame-Options: SAMEORIGIN

For more granular control, use CSP's frame-ancestors directive instead, which supports allowlisting specific domains:

Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com

Common Mistakes


4. X-Content-Type-Options

What It Does

This header prevents browsers from MIME-sniffing a response away from the declared Content-Type. There is exactly one valid value:

X-Content-Type-Options: nosniff

Why It Matters

Without this header, a browser might interpret a file based on its content rather than its declared type. An attacker who can upload a file with a .jpg extension but containing JavaScript could trick the browser into executing it as a script if the file is loaded in certain contexts. With nosniff set, the browser strictly respects the declared Content-Type and refuses to execute content that does not match.

Common Mistakes

The only mistake is not setting it. This header has no configuration options, no edge cases, and no risk of breaking functionality. There is no reason for any application to omit it.


5. Referrer-Policy

What It Does

Referrer-Policy controls how much URL information the browser includes in the Referer header when a user navigates from your site to an external link. By default, browsers send the full URL including the path and query string.

Why It Matters

URLs often contain sensitive information: session tokens in query parameters, internal path structures, user IDs, search queries, and other data that should not be leaked to third parties. When a user clicks an external link on your page, the destination site receives the full URL of the page they came from.

Consider a URL like https://app.example.com/users/12345/settings?token=abc123. Without a restrictive Referrer-Policy, any external link on that page sends the full URL -- including the user ID and token -- to the linked site.

The Correct Configuration

Referrer-Policy: strict-origin-when-cross-origin

This sends only the origin (scheme + host) for cross-origin requests while preserving the full URL for same-origin navigation. For maximum privacy:

Referrer-Policy: no-referrer

Common Mistakes


The Complete Header Set

Here is the complete set of security headers we recommend for every SaaS application. Copy this into your web server configuration and adjust the CSP to match your application's needs:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()

Verification Tools

After deploying these headers, verify them with these free tools:

Aim for an A+ on SecurityHeaders.com. It is achievable for any application and takes less than an afternoon of work.

How do your headers stack up?

Our free scan checks your security headers, DMARC, TLS configuration, and more in minutes.

Scan Your Domain Free

Sources