WordPress · Security · HTTP Headers

How to add HTTP security headers to WordPress

Security headers protect a WordPress site from clickjacking, content sniffing and XSS. What each header does and how to add them without editing server files.

Mohit Goyal 5 min read
How to add HTTP security headers to WordPress

To add HTTP security headers to WordPress, either add them to your server configuration (.htaccess on Apache, the server block on Nginx) or send them from WordPress with a plugin. I wrote the free HTTP Security Header plugin for exactly this, and it now has more than 1,000 active installs. Scan your site first, switch on the safe headers, and add Content-Security-Policy last, with testing.

What are HTTP security headers?

They are instructions your server sends with every page. The browser reads them and enforces rules on your behalf: only load this site over HTTPS, do not let other sites frame this page, do not guess file types, do not send full URLs to other sites. A few lines of configuration close off whole classes of attack such as clickjacking, content sniffing and cross-site scripting.

Most WordPress sites send none of them, because adding headers normally means editing server files that site owners are rightly afraid to touch.

Which security headers does a WordPress site need?

HeaderWhat it protects againstSafe to switch on?
Strict-Transport-Security (HSTS)Visitors being downgraded from HTTPS to HTTPYes, once the whole site works on HTTPS
Content-Security-Policy (CSP)Injected scripts and cross-site scriptingOnly after testing
X-Frame-OptionsClickjacking, where your site is loaded in a hidden frameYes, unless you embed your own pages elsewhere
X-Content-Type-OptionsBrowsers guessing a file's type and running it as scriptYes
Referrer-PolicyLeaking full page URLs to other sitesYes
Permissions-PolicyPages or embeds using camera, microphone or location without needYes, after listing the features you use

The plugin also covers X-XSS-Protection, X-Permitted-Cross-Domain-Policies and Feature-Policy, the older name for Permissions-Policy, because some scanners and older browsers still look for them.

How do you check which headers your site sends?

Use my free HTTP Security Header Scanner. It fetches your headers on the server, which matters because a browser cannot read another site's response headers. It grades the site from A+ to F, shows each header's status and exact value, explains what it protects against and gives a step-by-step fix. Each finding links to an article in my 15-part series on individual headers.

If you prefer the terminal:

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

Every header that does not appear is missing.

What are the ways to add security headers in WordPress?

MethodGood forWatch out for
.htaccess on ApacheDevelopers on Apache hostingA typo can take the whole site down
Nginx server blockDevelopers with server accessNeeds a reload, and not possible on many managed hosts
A WordPress pluginSite owners and agencies on any hostCheck the host is not already sending the same headers

For Apache, the safe trio looks like this:

apache
<IfModule mod_headers.c>
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set X-Content-Type-Options "nosniff"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

On Nginx the equivalent is an add_header ... always; line per header inside the server block.

How does the HTTP Security Header plugin work?

After you install it, the settings live under Settings > Security Headers. It works on WordPress 5.0 and above.

  • It sends headers from WordPress, not the web server, so it is portable across Apache, Nginx and managed hosts where you have no config access.
  • Each header has its own settings with defaults that are safe to switch on.
  • Values are validated before saving.
  • It falls back instead of breaking. A bad Content-Security-Policy or a mistyped frame option cannot lock you out of your own dashboard, because the plugin falls back to a working value.

That last point matters most. A security plugin that breaks a site gets switched off and forgotten. One that cannot break the site stays on. I published it to WordPress.org in November 2024 and have shipped updates through version 3.1. Agencies I work with install it as a standard part of a build, and I run it on stores such as Sun Shoppers.

If you use page caching at the server or CDN level, re-scan after switching headers on, because some cache layers serve stored pages with their own headers.

How do you add Content-Security-Policy without breaking the site?

CSP tells the browser which domains may supply scripts, styles, images, fonts and frames. It is the most powerful header and the easiest to get wrong.

  1. 1

    List what the site loads

    Analytics, Google Tag Manager, HubSpot or other CRM scripts, fonts, video embeds, payment widgets and chat tools. Each one needs its domain allowed.

  2. 2

    Start in report-only mode

    Send Content-Security-Policy-Report-Only first. The browser reports what it would block without blocking anything.

  3. 3

    Tighten in steps

    Allow what is legitimate, remove what is not, and keep checking the browser console.

  4. 4

    Test the important paths

    Forms, checkout, logins and the WordPress admin, on desktop and mobile.

  5. 5

    Enforce

    Switch to the enforcing header once a full test pass shows nothing legitimate is blocked.

Sites that load a lot through Google Tag Manager need extra care. On Ravens Ait, for example, enquiry forms sync to HubSpot through Tag Manager, so every domain in that chain has to be allowed.

What else should you harden besides headers?

Headers are one layer. On client sites I also set up:

  • Two-factor login with Wordfence, as on Sun Shoppers.
  • Off-site backups, such as UpdraftPlus to Google Drive.
  • An activity log, such as WP Activity Log on Samko Holdings.
  • A supported PHP version. Two of my 2025 client sites moved from PHP 8.0 to 8.3, which also fixed a form bug.
  • Fewer plugins. Every unused plugin is weight and attack surface. I removed a leftover WooCommerce install from the Raasa launch page for that reason.

For high-stakes sites, the biggest single gain is not serving WordPress publicly at all. The Janssen Neuroscience microsite was served statically, which removed the live database and admin from the public surface.

Need headers set up, or a plugin hardened for your own product? That falls under my custom WordPress plugins and maintenance work.

Frequently asked

Do security headers help SEO?+

Not directly. They protect your visitors and your site. HSTS does make sure every visit uses HTTPS, which you want anyway.

Can security headers break my WordPress site?+

Most are safe to switch on. Content-Security-Policy and X-Frame-Options can break embeds, analytics or the admin if set too strictly, which is why my plugin validates values and falls back to a working setting.

My host says it adds security headers. Do I still need a plugin?+

Scan the site first. If the host already sends the headers you need, do not add them twice, because duplicate headers with different values can conflict.

Is X-XSS-Protection still needed?+

Modern browsers have dropped the filter it controlled, and Content-Security-Policy is the real protection against cross-site scripting. Some scanners still check for it, so the plugin can send it.

Does the plugin work on Nginx and managed hosting?+

Yes. It sends headers from WordPress itself rather than from the web server, so it works on Apache, Nginx and managed hosts where you have no access to server configuration.

Mohit Goyal

Written by Mohit Goyal

Senior Web Developer in Gurugram, India. 100+ fast, SEO-friendly sites shipped in 4+ years with Next.js, React and WordPress, including the procol.ai rebuild. Send me your next project.

Keep reading

Let's build

Have a site that needs to be fast, rank and convert?

Open to Work. Usually replies within a day.