WordPress hardening guide illustration with lock, security audit, headers, and best practices.

WordPress Hardening: 9 Real Fixes That Took Me From D to A+

WordPress hardening means reducing the number of ways an attacker can abuse your website while keeping the site usable, maintainable, and recoverable. I recently applied that principle to HackersGhost after two independent security checks returned D-level results. After working through the problems one by one, SecurityHeaders reached A+, while MDN HTTP Observatory reached C with 11 of 12 tests passing.

That difference between A+ and C became one of the most useful lessons in this entire WordPress hardening project. Security scores are helpful, but they are not absolute measurements of whether a website is “secure.” One remaining test can heavily influence a score even when most of the underlying controls are working correctly.

This is not a theoretical WordPress hardening guide. I did every test on my own production cybersecurity website, checked the actual HTTP responses, broke a few things along the way, fixed them again, and learned why blindly copying a security-header template from the internet can create more problems than it solves.

If practical experiments like this are your kind of reading, you can join my HackersGhost newsletter. I share the things that worked, the things that did not, and the occasional moment when a security improvement politely informs me that WordPress would now prefer not to function.

Security testBeforeAfter hardening
SecurityHeadersD-level resultA+
MDN HTTP ObservatoryD / 30C / 50
MDN tests passed10 / 1211 / 12

Key Takeaways From My WordPress Hardening Project

  • A WordPress security audit needs more than a plugin. Hosting, headers, CDN behavior, WordPress, third-party scripts, caching, and browser security all interact.
  • SecurityHeaders moved from D to A+ after I improved headers and replaced a weak CSP setup with a much stricter policy.
  • MDN still gives the site C / 50 because its remaining Subresource Integrity test alone costs 50 points.
  • I replaced script-src ‘unsafe-inline’ with 32 SHA-256 hashes for known inline scripts.
  • I used Report-Only CSP first, because enforcing a policy before testing it is an excellent way to discover how many plugins your website actually depends on.
  • I discovered UserWay was loading twice and removed the duplicate script.
  • I added SRI to a stable Writesonic script, but deliberately did not force SRI onto dynamic third-party scripts that could break after a vendor update.
  • A frontend CSP also broke Gutenberg, so I excluded /wp-admin/ from that custom policy without weakening the public site.

Why My WordPress Hardening Started With Two D Grades

There is something mildly awkward about running a cybersecurity website and watching two security scanners hand it a D. My first reaction was not panic. It was curiosity. A grade is useful only when you understand what created it.

I used SecurityHeaders to review the response headers and MDN as my second reference point. The two services score websites differently, which later became extremely important.

A proper WordPress security audit therefore became my starting point. I looked at HTTPS redirection, HSTS, Referrer-Policy, frame protection, MIME sniffing protection, CSP, external JavaScript, PHP disclosure, caching, my CDN, Defender, and the behavior of several plugins.

HackersGhost Note: A D grade does not tell you which attacker is outside your door. It tells you which controls deserve inspection. That distinction saved me from randomly installing another security plugin and hoping the dashboard would become greener.

WordPress hardening shield illustration for security guide, audit, headers, and best practices.

WordPress Hardening Fix 1: Untangling HTTPS and CSP

One of the stranger findings came from my hosting setup. Hostinger has an HTTPS enforcement option, and on my configuration it was also causing this header to appear:

Content-Security-Policy: upgrade-insecure-requests

That directive is not inherently bad. The problem was that I wanted to manage a complete Content Security Policy myself. Having the hosting layer inject its own limited CSP made troubleshooting unnecessarily confusing.

I verified the behavior both through the public CDN and directly against the origin server. Static files showed the same header, which proved WordPress itself was not responsible. Hostinger support later confirmed that the HTTPS feature was the source in my setup.

I kept HTTPS enforcement, but moved responsibility to my own .htaccess redirect instead:

# BEGIN Custom Force HTTPS
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# END Custom Force HTTPS

