Reference guide · wordpress · Published 2026-08-16 · 4 min read
Security headers for WordPress
Security headers for WordPress: set HSTS, X-Frame-Options, X-Content-Type-Options and a CSP that does not break admin, uploads or inline assets.
- ·The headers to set
- ·Apply at the right layer
- ·Testing headers
Which headers matter for WordPress
WordPress is a PHP application and many of its plugins and themes rely on behavior that a strict header set can break: inline scripts and styles, data: URIs, and CDN-hosted assets. The headers below are the practical set, chosen for how WordPress behaves:
| Header | What it does | Risk to WordPress |
|---|---|---|
Strict-Transport-Security (HSTS) | Forces HTTPS on a browser visit | Low (needs HTTPS site wide) |
X-Content-Type-Options: nosniff | Stops MIME-type sniffing | None |
X-Frame-Options: SAMEORIGIN | Blocks clickjacking frames | None |
Content-Security-Policy (CSP) | Restricts script, style, connect sources | The one that breaks plugins |
An HTTPS-only WordPress site should also run a Referrer-Policy: strict-origin-when-cross-origin and Permissions-Policy, but the four above are the anchors; CSP is the one that needs careful rework.
How to set them
The cleanest place for a WordPress site is the hosting layer, not PHP: the server or CDN adds headers before WordPress runs. Three examples.
Apache (.htaccess in the document root)
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
nginx (server block)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
CDN layer (Cloudflare or similar): the referenced Transform Rules add the same response headers on passthrough. This keeps WordPress itself untouched, which is the usually safest option when your CDN handles the website (X-Frame-Options and HSTS both work at the edge).
The CSP you can ship without breaking everything
A strict CSP on WordPress (Content-Security-Policy: default-src 'self') breaks inline scripts and styles, which many themes, plugins, and analytics inject. The practical WordPress starting CSP:
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https://www.google-analytics.com;
unsafe-inlineinscript-srcandstyle-srcis the pragmatic opening position for WordPress: it allows plugin-injected inline scripts and styles rather than forcing a plugin audit on day one.data:inimg-srcandfont-srcpermitsdata:URL images and fonts that some plugins use.https:inimg-srclets image hotlinks to external images (CDNs, social cards) work.
Run CSP first in report-only mode (Content-Security-Policy-Report-Only) and look at the console / RUM for violated URLs before enforcing from strict. The config is per-page in the header you set, so a plugin that violates a strict CSP is visible in the browser console before real traffic, not after.
Where WordPress commonly breaks, and the fix
| Symptom | Header cause | Fix |
|---|---|---|
| Admin/dashboard white screen | CSP script-src lacks the blocker's inline scripts | Add the domain or a 'unsafe-inline' for the admin route type |
| Plugin gallery stops loading | img-src too strict for external hosts/data: | Widen img-src |
Login This site is no longer active | HSTS on HTTPS-only plus mixed http page | Ensure the whole site runs http to https; HSTS warns only, not blocks, on http |
| Frames break embeds | X-Frame-Options: DENY from section below | Use SAMEORIGIN or frame-ancestors in the same header |
The mixed-content angle also matters: HSTS without the http to https redirect on the CMS side leaves sticky http assets. The http to https redirect article covers restoring the site-wide HTTPS.
Test
Check the response headers from a public URL:
curl -sI https://example.com | findstr /I "strict-transport x-content x-frame content-security referrer"
Expected lines for HSTS, nosniff, SAMEORIGIN/frame-ancestors, a no-CSP or a report-only CSP, and the referrer policy. The SSL errors page shows the HSTS caveat: an invalid cert under HSTS hard-stops browsers on the domain, so roll out HSTS only when the cert renewal and the ssl renewal checklist are solid.
When to let a professional set the CSP
A strict CSP that covers every plugin and inline script on a CMS with active plugins is a multi-week audit project, not a settings change. If you enforce a tight policy and the dashboard breaks, the honest answer is report-only first, a planner to find the script domains and nonce handling, then a tightened policy with a nonce. Treat CSP for WordPress as a roadmap, not a one-line install, and always keep a report-only escape hatch before the enforced state.