WordPress security headers, explained: what each one does
WordPress security headers are short instructions your site sends with every page, telling the browser how strict to be with it. Without them, a browser falls back to its most permissive behavior: it may guess at file types, and any site may show your pages in a frame.
BetterShield adds four standard headers with one switch, and keeps the two that need more care, HSTS and a content policy, behind choices of their own. Here is what each does and what it could affect.
Quick summary
- A security response header tells the browser what to allow around a page. Visitors never see it.
- Send security response headers adds X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy, and leaves alone any your server already sends.
- HSTS has its own fix, Tell browsers to refuse plain HTTP. Start at five minutes, because a six-month setting stays in browsers after you turn it off.
- A content policy starts in report-only mode, so nothing is blocked. Enforcing is offered only after 7 days with no reports.
- The finding “Common security response headers are missing” is Low, costs 3 points, and has an Apply fix button.
What a security response header is
A browser that asks for a page gets the page plus a short block of labeled lines called headers. A security response header asks the browser to be stricter with the page than its default. It changes nothing about how the page looks.
To see them, open your browser’s developer tools, choose the Network tab, reload, and read the first request’s response headers.
The four WordPress security headers in one switch
Send security response headers is under What browsers are told on BetterShield › Protect › Hardening. It adds four standard headers to front-end pages, the sign-in page, the REST API and the dashboard. WordPress already sends two of the four on the dashboard, so the fix adds the other two there.
| Header and value sent | What it tells the browser | What it could affect |
|---|---|---|
X-Content-Type-Optionsnosniff | Use the file type the server declares. Never guess. | A file served with the wrong type may be refused as a script or stylesheet. |
X-Frame-OptionsSAMEORIGIN | Only your own site may show these pages in a frame. | Another site that frames your pages stops showing them. |
Referrer-Policystrict-origin-when-cross-origin | On links to other sites, pass on your domain, not the full address. | Sites you link to see the domain a visitor came from, not the page. |
Permissions-Policybrowsing-topics=() | Leave these pages out of the Topics API, which shares interest topics with advertisers. | Ads on your pages that rely on that API get no topics from it. |
Each closes a small gap. Without nosniff, a browser can decide an uploaded file is a script and run it. Without a framing rule, another site can load your page in a hidden frame under its own buttons. Without a referrer rule, anything private in an address can reach the sites you link to. And a browser takes part in the Topics API unless the site opts out.
Headers your server already sends are left alone
The fix never overwrites a header WordPress or another plugin has already set. Your web server can also add headers after WordPress has finished, out of a plugin’s sight, so once a day the fix asks your own front page which of the four the server sends, and leaves those to it. The card names them: “Your server already sends X-Frame-Options. This item leaves those to it and sends the rest.”
How to add security headers in WordPress with BetterShield
- On BetterShield › Protect › Hardening, find Send security response headers under What browsers are told.
- Press Preview the change. It lists what applying would do and changes nothing.
- Turn the switch on. Once a visitor’s page has carried the headers, the card says Confirmed on a page a visitor received, with the time.
- To undo, turn the switch off.
It is also in Quick Setup’s Safe fixes, as Add security headers, and wp bettershield harden security_headers --dry-run previews it from the terminal (WP-CLI commands).
HSTS in WordPress: tell browsers to refuse plain HTTP
Strict-Transport-Security, or HSTS, tells a browser to use only HTTPS for your site for a set time. Once a browser has seen it, plain HTTP is refused for the whole period, and the browser cannot fall back if the certificate lapses. That is why it is not one of the four: in the fix’s own words, it is “the one that can take a site offline.”
Tell browsers to refuse plain HTTP has two choices:
| Field | Choices |
|---|---|
| How long browsers should insist | Five minutes, to prove it works (preselected) or Six months, once you have lived with the short one |
| Include subdomains | This domain only (preselected) or Every subdomain as well |
- Make sure the site address is HTTPS. If it is not, the fix shows Not available here.
- Keep the preselected choices and press Preview the change. It shows the exact header:
max-age=300. - Turn it on, then use the site as visitors do: pages, forms, sign-in and the dashboard.
- When you are confident, turn the switch off, choose Six months, once you have lived with the short one, and turn it on again. The header becomes
max-age=15768000.
It goes out on HTTPS responses only, and one your server already sends is left alone. If the certificate expires within 21 days, the fix asks you to renew it first.
Why a long setting stays after you turn it off
Turning the fix off stops sending the header, but it cannot reach browsers that already saw it. At five minutes, they forget it within five minutes. At six months, they keep insisting on HTTPS until the time runs out.
Every subdomain as well is only for sites where every subdomain is on HTTPS too, including forgotten ones such as a staging or mail subdomain. For the same reasons, a connected AI assistant may apply only the five-minute, this-domain-only form. Six months or every subdomain waits for you.
Content-Security-Policy in WordPress: report first, enforce later
A Content-Security-Policy lists where a page may load scripts, styles, images, fonts and frames from, and the browser blocks everything else. It is a strong defense against injected script, and the header most likely to break a site’s own analytics, embeds and payment scripts.
Find out what a content policy would break sends the policy on front-end pages in report-only mode. Nothing a visitor loads changes. Browsers only report what would have been blocked.
The starting policy allows your own site, inline scripts and styles included, so the reports show what your pages load from elsewhere.
- Turn on Find out what a content policy would break under What browsers are told. The card says “Watching. Nothing has been reported yet.”
- As reports arrive, read What the policy would have blocked. Each line names a rule and the origin of what it would have blocked, most frequent first. The full address is never kept.
- Start enforcing this policy is offered only once nothing has been reported for 7 days. Until then the card says why, such as “Nothing has been reported in 3 of the 7 days this waits for.”
- Enforcing asks you to confirm. Go back to watching returns to report-only at once and is never held back.
A week covers traffic a quiet afternoon misses, such as a checkout used twice a week. Turning the fix off and on again restarts it in report-only.
For many sites the list is the useful part: a plain picture of what the pages pull in from elsewhere. Enforcing is for a site whose list stays empty.
The audit finding: “Common security response headers are missing”
The audit reports this finding when any of the four headers is missing. It sits in the Exposure area at Low severity and costs 3 points while open.
Explain on BetterShield › Findings says under Why it matters: “Without them a browser falls back to its most permissive behavior.” Under What could break, it says almost nothing: “If another site legitimately embeds your pages in a frame, that embed would stop working.”
Apply fix turns on Send security response headers straight away; undo it from Protect › Hardening. The finding covers the four headers only. HSTS and the content policy are your choices on the Hardening screen. See the Score and findings guide and the checklist.
Common mistakes
- Starting HSTS at six months. Prove it at five minutes first. A long setting stays in browsers after you turn it off.
- Choosing Every subdomain as well without checking each one. A forgotten staging or mail subdomain on plain HTTP becomes unreachable in those browsers.
- Forgetting that another site frames yours. If a partner site shows your pages in a frame,
SAMEORIGINstops it. Check before you apply. - Expecting HSTS behind a proxy that handles HTTPS. If WordPress sees requests as plain HTTP, the fix says so. Nothing is sent until wp-config.php sets the HTTPS server variable.
Frequently asked questions
Do security headers change how my site looks?
No. Visitors never see headers. For most sites, the one visible change is on another site that showed your pages in a frame.
My host already adds some of these. Will visitors get them twice?
No. The fix leaves any of the four already present untouched. Once a day it also checks which ones your web server sends on its own, and leaves those to the server.
Does BetterShield add HSTS preload?
No. Preload puts a site on a list built into browsers, and removal takes months, so the fix never adds it.
Can I turn the headers off again?
Yes. Turn the switch off on Protect › Hardening, or run wp bettershield harden security_headers --undo --user=<login>. The exception is HSTS: browsers that already saw a six-month setting keep it until it expires.
Conclusion
WordPress security headers are a small, quiet layer: four lines that make the browser stricter, one that insists on HTTPS, and one that limits where a page may load from. Turn on Send security response headers first. Then prove HSTS at five minutes, and let a content policy report for a week before you think about enforcing it.
BetterShield is free on WordPress.org. The Hardening guide covers all 16 fixes, and the WordPress security checklist shows where this finding fits.