After disabling Hostinger’s HTTPS switch, HTTP requests still returned a proper 301 redirect to HTTPS, while the unwanted CSP disappeared. SSL remained active. WordPress hardening is often less about adding another layer and more about deciding which layer should own each control.

WordPress Hardening Fix 2: Improving Security Headers

The next stage focused on WordPress security headers. Defender already handled several of them, so I improved the existing configuration instead of replacing it with yet another plugin.

I changed Referrer-Policy to strict-origin-when-cross-origin, kept X-Frame-Options on SAMEORIGIN, enabled X-Content-Type-Options, and increased HSTS to a one-year max age. I deliberately left HSTS preload disabled because preloading is a larger operational commitment than simply enabling HSTS.

I also kept Permissions Policy enabled. These changes moved SecurityHeaders significantly upward. One earlier policy value had been enough to prevent the best grade, which is another reason I prefer reading the scanner details rather than staring at the letter.

HackersGhost Note: My WordPress security best practices rule is simple: every header needs a reason. “I found this giant header block on a forum” is not a reason. That is a hobby involving copy and paste.

WordPress Hardening Fix 3: Hiding PHP Version Details

During the WordPress security audit, the server exposed an X-Powered-By header containing the PHP version. Hiding a version number does not magically patch PHP, but unnecessary software disclosure gives an attacker one less piece of free reconnaissance.

Changing expose_php in .user.ini did not remove the header in my environment. The effective fix was performed at the HTTP-header level:

# BEGIN Hide PHP Version
<IfModule mod_headers.c>
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
# END Hide PHP Version

I then tested both the public CDN response and the origin. The header was gone from both.

I also removed an additional headers plugin after confirming the site kept its strong SecurityHeaders grade without it. Fewer overlapping security tools mean fewer places where one setting can quietly override another.

Nikto Web Server Scanner: 7 Useful Checks for Beginners

See how Nikto can reveal server-side configuration issues and outdated web components inside a controlled security test.

WordPress Hardening Fix 4: Building CSP in Report-Only Mode

Content Security Policy became the largest part of this WordPress hardening exercise. CSP controls which sources a browser may use for scripts, styles, images, fonts, frames, connections, workers, forms, and other resources.

My first real policy was deliberately configured as Content-Security-Policy-Report-Only. That meant the browser could show me what would have been blocked without actually breaking the website.

I started with a restrictive baseline such as default-src 'self' and then watched the browser console while loading the homepage and important pages. The site revealed exactly which third-party services it relied on.

Those included Cloudflare challenges, UserWay, Google services, Google Tag Manager, advertising scripts, Ahrefs analytics, WPMU DEV analytics, Writesonic, Google Fonts, WordPress assets, and other required endpoints.

This is why I would never recommend copying my complete CSP into another website. Your CSP should describe your site, not mine. A WooCommerce store, membership site, analytics-heavy publication, or simple personal blog can require completely different sources.

HackersGhost Note: Report-Only mode turned the browser console into my shopping list. Every blocked resource had to answer one question: “Do I actually need you?” External JavaScript becomes much more interesting when it has to introduce itself.

WordPress Hardening Fix 5: Removing unsafe-inline From Scripts

The biggest CSP improvement came from removing 'unsafe-inline' from script-src. Allowing arbitrary inline JavaScript weakens a CSP because injected script can potentially run under the same permission.

WordPress complicated the process because my pages legitimately contained many inline scripts. Instead of allowing every inline script, I generated SHA-256 hashes for the exact executable blocks that belonged on the site.

I tested several representative pages: the homepage, a review, my contact page, and a technical tutorial. My improved scanner ignored non-executable JSON and structured-data blocks and handled speculation rules separately. The result was 32 unique SHA-256 hashes.

I fetched the homepage repeatedly and compared the hash sets before enforcing anything. They remained stable. Only after Report-Only testing showed no relevant CSP violations did I switch the policy to real enforcement.

