BLOG Web Security 14 MIN READ

HTTP Security Headers: How CSP, HSTS, and X-Frame-Options Reduce Browser-Side Risk

A technical deep-dive into how browser-enforced HTTP security headers work, what breaks when they are missing, how attackers abuse the gaps, and how to deploy safe header policies.

Introduction

A login page can be served over HTTPS, have a valid certificate, and still expose users to avoidable browser-side attacks.

If the page can be framed by another site, it may be clickjacked. If the browser is allowed to load scripts from anywhere, a small XSS bug can become account takeover. If users can be downgraded from HTTPS to HTTP before the browser learns the site should be HTTPS-only, credentials and session cookies are easier to intercept on hostile networks.

HTTP security headers are the control plane for these browser decisions. They do not patch vulnerable code, but they tell the browser what must be blocked, upgraded, isolated, or restricted.

This deep-dive explains the three headers security teams ask about most often: Content-Security-Policy, Strict-Transport-Security, and X-Frame-Options. It also shows how to detect missing headers and deploy practical fixes without breaking production.

How HTTP security headers work at the browser level

HTTP security headers are response headers sent by the server. The browser reads them before rendering the page or loading related resources.

The important detail is enforcement location. CSP, HSTS, and X-Frame-Options are enforced by the browser, not by the origin server after the fact.

That makes them useful as defense-in-depth controls. The application may still contain a bug, but the browser can refuse to execute untrusted script, refuse to use plaintext HTTP, or refuse to embed the page inside a malicious frame.

A simple response might look like this: ```http HTTP/2 200 OK Content-Type: text/html; charset=utf-8 Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0m'; object-src 'none'; base-uri 'self'; frame-ancestors 'none' Strict-Transport-Security: max-age=31536000; includeSubDomains X-Frame-Options: DENY X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), camera=(), microphone=() ```

What the main HTTP security headers control.
HeaderBrowser behaviorMain risk reducedCommon mistake
Content-Security-PolicyControls which scripts, frames, images, styles, connections, and parents are allowedXSS impact, content injection, unwanted framing, unsafe third-party loadingUsing unsafe-inline or a huge allowlist that trusts too much
Strict-Transport-SecurityForces future requests to the host to use HTTPS for a configured timeHTTP downgrade and SSL stripping after policy is learnedSetting it without testing subdomains or using too short a max-age
X-Frame-OptionsControls whether the page can be rendered inside a frameClickjackingUsing it instead of CSP frame-ancestors when trusted embedding needs multiple origins
X-Content-Type-OptionsStops MIME sniffing for script and style responsesScript/style execution from wrong MIME typesMissing nosniff on static assets and upload-serving domains
Referrer-PolicyControls how much referrer data is sent to other originsURL and token leakage through Referer headersUsing no policy on apps with sensitive URL paths
Permissions-PolicyRestricts browser features such as camera, microphone, geolocation, and paymentUnnecessary feature access by page or embedded contentLeaving powerful browser APIs available by default

What the vulnerable header configuration looks like

A vulnerable header configuration is often not obviously broken. The site loads, login works, the certificate is valid, and users see no visible error.

The problem is that the browser receives no clear policy for script execution, HTTPS enforcement, framing, MIME handling, referrer leakage, or browser feature access.

A weak response often looks like this: ```http HTTP/2 200 OK Content-Type: text/html Server: nginx ```

That response may be missing CSP, HSTS, X-Frame-Options or CSP frame-ancestors, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy.

These are separate findings with different risks. Missing CSP affects XSS impact and resource loading. Missing HSTS affects HTTPS downgrade protection. Missing frame protection affects clickjacking. Missing nosniff, referrer, and permissions policies affect resource handling, URL leakage, and browser feature exposure.

Content-Security-Policy: what CSP stops

Content-Security-Policy, usually called CSP, tells the browser which sources are allowed for scripts, styles, images, fonts, frames, form submissions, network connections, and embedding parents.

CSP is most important as an XSS impact reducer. If an attacker injects script into a page, a strong CSP can stop that script from executing unless it has the right nonce, hash, or allowed source.

CSP can also restrict where data can be sent. For example, connect-src can limit which API endpoints JavaScript can call, and form-action can limit where forms may submit data.

