Security · 4 min read
Security headers a website audit should fail
A security audit that only lists missing headers is incomplete. Here is how to read each finding and what a developer should change first.
Published · Updated
A website security audit starts with the response headers a browser actually received. Missing headers are not theoretical. They decide whether another site can iframe you, whether a leaked referrer includes a token, and whether HTTPS is sticky after the first visit.
Siteory's security audit records the live header set, then writes the fix in Markdown. This article is the decoder ring for those findings.
Which security headers should every public site send?
At minimum, a public HTML response should declare HTTPS policy, framing policy, referrer policy, and a content type hint. Content-Security-Policy is the high-value header and the one teams postpone because it can break analytics.
A practical baseline:
- Strict-Transport-Security with a long max-age once you are sure HTTPS works on every host
- X-Content-Type-Options: nosniff
- Referrer-Policy that does not leak full URLs to third parties
- Permissions-Policy that turns off unused powerful APIs
- X-Frame-Options or a CSP frame-ancestors rule
- Content-Security-Policy, even if the first version is report-only
Cookies used for auth need Secure, HttpOnly, and a tight SameSite value. Those are not "headers on the document" in the same way, but a security audit that ignores Set-Cookie is unfinished.
HSTS is safe only after HTTPS is boring
HSTS tells the browser to use HTTPS for a defined time. If a leftover HTTP host still serves the app, users can lock themselves out of it. Enable HSTS after:
- Every production hostname redirects HTTP to HTTPS
- The certificate covers www and the apex if both are used
- You are ready to keep that certificate renewed
preload is optional. Do not submit the domain to the HSTS preload list until the header is stable and includeSubDomains is intentional.
Content-Security-Policy without breaking the product
CSP is the header that stops unexpected scripts from running. The first version should be report-only so you can see what would have broken.
A first useful policy:
- default-src 'self'
- script-src that lists your script hosts, not unsafe-inline if you can avoid it
- style-src that matches how you actually ship CSS
- img-src that includes your CDN and any avatar hosts
- connect-src for your API and analytics beacons
- frame-ancestors 'none' or the specific admin preview origin
'unsafe-inline' and 'unsafe-eval' keep the page working and keep the policy weak. Nonces or hashes are the path out. If the report flags unsafe-inline, treat it as a follow-up, not as a fail you ignore forever.
Framing, referrers, and MIME sniffing
X-Frame-Options: DENY (or CSP frame-ancestors 'none') stops clickjacking on pages that should never be embedded. Marketing pages that must live in a partner iframe need an explicit allow list, not a missing header.
Referrer-Policy: strict-origin-when-cross-origin is a sane default. It keeps same-origin debugging useful and strips paths when the user leaves for another site. If a reset-password URL ever appears in a referrer, that is an incident, not a lint.
X-Content-Type-Options: nosniff stops the browser from guessing that a downloaded file is HTML. It is a one-line header and should already be on static assets.
What a security audit should not pretend to be
A header scan is not a penetration test. It will not find an IDOR in your API or a stored XSS in a comment field. It will find the configuration you forgot on the CDN edge.
Be honest in the report:
- Missing CSP is high if you handle logins on the same host
- Missing HSTS is medium until HTTPS is proven, then high
- A marketing site without Permissions-Policy is low
- Mixed content on the checkout host is critical
Siteory groups findings that way so the first pull request is the one that reduces real exposure.
How to verify a fix
After you ship headers, do not trust a screenshot of an old response.
- Request the URL with curl or your browser's network panel
- Confirm the header is on the HTML document, not only on /favicon.ico
- Confirm the CDN did not strip it
- Re-run the Siteory security audit on the same host
If you already ran the SEO audit, keep both reports. Header changes rarely move rankings. They do move whether a security reviewer will sign off on the launch.
