Security Headers in WordPress add an extra layer of protection against common attacks without requiring changes to your application’s code.
When it comes to securing websites or web applications, there are several aspects to consider. A good place to start strengthening the security of WordPress sites is by adding Security Headers.
What Are Security Headers in WordPress?
Security Headers are HTTP response headers that instruct the browser how to behave when handling your site’s content. They help prevent various attacks – including clickjacking, cross-site scripting (XSS), and protocol downgrade attacks – by restricting what the browser is allowed to do.
In this post, we will go through the most important Security Headers and see how to add them to your site, whether you are running an Apache server or an NGINX server.
It is important to note that the settings presented in this post may not be suitable for every site. You should test each header individually and check for console errors after every change.
Incorrect Security Header configuration can cause a 500 error or break parts of your site. Always back up your .htaccess or nginx.conf file before making changes, and make sure you have FTP or file manager access so you can revert if the site goes down.
For a deeper reference on each header and its parameters, see the MDN Web Docs on HTTP Security Headers.
Recommended Security Headers to Add
Here are the recommended Security Headers for WordPress sites. Add them one at a time and test after each change.
A. HTTP Strict Transport Security (HSTS)
HTTP Strict Transport Security (HSTS) tells browsers to only connect to your site over HTTPS, never over plain HTTP. This prevents protocol downgrade attacks and cookie hijacking.
Your site must already have a valid SSL certificate and be fully working on HTTPS before enabling HSTS.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;The max-age=31536000 value means the browser will remember this policy for one year. The includeSubDomains directive applies the policy to all subdomains as well – only use this if all your subdomains support HTTPS.
If you are setting up HSTS for the first time, start with a short max-age (e.g., 300 for 5 minutes) and gradually increase it once you confirm everything works.
B. X-Frame-Options
X-Frame-Options protects users from clickjacking attacks. Without it, an attacker could load your site inside an iframe on their own page and trick users into clicking on hidden elements.
This is particularly dangerous when the user is logged into an area on your site that requires authentication.
<IfModule mod_headers.c>
Header always append X-Frame-Options SAMEORIGIN
</IfModule>add_header X-Frame-Options "SAMEORIGIN" always;The SAMEORIGIN value allows your own site to embed itself in iframes (useful for previews in the WordPress admin) but blocks other domains from doing so.
C. X-Content-Type-Options
Setting the X-Content-Type-Options header prevents the browser from guessing (or “sniffing”) the MIME type of a file. Without it, a browser might interpret a malicious file as JavaScript or HTML.
Header set X-Content-Type-Options nosniffadd_header X-Content-Type-Options "nosniff" always;This is one of the simplest headers to add and has virtually no risk of breaking your site.
D. Content-Security-Policy
The Content Security Policy (CSP) header is the most powerful – and the most complex – security header. It tells the browser exactly which sources are allowed to load scripts, styles, images, fonts, and other resources.
A strict CSP can effectively prevent XSS attacks. However, WordPress themes and plugins rely heavily on inline scripts and styles, which makes a strict policy difficult to implement without breaking functionality.
A realistic starting point for most WordPress sites:
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' https: data:; font-src 'self' https: data:; connect-src 'self' https:; frame-ancestors 'self';"add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' https: data:; font-src 'self' https: data:; connect-src 'self' https:; frame-ancestors 'self';" always;The unsafe-inline and unsafe-eval directives weaken CSP protection, but they are currently required for most WordPress sites to function. WordPress core, Gutenberg, and many plugins depend on inline scripts. Removing these directives will likely break your site. Use them as a practical compromise and tighten the policy over time as WordPress improves its CSP support.
If you want to test your CSP before enforcing it, use Content-Security-Policy-Report-Only instead. This logs violations in the browser console without blocking anything, so you can see what would break.
E. Referrer-Policy
The Referrer-Policy header controls how much referrer information the browser sends when navigating from your site to another.
Header set Referrer-Policy "strict-origin-when-cross-origin"add_header Referrer-Policy "strict-origin-when-cross-origin" always;The strict-origin-when-cross-origin value sends the full URL for same-origin requests but only the origin (domain) for cross-origin requests. This is a good balance between privacy and functionality – it preserves analytics data while not leaking full page paths to external sites.
F. Permissions-Policy
The Permissions-Policy header (formerly Feature-Policy) controls which browser features and APIs your site can use, such as the camera, microphone, geolocation, and payment APIs.
Most WordPress sites do not need access to these features, so disabling them reduces your attack surface:
Header set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;The empty parentheses () disable each feature entirely. If your site uses any of these features (e.g., a store locator that needs geolocation), adjust accordingly: geolocation=(self).
G. X-XSS-Protection (Deprecated)
The X-XSS-Protection header was designed to activate the browser’s built-in XSS filter. However, this header is now deprecated and has been removed from all modern browsers (Chrome removed it in version 78, Firefox never supported it, and Edge removed it in version 17).
The XSS filter was found to have security flaws of its own – it could be exploited to create cross-site information leaks. The recommended approach is to either omit this header entirely or explicitly disable it:
Header set X-XSS-Protection "0"add_header X-XSS-Protection "0" always;Use Content-Security-Policy instead for XSS protection. If you previously had X-XSS-Protection: 1; mode=block in your configuration, it is safe to remove it.
Complete Configuration Example
Here is a complete .htaccess configuration with all recommended headers:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
Header set X-Content-Type-Options nosniff
Header always append X-Frame-Options SAMEORIGIN
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' https: data:; font-src 'self' https: data:; connect-src 'self' https:; frame-ancestors 'self';"
</IfModule>If you encounter a 500 error after adding these headers, try a minimal configuration first and add headers one by one to identify which one causes the issue:
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000" env=HTTPS
Header set X-Content-Type-Options nosniff
Header always append X-Frame-Options SAMEORIGIN
Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>Checking Your Security Headers
After adding the headers, verify they are working correctly. You can test your site on securityheaders.com to get a grade and see which headers are present.

You can also check headers in your browser’s Developer Tools. Open the Network tab, click on the main document request, and look at the Response Headers section to confirm your headers are being sent.
FAQs
Common questions about WordPress security headers:
Summary
Security headers are one of the easiest ways to improve your WordPress site’s security posture. Start with the low-risk headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy), then add HSTS once you are confident your HTTPS setup is solid, and finally work on Content-Security-Policy and Permissions-Policy.
The key rule: add one header at a time, test, and keep a backup. If something breaks, you can always revert.
If you have questions or want to suggest improvements, feel free to leave a comment below.


Thanks! Very helpful