A basic CSP looks like this: ```http Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none' ```

That is a start, but it is not enough for most modern apps because JavaScript, CSS, images, fonts, workers, analytics, and API calls often need separate directives.

Important CSP directives and what they control.
DirectiveControlsUseful for
default-srcFallback source list for many resource typesReducing accidental loading from untrusted origins
script-srcJavaScript sources, nonces, hashes, and inline script behaviorReducing XSS impact
style-srcStylesheet and inline style behaviorRestricting injected CSS and untrusted style sources
img-srcAllowed image sourcesControlling image beacons and third-party tracking paths
connect-srcfetch, XHR, WebSocket, EventSource, and similar connectionsRestricting data exfiltration routes from frontend code
frame-srcWhat the page may embedControlling embedded widgets, payment frames, and third-party content
frame-ancestorsWho may embed this pageReplacing or strengthening X-Frame-Options for clickjacking defense
form-actionWhere forms may submitBlocking credential submission to attacker-controlled origins
base-uriWhere base tags may pointPreventing injected base tags from rewriting relative URLs
object-srcPlugin-style object, embed, and applet contentRemoving legacy plugin attack surface
report-uri or report-toWhere policy violation reports are sentSafe rollout and monitoring

What a vulnerable CSP configuration looks like

A missing CSP gives the browser no page-level loading policy: ```bash curl -I https://example.com | grep -i content-security-policy ```

Weak output: ```text (no Content-Security-Policy header returned) ```

A weak CSP often exists but allows the exact behavior it was supposed to block: ```http Content-Security-Policy: default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; ```

That policy trusts every origin, allows inline JavaScript, allows eval-like execution, and permits data and blob URLs broadly. It may look like a CSP to a scanner, but it gives attackers too much room.

Another common weak policy only protects one resource type: ```http Content-Security-Policy: default-src 'self' ```

This is better than nothing, but it does not explicitly handle framing, form submission, object embedding, base tags, report collection, or modern script nonces.

  • Missing CSP — The browser has no policy restricting script, frame, form, or connection sources.
  • unsafe-inline — Inline scripts can run, which weakens CSP’s ability to reduce XSS impact.
  • unsafe-eval — String-to-code execution remains allowed, increasing the impact of injection bugs and unsafe dependencies.
  • Wildcard sources — A broad * source can allow attacker-controlled infrastructure or untrusted third-party content.
  • No frame-ancestors — The page may still be embeddable even if script loading is restricted.
  • No report-only rollout — Teams deploy a blocking CSP directly and break production scripts without telemetry.

Secure CSP examples

A safer baseline for a traditional server-rendered app might look like this: ```http Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}'; style-src 'self'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none' ```

The nonce must be generated with strong randomness per response and applied only to scripts the server intentionally emits.

Example script tag: ```html <script nonce="{RANDOM_PER_RESPONSE}"> window.appConfig = {"apiBase":"https://app.example.com"}; </script> ```

For a single-page app that calls APIs and loads assets from a CDN, be explicit rather than using wildcards: ```http Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}' https://cdn.example-cdn.com; style-src 'self' https://cdn.example-cdn.com; img-src 'self' data: https://images.example-cdn.com; connect-src 'self' https://api.example.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none' ```

For rollout, start with report-only mode: ```http Reporting-Endpoints: csp-endpoint="https://csp-report.example.com/report" Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-to csp-endpoint; report-uri https://csp-report.example.com/report ```

Report-only mode lets the browser report violations without blocking resources. Use it to find legitimate sources before enforcing the policy. The report-to directive is the modern reporting direction, while report-uri is often kept for compatibility.

Strict-Transport-Security: what HSTS stops

Strict-Transport-Security, usually called HSTS, tells the browser that a host must be accessed only over HTTPS for a configured time.

Once the browser has learned an HSTS policy, future attempts to visit http://example.com are upgraded to https://example.com before the request is sent.

HSTS reduces HTTP downgrade and SSL stripping risk after the browser has received the policy over HTTPS. It also prevents users from clicking through certificate errors for that host while the policy is active.

A basic HSTS header looks like this: ```http Strict-Transport-Security: max-age=31536000 ```

A stronger production header, after careful testing, looks like this: ```http Strict-Transport-Security: max-age=63072000; includeSubDomains; preload ```