The live script-src then contained those hashes and no 'unsafe-inline'. I still allow 'unsafe-inline' in style-src, because modern WordPress themes and blocks make CSS hardening a separate, more complicated project.

This single change improved the MDN result from D / 30 to C / 50 and moved the CSP test itself into the passing column.

WordPress Hardening Fix 6: Auditing Third-Party Scripts

The CSP work also exposed something I was not specifically looking for: UserWay was being loaded twice.

I found one UserWay script manually inserted through my header code and another generated automatically by the UserWay plugin. Removing the manual copy reduced the widget to a single load.

That cleanup immediately demonstrated another CSP lesson. The UserWay button appeared, but clicking it produced a blocked page. The widget itself was allowed, while its interface needed permission to load inside a frame.

I expanded frame-src only for the required UserWay domains. After clearing LiteSpeed and CDN caches, the widget worked normally again.

This became one of my favorite parts of the WordPress hardening guide because it shows the difference between “the script loads” and “the feature works.” Security testing needs real interaction, not just a green homepage.

WordPress hardening guide illustration with security audit, headers, checklist, and best practices icons.

WordPress Hardening Fix 7: Adding SRI Where It Made Sense

Subresource Integrity, or SRI, lets a browser verify that an external script still matches a cryptographic hash specified by the page. If the content changes, the browser refuses to execute it.

I tested several third-party scripts by downloading them repeatedly and comparing SHA-384 hashes. Writesonic returned the same hash three times and also provided the required cross-origin permission. That made it a reasonable SRI candidate.

I added an integrity attribute and crossorigin="anonymous" to that script, cleared the caches, and verified the live HTML.

Ahrefs produced a stable hash during my tests but did not expose the CORS behavior I needed for cross-origin SRI. Google Tag Manager, AdSense, reCAPTCHA, Cloudflare Turnstile, and similar vendor scripts are also poor candidates for blindly pinning a static hash because the provider can update them independently.

That is where I deliberately stopped chasing the scanner score. A stale SRI hash can block a legitimate vendor update and break analytics, advertising, accessibility, or verification. The final MDN report still deducts 50 points for SRI, but I prefer a maintainable site over a decorative 100/100.

HackersGhost Note: A scanner is allowed to want perfection. It does not have to answer the support email when your CAPTCHA stops working.

WordPress Hardening Fix 8: Keeping Frontend CSP Out of wp-admin

Just when the public site looked stable, changing WordPress back to the Block Editor exposed another problem. Gutenberg claimed JavaScript was disabled.

JavaScript was not disabled. My custom frontend CSP was also being sent to /wp-admin/, where Gutenberg uses its own inline JavaScript that was not part of the 32 frontend hashes.

The solution was not to weaken script-src globally. I marked /wp-admin/ requests with an environment variable and explicitly removed my custom CSP header for those requests:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/wp-admin/ [NC]
RewriteRule ^ - [E=skip_custom_csp:1]
</IfModule>

<IfModule mod_headers.c>
Header always set Content-Security-Policy "..." env=!skip_custom_csp
Header always unset Content-Security-Policy env=skip_custom_csp
</IfModule>

I verified the change with curl. Requests to /wp-admin/ no longer received my custom frontend CSP, while the public homepage still returned the full policy.

Gutenberg started working again, Spectra remained available for the posts that use its blocks, and the public site retained the stronger policy.

This was probably the clearest example of WordPress security best practices beating score chasing: apply the strict control where it belongs instead of forcing one policy onto two very different application contexts.

WordPress Hardening Fix 9: Keeping the Other Security Layers

The final fix was not one magic setting. It was making sure the rest of the security stack still supported the new configuration.

Defender handles login protection, 404 detection, security headers, firewall features, banned usernames, suspicious user agents, and other hardening controls. I use 2FA for administration and keep the WordPress core, theme, and plugins updated.

Hostinger adds another layer through its CDN, WAF, backups, and recurring vulnerability checks. I currently use the higher CDN security setting because the site remained functional during testing.

