Guides/Security headers

WordPress security guide

WordPress security headers: what to send and how

Five response headers tell browsers to refuse whole classes of attack on your visitors. They cost nothing and most WordPress sites send none of them.

Today, on most WordPress sites HEAD/0 of 5 headers

Browsers fall back to their most permissive behaviour.


After this guide HEAD/5 of 5 headers

Https only, no type guessing, no hidden frames, no leaking addresses.

Why it matters

DowngradesWithout HSTS, someone on the network can turn a visit into plain http.
Hidden framesOther sites load yours invisibly to trick clicks.
LeaksFull page addresses, sometimes with tokens in them, travel to other sites.
HeaderSafe value
Strict-Transport-Securitymax-age=31536000
X-Content-Type-Optionsnosniff
X-Frame-OptionsSAMEORIGIN
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policycamera=(), microphone=(), geolocation=()

Add includeSubDomains to HSTS only when every subdomain serves https, and preload only once you are sure: it is hard to undo. A Content-Security-Policy is powerful, but on WordPress it breaks plugins easily; if you want one, start with Content-Security-Policy-Report-Only and watch what it would block.

Check your site

Run the free check, or ask the URL yourself:

curl -sI https://example.com/ | grep -iE "strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy"

Each line that comes back is one header present. Five lines means all five.

Fix it

nginx

add_header Strict-Transport-Security "max-age=31536000" 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;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Catch: a location block with any add_header of its own drops all of these for the requests it handles. Repeat them there, or put them in a file and include it in each such block.

Apache

With mod_headers enabled, in .htaccess or the virtual host:

Header always set Strict-Transport-Security "max-age=31536000"
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"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"

WordPress

add_action( 'send_headers', function () {
    if ( is_ssl() ) {
        header( 'Strict-Transport-Security: max-age=31536000' );
    }
    header( 'X-Content-Type-Options: nosniff' );
    header( 'X-Frame-Options: SAMEORIGIN' );
    header( 'Referrer-Policy: strict-origin-when-cross-origin' );
    header( 'Permissions-Policy: camera=(), microphone=(), geolocation=()' );
} );

Catch: this only reaches pages WordPress renders. Images, scripts, stylesheets and pages served by a page cache skip PHP and go out without them.

Questions

Will these headers break my site?

These five values are safe for nearly every WordPress site. The one to watch is X-Frame-Options if another site of yours embeds this one in a frame; use a CSP frame-ancestors rule for that case.

Do security headers help SEO?

Not directly. HSTS keeps every visit on https, which search engines prefer, but the headers exist to protect visitors.

Why not a Content-Security-Policy?

A strict CSP is the strongest of all, but WordPress themes and plugins load scripts from many places, so a policy that does not break anything takes per-site work.

More guides

Last reviewed 2026-10-08