HSTS directives and their effect.
DirectiveMeaningRisk if misused
max-ageHow many seconds the browser remembers the HTTPS-only policyToo short gives weak protection; too long can lock users out if HTTPS breaks
includeSubDomainsApplies the policy to all subdomainsBreaks subdomains that still need HTTP or have invalid TLS
preloadSignals consent for browser preload-list submissionHard to reverse quickly; every subdomain must be HTTPS-ready

What a vulnerable HSTS configuration looks like

Missing HSTS: ```bash curl -I https://example.com | grep -i strict-transport-security ```

Weak output: ```text (no Strict-Transport-Security header returned) ```

A short max-age is also weak for production: ```http Strict-Transport-Security: max-age=300 ```

That tells the browser to remember HTTPS-only behavior for only five minutes.

A risky preload attempt looks like this: ```http Strict-Transport-Security: max-age=63072000; includeSubDomains; preload ```

This is strong only if every current and future subdomain supports HTTPS correctly. If internal, legacy, regional, or vendor-hosted subdomains still depend on HTTP, includeSubDomains can create outages.

  • Missing HSTS — Users can still be sent to HTTP on first contact or after bookmarks, links, and redirects.
  • Short max-age — The browser forgets the HTTPS-only policy quickly.
  • No includeSubDomains — Subdomains may remain downgradeable even when the root domain is protected.
  • Preload before inventory — Submitting a domain before validating every subdomain can create long-lived availability problems.
  • HSTS on HTTP responses only — Browsers ignore HSTS delivered over insecure HTTP; it must be delivered over HTTPS.

Safe HSTS rollout plan

HSTS should be rolled out like a migration, not pasted blindly into a web server config.

Start with HTTPS correctness. Every hostname that will be covered needs a valid certificate, correct redirects, and no required HTTP-only workflow.

Use a short test max-age first: ```http Strict-Transport-Security: max-age=300 ```

Then increase gradually: ```http Strict-Transport-Security: max-age=604800 ```

Then move to a long production value: ```http Strict-Transport-Security: max-age=31536000; includeSubDomains ```

Only consider preload after you have verified root-domain HTTPS, HTTP-to-HTTPS redirect behavior, valid certificates, includeSubDomains readiness, a max-age of at least 31536000, and no HTTP-only subdomains.

A preload-ready header commonly looks like this: ```http Strict-Transport-Security: max-age=63072000; includeSubDomains; preload ```

  • Preload readiness checklist — Verify HTTPS on the root domain, redirect HTTP to HTTPS, serve valid certificates, confirm every subdomain is HTTPS-ready, use includeSubDomains, use a long max-age, and confirm no legacy, regional, vendor, or internal subdomain still depends on HTTP.

X-Frame-Options: what XFO stops

X-Frame-Options tells the browser whether a page can be rendered inside a frame, iframe, embed, or object.

Its main purpose is clickjacking defense. In a clickjacking attack, a malicious page embeds a real application in a hidden or disguised frame and tricks an authenticated user into clicking something they did not intend to click.

The two practical values are: ```http X-Frame-Options: DENY ```

And: ```http X-Frame-Options: SAMEORIGIN ```

DENY blocks all framing. SAMEORIGIN allows the page to be framed by pages from the same origin.

For modern applications, CSP frame-ancestors is more flexible because it can allow specific trusted parent origins: ```http Content-Security-Policy: frame-ancestors 'self' https://admin.example.com https://partner.example.net ```

X-Frame-Options and CSP frame-ancestors comparison.
ControlBest useLimitation
X-Frame-Options: DENYPages that should never be embeddedNo allowlist support
X-Frame-Options: SAMEORIGINPages that may be framed only by the same originNot enough for multi-origin trusted embedding
CSP frame-ancestors 'none'Modern equivalent of no embeddingRequires CSP support
CSP frame-ancestors 'self' https://partner.exampleTrusted embedding by specific originsMust be carefully maintained

What a vulnerable frame configuration looks like

Missing frame protection is easy to detect: ```bash curl -I https://example.com/login | grep -Ei 'x-frame-options|content-security-policy' ```

Weak output: ```text (no X-Frame-Options header returned) (no Content-Security-Policy frame-ancestors directive returned) ```

