Most WordPress sites aren't attacked by sophisticated hackers. They're attacked by automated bots scanning for known vulnerabilities — outdated plugins, exposed login endpoints, weak file permissions, and misconfigured REST APIs. The attack isn't personal. It's systematic.
That's what makes the "my host keeps me secure" assumption so dangerous. Your host secures the server infrastructure — DDoS mitigation, network-level filtering, physical security. Nobody — unless you've explicitly set this up — is securing the application layer. And that's exactly where WordPress gets compromised: the application layer, sitting fully exposed on a well-protected server.
Here are 10 security steps that actually close real attack vectors. Not checkbox theater. Not a "security plugin and call it done" approach. Real, layered hardening.
1. Lock Down wp-login.php Before Anything Else
Your WordPress login page is the most targeted URL on your domain. Automated credential-stuffing bots don't need to guess your password intelligently — they can hammer the endpoint thousands of times a minute until something gives.
The fix isn't just a strong password. Strong passwords help, but they don't stop the attack — they just raise the difficulty. You need to reduce access at the server level.
Via .htaccess hardening, restrict wp-login.php to specific IP addresses:
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from YOUR.IP.ADDRESS
</Files>
If you're on a dynamic IP, implement rate limiting at the firewall level instead. At minimum, use login attempt throttling. And while you're editing .htaccess, add this block to protect wp-config.php from direct access:
<Files wp-config.php>
Order Allow,Deny
Deny from all
</Files>
wp-config.php holds your database credentials, secret keys, and table prefix. It should never be web-accessible. These two .htaccess rules alone close down attack paths that automated scanners probe within minutes of a new site going live.
2. Enforce Two-Factor Authentication on All Admin Accounts
2FA is not optional for admin accounts. Full stop. A compromised admin credential gives an attacker complete site control — theme editor access (hello, PHP execution), plugin installation, new admin user creation, and direct database exposure via phpMyAdmin links.
Use WP 2FA or Wordfence Login Security. Configure it to enforce 2FA for all administrator and editor roles — not just the primary admin. One weak account in your user list is a sufficient entry point. Content injection attacks often enter through lower-privilege accounts and then escalate laterally, especially if your user role permissions aren't locked down.
Avoid SMS-based 2FA where possible. SIM-swapping attacks make SMS codes a weak second factor. Use an authenticator app — TOTP-based codes are far more resilient.
3. Install and Configure a Web Application Firewall
Most site owners conflate their host's firewall with WordPress application security. They're entirely different things. Your host's firewall protects the server. A Web Application Firewall (WAF) protects WordPress — inspecting and filtering HTTP/HTTPS requests before they reach PHP execution.
Wordfence runs as a plugin and gives you granular control over WordPress-specific threat signatures — blocking known malicious IPs, alerting on suspicious file changes, filtering bad actors by geographic origin, and maintaining a threat intelligence feed updated in near real-time. For most sites, Wordfence at the free tier handles the essentials.
Cloudflare WAF operates at the network edge, meaning attack traffic gets absorbed before it even reaches your origin server. For higher-traffic sites, this matters for both security and performance — your server load drops because Cloudflare is rejecting bad traffic at the CDN layer.
At minimum: enable a WAF with WordPress-specific rulesets. Check blocked requests weekly. A firewall you've set up once and never reviewed is a firewall you trust blindly, and blind trust is not a security posture.
4. Harden File Permissions the Right Way
Across dozens of WordPress audits, we consistently find file permissions that are either too open — making files writable by malicious processes — or incorrectly set in ways that interfere with plugin functionality and create diagnostic confusion.
The correct baseline for a standard WordPress installation:
- Directories: 755
- Files: 644
- wp-config.php: 440 or 400
You can set these in bulk using WP-CLI:
find /path/to/wordpress -type d -exec chmod 755 {} \;
find /path/to/wordpress -type f -exec chmod 644 {} \;
chmod 440 wp-config.php
Verify this after every major plugin update, server migration, or hosting environment change. Some managed hosting platforms auto-reset permissions during deployments. Some shared hosting control panels make files world-writable during certain operations. These aren't edge cases — they're common enough that a post-deployment permission check should be a fixed part of your workflow.
The /wp-content/uploads/ directory deserves specific attention. It should never execute PHP. If it does, an attacker who uploads a malicious file via a form submission vulnerability can execute arbitrary code server-side. Add this to your .htaccess inside the uploads directory:
<Files *.php>
Deny from all
</Files>
5. Disable XML-RPC Unless You Have a Specific Reason Not To
XML-RPC is a legacy remote publishing API that the vast majority of WordPress sites don't use — but attackers do. It allows credential-based authentication and supports batched requests, meaning an attacker can attempt thousands of username/password combinations in a single HTTP request. Standard login throttling doesn't catch this.
Unless you're using Jetpack with remote publishing features, or a mobile app that specifically requires it, disable XML-RPC entirely.
Via .htaccess hardening:
<Files xmlrpc.php>
Order Allow,Deny
Deny from all
</Files>
Or handle it cleanly through a security plugin. XML-RPC is enabled by default in every WordPress installation. Used by almost nobody running a typical business site. Exploited constantly. Disabling it takes five minutes and eliminates a persistent attack vector.
6. Audit Your REST API Exposure
This is one of the most overlooked application-layer exposures in WordPress. The REST API ships enabled by default and, without restrictions, exposes an endpoint at /wp-json/wp/v2/users that publicly enumerates every WordPress username on your installation.
That's not a theoretical vulnerability. That's a free directory of valid login targets, served on request to anyone who knows the URL.
Restrict unauthenticated REST API access to only the endpoints your site actually requires. For most content sites, anonymous users have no legitimate need to access the user endpoint. You can suppress it with a filter in functions.php, or through plugins like Disable REST API or Perfmatters.
While you're reviewing REST API exposure, also check what custom routes your installed plugins are registering. Plugin-registered REST endpoints sometimes lack proper authentication checks — a plugin vulnerability category that's appeared repeatedly in WordPress CVE disclosures. Use Query Monitor to inspect active REST routes during a site audit.
7. Update PHP — And Do Not Let It Stagnate
"If it's not broken, don't touch it" gets applied to PHP versions with alarming regularity. It's wrong. PHP releases follow published end-of-life dates. Once a version hits EOL, security patches stop — permanently. Attackers index known vulnerabilities in EOL PHP builds and run automated scans against sites that report old version signatures.
PHP 7.4 hit end-of-life in November 2022. PHP 8.0 went EOL in November 2023. Running either today means operating on software with known, unfixed CVEs.
Check your current version quickly via WP-CLI:
wp --info | grep PHP
Then stage the upgrade. Test plugin and theme compatibility on a staging environment before pushing to production. PHP major version changes can break plugins relying on deprecated functions — this is a known issue, not a rare edge case. But "there might be a compatibility problem" is not a reason to run unsupported software indefinitely. It's a reason to test properly.
8. Eliminate Abandoned Plugins — Deactivated Is Not Safe
Plugin abandonment risk is systematic and underappreciated. A plugin that hasn't received an update in 12–18 months is a meaningful signal that active maintenance has stopped. If that plugin has a known CVE in WPScan's database, you're carrying a loaded vulnerability with no patch coming.
But here's the part most owners miss: deactivating a plugin does not eliminate the risk. If the plugin files exist on disk, certain attack scenarios — particularly those targeting file inclusion vulnerabilities — can still exploit them.
The rule is simple: if you're not using it, delete it. Not deactivate. Delete.
For plugins you are using, check their update history, active installation counts, and compatibility flags in the WordPress repository. A plugin with 200 installs, last updated two years ago, and a "not tested with current WordPress version" flag deserves closer scrutiny than your core business plugins.
9. Inspect Your wp-cron Jobs — Especially After Any Security Event
WordPress cron jobs power scheduled tasks — email dispatch, cache clearing, scheduled posts, backup triggers, plugin maintenance routines. They run via wp-cron, which fires on page load unless you've disabled that default behavior and configured a real server-side cron instead.
After any security incident — or as part of a proactive audit — inspect your scheduled tasks:
wp cron event list
In compromised sites, attackers sometimes inject malicious cron tasks to maintain persistence. Even after you've cleaned visible malware, a rogue cron job calling an external URL or re-executing an injection script will re-infect the site. This is a technique that makes cleanups fail repeatedly if the cron layer isn't inspected.
Also audit your wp_options table for unusual autoload entries. Malicious code is sometimes injected into serialized option values or hidden inside transients — short-lived database entries that most security scanners skip because they're treated as cache, not content. If you're thorough, scan transients explicitly during any security audit.
10. Run a Full Security Audit — And Treat It as the Starting Point, Not the End Goal
A one-time hardening pass is not a security posture. It's a starting point.
Malware can sit dormant for months before triggering visible symptoms. Object cache poisoning, injected transients carrying executable payloads, modified core files — these don't always manifest as obvious site breakage. A site can look completely operational while actively exfiltrating customer data, serving hidden spam links to search engines, or running a botnet relay.
A proper security audit covers:
- File integrity verification against WordPress core checksums
- Database scanning for injected PHP in post content, widget options, and the wp_options table
- Transient inspection for malicious payloads
- Plugin vulnerability mapping against current CVE databases
- Admin user and active session audit
- Server log review for anomalous request patterns
- Review of all cron events and scheduled hooks
- Confirmation of .htaccess rules and PHP execution restrictions
You can start the core file check with WP-CLI:
wp core verify-checksums
That command checks WordPress core against official checksums. It does not check your plugins, your database, your transients, your file permissions, or your cron jobs. It's one piece of the audit, not a substitute for it.
What Most Sites Are Actually Missing
The honest assessment: most WordPress sites implement two or three of these steps and operate under the assumption they're reasonably protected. That's not security — it's selective hardening with open flanks on all sides.
The vulnerabilities that compromise WordPress sites most often aren't sophisticated zero-days requiring custom exploit chains. They're outdated plugins with publicly listed CVEs, no WAF or a WAF that's never been reviewed, XML-RPC sitting open by default, REST API exposing usernames without restriction, and PHP versions running two or more years past end-of-life.
These are solvable problems. They just require someone to actually solve them systematically instead of hoping an automated plugin handles it.
If you want a definitive view of where your site stands, our WordPress Security Shield Audit is $129. It covers every attack vector in this article — file permissions, plugin CVE mapping, REST API exposure, database integrity, cron inspection, and a prioritized hardening report. It's designed to give you a clear, actionable picture, not a vague risk score.
For ongoing protection, our WordPress maintenance plans include continuous security monitoring, plugin update management, malware scanning, uptime alerting, and rollback capability — built into the baseline service, not sold as add-ons.
If something's already broken or you suspect a compromise has already happened, emergency WordPress support is available for immediate triage and cleanup.
Look — I'm writing this because this is a problem I see constantly, and it's also exactly what we built Vimsy to solve. If you want professionals handling this instead of hoping nothing breaks, book a free call.