LiteSpeed caching remains enabled, but every important CSP change is followed by a full cache purge because stale HTML can make security troubleshooting look supernatural.

I also keep regular backups. WordPress hardening without recovery planning is incomplete. Security controls reduce probability and impact; backups give you a path back when prevention loses an argument.

How to Use Burp Suite: Avoid 7 Common Beginner Mistakes

Learn how Burp Suite helps you inspect requests, responses, cookies, parameters, and web security behavior without turning your first session into packet-shaped confetti.

Why SecurityHeaders Gives Me A+ While MDN Gives Me C

This is where the numbers become genuinely interesting.

SecurityHeaders now awards HackersGhost an A+. The public site sends the expected protection for framing, MIME sniffing, HSTS, referrers, permissions, and the enforced Content Security Policy.

MDN reports C / 50 while showing 11 of 12 tests passed. Its Content Security Policy test passes. HSTS passes. Redirection passes. Referrer Policy passes. CORS passes. X-Content-Type-Options passes. Frame protection passes.

The remaining Subresource Integrity test alone produces a -50 score.

That makes the letter C look much worse than the details actually are. I still value the warning because it identifies third-party dependency risk. I simply do not treat it as an instruction to pin every dynamic vendor script with an SRI hash.

WordPress hardening is risk management, not a school report. A working A+ and C combination with 11 passing MDN tests can be healthier than a brittle configuration built only to impress a scanner.

My Practical WordPress Security Checklist

If I repeated this WordPress hardening process on another site, this is the order I would use. It keeps the work understandable and makes rollback easier.

  1. Create a backup first. Especially before editing .htaccess, headers, caching, or login behavior.
  2. Run a WordPress security audit. Record the starting state before making changes.
  3. Verify HTTPS redirects. Avoid overlapping redirect systems unless you know exactly what each one does.
  4. Review WordPress security headers. HSTS, framing, MIME protection, referrer behavior, permissions, and CSP should fit the site.
  5. Reduce unnecessary disclosure. Remove redundant plugins and avoid exposing software versions when there is no benefit.
  6. Build CSP in Report-Only mode. Inventory legitimate resources before enforcement.
  7. Remove unsafe script permissions where practical. Use hashes or nonces only when you understand their maintenance impact.
  8. Test real functionality. Forms, cookie consent, accessibility widgets, ads, editors, login, and administrative pages matter more than a homepage screenshot.
  9. Re-test after every major change. Browser console, network panel, curl, scanners, and normal usage each reveal different problems.
  10. Plan maintenance. Plugin or theme updates can change inline scripts and invalidate CSP hashes.

HackersGhost Note: The best WordPress security checklist is the one you can repeat after the next plugin update. A configuration you are afraid to touch eventually becomes archaeological evidence.

My Testing Workflow From Parrot OS

I did much of the verification from Parrot OS rather than relying entirely on browser plugins or WordPress dashboards. I run Parrot mainly inside VMware on a second-hand HP EliteBook that I upgraded from 16 GB to 32 GB of RAM.

The extra memory is unnecessary for checking a header with curl, but it gives me a comfortable platform for running multiple security VMs and vulnerable lab systems while keeping production testing separate.

For this WordPress hardening project, simple tools were often the most useful. Commands such as curl -I, grep, and repeated cache-busting requests let me compare the public CDN with the origin and verify whether a change was genuinely live.

That is one reason I enjoy defensive work alongside ethical hacking. The same habit applies on both sides: observe first, form a hypothesis, test it, and verify the result.

WordPress hardening guide collage with security audit, headers, checklist, and best practices icons.

Where Endpoint Security Fits Into WordPress Hardening

A hardened website can still be compromised if the administrator’s own computer is infected and an attacker steals session cookies, credentials, browser data, or FTP and SSH access.

That is why I treat endpoint security as a supporting layer around my WordPress security best practices. It does not replace a firewall, CSP, updates, 2FA, or secure hosting, but it protects a different part of the path into the site.