A misleading configuration looks like this: ```http X-Frame-Options: ALLOW-FROM https://partner.example ```

ALLOW-FROM is obsolete in modern browser practice and does not solve multi-origin embedding reliably. Use CSP frame-ancestors for allowlists instead.

Another weak pattern is protecting only the homepage while leaving authenticated actions unprotected: ```text / -> X-Frame-Options: DENY /account/delete -> no frame protection /billing/update -> no frame protection /admin/users -> no frame protection ```

Clickjacking risk depends on the action. A static marketing page may not matter much. An authenticated billing, OAuth consent, admin, or account settings page matters.

How attackers exploit missing headers step by step

These steps are for defensive understanding only. Test only systems you own or have explicit permission to assess.

For missing CSP, the attacker first needs an injection path: stored XSS, reflected XSS, unsafe HTML rendering, compromised third-party script, or a vulnerable dependency.

Without a strong CSP, injected JavaScript can often execute, read page-accessible data, perform actions as the user, or send data to attacker-controlled infrastructure. CSP does not remove the injection bug, but it can block the script execution path or restrict where exfiltration requests can go.

For missing HSTS, the attacker needs a network position or downgrade opportunity. The user follows an http:// link or types a bare domain, the attacker interferes with the redirect to HTTPS, and the user may interact with a downgraded flow. HSTS reduces this after the browser has learned the policy, and preload reduces the first-visit gap.

For missing X-Frame-Options or frame-ancestors, the attacker embeds the target page inside a frame on another site. The visible decoy page tricks the authenticated user into clicking where a sensitive button or control exists in the framed application.

The defensive lesson is simple: headers do not replace input validation, HTTPS, CSRF protection, or authentication controls. They make browser exploitation paths harder and reduce the blast radius when application bugs exist.

Header gaps and attacker outcomes.
Missing or weak headerAttack pathPossible consequence
Weak CSPInjected or compromised script executes in the pageSession actions, account takeover paths, data theft from page context
No HSTSHTTP downgrade or SSL stripping before HTTPS is enforcedCredential or session exposure on hostile networks
No X-Frame-Options or frame-ancestorsAuthenticated page is embedded in a malicious frameClickjacking of account, billing, consent, or admin actions
No X-Content-Type-OptionsBrowser sniffs script or style content with wrong MIME typeUnexpected execution or resource handling
Weak Referrer-PolicyFull URL is sent to third-party originsToken, path, campaign, or internal route leakage
Loose Permissions-PolicyBrowser features remain available unnecessarilyUnwanted access paths through embedded or compromised content

How to detect HTTP security headers in your environment

Start with the pages that carry user risk: login, checkout, account settings, admin panels, OAuth consent, password reset, billing, dashboard, API documentation, and public upload-serving domains.

Check one page manually: ```bash curl -I https://example.com/login ```

Filter for common security headers: ```bash curl -I https://example.com/login | grep -Ei 'content-security-policy|strict-transport-security|x-frame-options|x-content-type-options|referrer-policy|permissions-policy' ```

Check redirects and final headers: ```bash curl -IL http://example.com/login ```

Check whether HSTS appears only after HTTPS: ```bash curl -I http://example.com | grep -i strict-transport-security curl -I https://example.com | grep -i strict-transport-security ```

The HTTP response should not be relied on for HSTS. Browsers process HSTS only when it is delivered over a secure HTTPS connection.

Check multiple important paths without disabling TLS validation: ```bash for path in / /login /account /admin /billing /reset-password; do echo "\n== $path ==" curl -sI "https://example.com$path" \ | grep -Ei 'HTTP/|content-security-policy|strict-transport-security|x-frame-options|x-content-type-options|referrer-policy|permissions-policy' done ```

Use `-k` only as a fallback when you need header evidence from a host with a known certificate problem, and record that TLS validation failed.

Remediation — secure header examples for common stacks

Do not deploy the same header block everywhere without testing. Admin apps, public marketing pages, API responses, file downloads, and embedded widgets may need different policies.

Start with a baseline, then tighten by route.

Nginx example

A practical Nginx baseline without nonce-based inline script support: ```nginx server { listen 443 ssl http2; server_name example.com; add_header Strict-Transport-Security "max-age=31536000; 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 "geolocation=(), camera=(), microphone=()" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always; location / { proxy_pass http://app_backend; } } ```

