An updated WordPress core, theme, and plugins do not eliminate all risks related to browser behavior. Incorrectly configured HTTP headers can leave a site exposed to clickjacking, MIME type spoofing, unnecessary URL disclosure in the Referer header, and the use of browser capabilities that are not required.
Basic security headers can be added at the web server level. This is generally more reliable than installing a separate plugin for every header, but the changes must be tested—especially when the site uses Elementor, AJAX forms, popups, video, maps, payment services, or other third-party widgets.
What the Main Security Headers Do
Security HTTP headers tell the browser how to process a page and its resources. They do not fix WordPress vulnerabilities and do not replace updates, backups, or access control, but they reduce the number of attack scenarios available to an attacker.
For most WordPress sites, it makes sense to start with four basic headers: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy.
- X-Content-Type-Options: nosniff prevents the browser from guessing a file’s MIME type. This reduces the risk of a resource being executed in a context other than the one for which it was loaded.
- X-Frame-Options: SAMEORIGIN allows pages to be opened in a frame only within the same origin. The header protects against many clickjacking scenarios.
- Referrer-Policy: strict-origin-when-cross-origin limits the transfer of the full URL when a user navigates to another site, while preserving more information for navigation within the same origin.
- Permissions-Policy restricts a page’s access to browser features such as the camera, microphone, and geolocation.
Configuring Headers in Apache
In Apache, headers are usually added to the VirtualHost configuration or to the .htaccess file if the hosting environment allows mod_headers. The always parameter is important because it adds headers not only to successful responses, but also to some error responses and redirects.
Place the rules in a context where they are not duplicated by other configurations or plugins. After making changes, check the configuration syntax and restart or reload Apache according to your hosting provider’s procedures.
- Create a backup of .htaccess before editing it.
- If the server returns a 500 error after the change, immediately remove the latest block and check the error log.
- Do not add the same header simultaneously in Apache, Nginx, a CDN, and a plugin without checking the result: duplicates can cause unpredictable behavior.
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=()"
Configuring Headers in Nginx
In Nginx, the add_header directive is used for this purpose. The always parameter allows a header to be added to a broader range of responses, rather than only to standard successful responses. The exact placement depends on the server configuration: it may be in the server block or in the relevant location block.
After editing the configuration, check the syntax first and only then reload Nginx. On managed hosting, access to the configuration may be restricted, so changes may need to be made through the hosting panel or by contacting the server administrator.
- Check whether the CDN or reverse proxy overwrites the headers.
- If Nginx runs in front of Apache, determine which layer actually generates the response.
- Do not copy Apache directives into the Nginx configuration: their syntax is different.
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;
What to Consider When Working with Elementor
Elementor and its additional widgets may use JavaScript, AJAX requests, iframes, web fonts, external images, video services, and other domains. Basic headers generally do not cause problems, but certain settings can change how the editor or published page behaves.
X-Frame-Options: SAMEORIGIN prevents a page from being embedded on another domain. If the site must open inside an external CRM, LMS, mobile wrapper, or another service, check this header separately. Do not weaken it unless you clearly understand who is allowed to embed the page.
Permissions-Policy does not prevent ordinary contact forms from working. However, it can affect features that genuinely require the camera, microphone, or geolocation. For video conferencing, camera-based photo uploads, or geolocation services, configure the rules specifically instead of leaving a global restriction in place.
- Check that the Elementor editor opens and saves changes.
- Test forms, popups, menus, sliders, and AJAX filters.
- Check pages containing video, maps, iframes, and third-party widgets.
- Make sure theme and plugin resources load without errors in the browser console.
Why You Should Not Start with Content-Security-Policy Without Testing
Content-Security-Policy, or CSP, can significantly restrict the execution of scripts and the loading of styles, fonts, images, iframes, and connections to third-party APIs. It is one of the most powerful headers for protection against XSS, but also one of the most difficult to maintain.
An overly strict CSP can break the Elementor editor, inline scripts, analytics, CAPTCHA, payment modules, forms, and third-party widgets. There is no universal value in WordPress that is safe for every site.
If CSP is required, start with Content-Security-Policy-Report-Only. It reports violations in the browser console or a reporting system without blocking resources. After analyzing the site’s dependencies, the policy can be introduced gradually, preferably on a staging copy of the site.
- Do not blindly add unsafe-inline or unsafe-eval just to remove errors: this weakens the protection.
- Create a list of the domains actually used for scripts, fonts, images, APIs, and iframes.
- After every change, check not only the homepage but also the editor, forms, cart, login, and thank-you pages.
How to Check Whether the Headers Are Working
You need to check the actual HTTP response, not just the configuration text. Open the site in a browser, use the developer tools, and view the Network tab for the main HTML document. The required values should appear in the Response Headers section.
For an additional check, you can use the curl command with headers. Check both the homepage and pages with forms, the admin area, static resources, and responses after redirects. If the site uses a CDN, perform the check externally through the public domain.
- Make sure each header is present only once.
- Check the browser console for messages about blocked resources or policy violations.
- Test the site with the cache disabled and after clearing the CDN cache.
- Check the mobile version, authentication, forms, popups, and interactive elements.
- After deployment, monitor server logs and user reports.
curl -I https://example.com/
Additional Headers and Common Mistakes
After the basic set, consider HSTS—Strict-Transport-Security. It forces the browser to use HTTPS, but should be added only after the entire site has been migrated to HTTPS. All subdomains, resources, and service addresses must work correctly over a secure connection. Do not enable a long duration or the preload parameter without separately checking the consequences.
The legacy X-XSS-Protection header is not a modern replacement for CSP and generally should not form the foundation of your protection. Also, avoid blindly adding dozens of headers from ready-made checklists: incorrect or outdated rules make troubleshooting more difficult and can damage site functionality.
- Do not confuse X-Frame-Options with the CSP frame-ancestors directive: they address similar, but not identical, tasks.
- Do not treat the green HTTPS padlock as proof of complete WordPress security.
- Do not test changes directly on the production site if a staging copy is available.
- Do not forget core, theme, and plugin updates, strong passwords, 2FA, backups, and minimum access privileges.
Frequently asked questions
Are HTTP headers enough to secure WordPress?
No. They reduce certain browser-related risks, but they do not protect against a vulnerable plugin, a stolen password, server misconfiguration, or malicious code. Updates, backups, access control, and monitoring are also required.
Can these headers be added through a WordPress plugin?
Technically, yes, but for basic rules it is often more reliable to configure them on the web server or proxy level. Avoid duplication and verify which component actually sends the header.
Will X-Frame-Options: SAMEORIGIN break Elementor?
Usually not, provided the site does not need to be embedded on another domain. Problems may occur with external iframe scenarios or integrations, so they should be checked separately.
Why did forms or widgets stop working after CSP was added?
CSP may have blocked a script, style, font, iframe, or request to a third-party domain. Review the browser console messages, temporarily use Report-Only mode, and gradually create a policy for the site’s actual dependencies.
Conclusion
For most WordPress sites, a practical starting point is to add X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy at the Apache or Nginx level. Then verify the actual server responses and all critical site functions.
Configure security in stages: start with basic headers, then add HSTS and CSP if needed. Test changes on a copy of the site, monitor the browser console, and remember that headers are part of hardening—not a replacement for updates and secure administration.