Malwarebytes is one option for malware and endpoint protection. If you are already reviewing the security of the computer you use to administer WordPress, it can fit into the wider picture without pretending to be a WordPress security plugin.

The button below is my affiliate link. I may receive a commission at no extra cost to you, which helps support the independent testing and lab work behind HackersGhost.

A Cybersecurity Book That Fits This Learning Path

If you are new to security, How Cybersecurity Really Works is a useful beginner-friendly introduction to how attackers operate and how defensive controls fit together.

I like that broader perspective because WordPress hardening makes more sense when you understand why controls exist. CSP, WAF rules, authentication, browser protections, patching, and monitoring are not isolated tricks. They address different parts of the attack surface.

The link below is an Amazon affiliate link, so I may earn a small commission if you buy through it.

Gobuster Tutorial for Beginners: Find Hidden Directories Safely

Discover how Gobuster helps uncover hidden directories and files during authorized testing—and why exposed paths can become part of a broader WordPress hardening review.

What This WordPress Hardening Case Study Taught Me

The headline version is easy: WordPress Hardening: 9 Proven Fixes From D to A. The real story was more useful than the headline.

I learned that a CDN can inject a header you did not expect, an accessibility widget can be loaded twice, a correct CSP can still block legitimate UI behavior, cache can make yesterday’s configuration look like today’s, and a technically stronger policy can break your editor if you apply it to the wrong context.

I also learned to trust verification more than assumptions. If I changed a header, I checked it. If I thought a script was stable, I hashed it repeatedly. If a plugin stopped working, I looked at the network and CSP behavior instead of immediately whitelisting the internet.

Most importantly, this WordPress hardening exercise changed how I think about security scores. I still want good scores. They are useful indicators and excellent ways to discover mistakes. But the score is a symptom of the configuration, not the objective.

HackersGhost Note: I started by trying to improve two D grades. I finished with a better understanding of how browsers, WordPress, LiteSpeed, Hostinger, plugins, third-party JavaScript, CSP, and SRI interact. The grades were useful. The troubleshooting was the education.

Final Thoughts on WordPress Hardening

WordPress hardening does not make a website impossible to hack. Nothing useful connected to the internet deserves that promise. What good hardening does is reduce unnecessary exposure, make common attacks harder, limit the damage of some failures, and improve your ability to detect and recover from problems.

HackersGhost now has stronger WordPress security headers, an enforced hash-based CSP on the public site, SRI where I consider it maintainable, reduced information disclosure, layered firewall and login protection, HTTPS enforcement, HSTS, backups, and a clearer understanding of the external scripts the site depends on.

The final SecurityHeaders A+ looks satisfying, but the MDN C is equally useful because it reminds me that third-party JavaScript remains a security dependency. That is a realistic result, not a failure.

If you use this as a WordPress hardening guide, take the process rather than blindly copying the configuration: audit, back up, change one thing, test, verify, and keep the site maintainable. The green letter is nice. A website that still works after you earn it is nicer.

WordPress hardening guide lock illustration for security audit, headers, and troubleshooting.

Frequently Asked Questions

What is WordPress hardening

Does an A+ SecurityHeaders score mean WordPress is fully secure

Why does MDN give my hardened site a C

Should WordPress use a Content Security Policy

Why remove unsafe-inline from script-src

Should every external WordPress script use SRI

Can WordPress security headers break plugins

Why did Gutenberg stop working after CSP hardening

What should I check first in a WordPress security audit

Some links in this article are affiliate links. If you use them, I may earn a small commission — at no extra cost to you. I only recommend tools I’ve actually tested inside my own cybersecurity lab. Read the full disclaimer.

In many cases, these links unlock better deals than you’ll find on your own.
No paid reviews. No sponsored opinions. Just real testing and real setups.

If you decide to use them, you’re not just getting a discount — you’re helping keep this lab running.

Leave a Reply

Your email address will not be published. Required fields are marked *