If your app uses inline scripts, generate the CSP nonce in application code with strong randomness per response and render the same nonce into both the CSP header and the allowed script tags. Do not use `$request_id`, a static value, or a proxy-generated value unless the application also injects that exact nonce into allowed script tags.

Apache example

A practical Apache baseline: ```apache <IfModule mod_headers.c> Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()" Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}'; style-src 'self'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" </IfModule> ```

If your Apache layer cannot generate and inject a matching per-response nonce into rendered HTML, remove the nonce from the server-level example and set nonce-based CSP in the application instead.

If your app is behind a reverse proxy or CDN, confirm whether headers are set at the app, proxy, CDN, or all three. Duplicate or conflicting headers can produce surprising browser behavior.

Express.js example

For Node and Express, Helmet is the common starting point: ```javascript import express from "express"; import helmet from "helmet"; import crypto from "crypto"; const app = express(); app.use((req, res, next) => { res.locals.cspNonce = crypto.randomBytes(16).toString("base64"); next(); }); app.use( helmet({ contentSecurityPolicy: { useDefaults: true, directives: { "default-src": ["'self'"], "script-src": ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`], "style-src": ["'self'"], "img-src": ["'self'", "data:", "https:"], "connect-src": ["'self'", "https://api.example.com"], "object-src": ["'none'"], "base-uri": ["'self'"], "form-action": ["'self'"], "frame-ancestors": ["'none'"] } }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: false }, frameguard: { action: "deny" }, noSniff: true, referrerPolicy: { policy: "strict-origin-when-cross-origin" } }) ); ```

This example shows the pattern, not a copy-paste guarantee. Test the actual rendered HTML so the nonce in script tags matches the nonce in the CSP header.

Before and after header baseline

A weak response often looks like this: ```http HTTP/2 200 OK Content-Type: text/html Server: nginx ```

A stronger baseline looks like this: ```http HTTP/2 200 OK Content-Type: text/html; charset=utf-8 Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM_PER_RESPONSE}'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none' Strict-Transport-Security: max-age=31536000; includeSubDomains X-Frame-Options: DENY X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: geolocation=(), camera=(), microphone=() ```

This is still a baseline. Real applications may need controlled exceptions for payment providers, identity providers, analytics, CDNs, image hosts, WebSocket endpoints, or trusted embedding parents.

How ExternalSight helps monitor HTTP header drift

HTTP security headers are easy to fix once and easy to break later. A CDN migration, framework upgrade, new reverse proxy, marketing microsite, or subdomain launch can remove headers without anyone noticing.

ExternalSight includes scanners for HTTP headers, CSP, HTTP configuration, TLS configuration, SSL, mixed content, cookie security, redirects, CORS, admin panels, and login surface exposure as part of its external attack surface monitoring workflow.

ExternalSight findings can be classified, enriched with remediation planning, included in score and coverage reporting, compared historically, and surfaced through alerts. Continuous monitoring is available for verified domains on supported plans.

Use that kind of workflow to catch drift: a missing HSTS header after a CDN change, a weakened CSP after a frontend release, or a missing frame policy on a newly launched admin surface.

ExternalSight does not replace secure development, manual review, penetration testing, WAF controls, or browser testing. Its role here is to help teams see externally visible header posture and monitor changes across internet-facing domains.

Real-world incidents and why headers still matter

Clickjacking is not only a theoretical browser trick. OWASP documents the Adobe Flash settings-page clickjacking example, where a page could be loaded in an invisible iframe and users could be tricked into changing camera and microphone-related settings.

The important lesson is that missing frame controls are most serious when an authenticated page contains a sensitive action. Login, billing, OAuth consent, account settings, and admin pages deserve stronger review than static marketing pages.

HSTS exists because HTTPS redirects alone are not enough against downgrade attacks. Moxie Marlinspike’s 2009 SSL stripping work showed how an on-path attacker could interfere with HTTP-to-HTTPS transitions. HSTS reduces that class of attack after the browser has learned the policy, and preload helps reduce the first-visit gap.

CSP matters because XSS is still one of the most common web exploit paths. OWASP describes CSP as defense-in-depth: it does not remove the underlying bug, but a strong policy can make exploitation much harder by blocking untrusted script execution and limiting allowed destinations.

Key takeaways

  • {'text': 'HTTP security headers are browser-enforced controls. They tell the browser what to block, upgrade, isolate, or restrict.'}
  • {'text': 'CSP reduces XSS impact, unsafe third-party loading, data exfiltration paths, and unwanted framing when written strictly.'}
  • {'text': 'HSTS reduces HTTPS downgrade and SSL stripping risk after the browser learns the policy; preload helps with first-visit protection.'}
  • {'text': 'X-Frame-Options reduces clickjacking risk, but CSP frame-ancestors is the better modern control for trusted embedding allowlists.'}
  • {'text': 'Missing headers are not all equal. Prioritize login, account, admin, billing, OAuth, checkout, and sensitive workflow pages first.'}
  • {'text': 'Deploy CSP and HSTS gradually. Report-only CSP and staged HSTS max-age values prevent avoidable production outages.'}

Frequently asked questions

What are HTTP security headers?
HTTP security headers are response headers that instruct browsers how to handle a page or resource. They can restrict script execution, enforce HTTPS, prevent framing, reduce MIME sniffing, limit referrer leakage, and restrict browser features.
Does CSP stop all XSS?
No. CSP does not fix the underlying injection bug. A strong CSP can reduce XSS impact by blocking untrusted script execution, inline scripts without a nonce or hash, unsafe eval, and some data exfiltration paths.
Should I use X-Frame-Options or CSP frame-ancestors?
Use CSP frame-ancestors for modern, flexible framing policy. Keep X-Frame-Options: DENY or SAMEORIGIN as a simple compatibility layer when appropriate. Do not use obsolete ALLOW-FROM patterns for modern allowlists.
What is a safe HSTS value?
For production, many teams work toward at least one year, such as max-age=31536000, after testing. Use includeSubDomains only after every subdomain is HTTPS-ready. Use preload only after validating preload requirements and operational impact.
Can security headers break a website?
Yes. CSP can block legitimate scripts or API calls. HSTS can break HTTP-only subdomains. Frame controls can break partner embeds. Roll out with testing, report-only policies, staged max-age values, and route-specific exceptions.
How does ExternalSight help with HTTP security headers?
ExternalSight includes HTTP header, CSP, HTTP configuration, TLS, cookie, CORS, redirect, admin panel, and login-surface checks as part of its external attack surface monitoring workflow. It helps identify externally visible header gaps and monitor verified domains for drift on supported plans.

References and further reading

  • MDN — Content Security Policy — https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP
  • MDN — Content-Security-Policy header — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
  • OWASP Content Security Policy Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html
  • RFC 6797 — HTTP Strict Transport Security — https://www.rfc-editor.org/rfc/rfc6797.html
  • MDN — Strict-Transport-Security — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security
  • HSTS preload list requirements — https://hstspreload.org/
  • RFC 7034 — X-Frame-Options — https://datatracker.ietf.org/doc/html/rfc7034
  • MDN — X-Frame-Options — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options
  • MDN — CSP frame-ancestors — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-ancestors
  • OWASP HTTP Security Response Headers Cheat Sheet — https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
  • OWASP Secure Headers Project — https://owasp.org/www-project-secure-headers/
  • OWASP Clickjacking — https://owasp.org/www-community/attacks/Clickjacking
  • Black Hat 2009 — New Tricks For Defeating SSL In Practice — https://blackhat.com/presentations/bh-dc-09/Marlinspike/BlackHat-DC-09-Marlinspike-Defeating-SSL.pdf

Monitor header drift across your external surface

ExternalSight helps teams scan internet-facing domains, identify HTTP header and CSP gaps, classify findings, generate remediation plans, compare scan history, receive alerts, export reports, and monitor verified domains on supported plans. Use it to catch header drift when new subdomains, CDNs, reverse proxies, or app releases change browser security posture.

Olivia Carter CLOUD SECURITY RESEARCHER · EXTERNALSIGHT

Find your shadow IT before someone else does

Run a deterministic external scan and get an evidence-backed inventory of every asset attackers can reach.

No agents to install Results in under 2 minutes Signed, audit-ready findings