Why WordPress Remains the Biggest Target on the Web
WordPress runs roughly 43% of all websites on the internet. That number alone explains why attackers focus on it so heavily. If you can find one exploit that works on a default WordPress installation, you potentially have access to hundreds of thousands of sites. For a threat actor, that's an extraordinary return on investment.
Yet many business owners in Lugano and across Switzerland still treat WordPress as if it were a static brochure they set up once and forget. The reality is far more complicated. WordPress is a living piece of software with a massive dependency chain: a PHP runtime, a MySQL or MariaDB database, a web server, the WordPress core itself, a theme, and anywhere from five to fifty plugins. Each of these layers is a potential entry point.
In this article, we will walk through the most critical vulnerability classes affecting WordPress sites in 2025, reference real CVEs, explain why many web agencies fail to keep sites secure, and give you a concrete hardening checklist you can act on immediately.
Outdated Core and PHP Versions
The WordPress Core Update Problem
WordPress has a decent auto-update mechanism for minor releases (e.g., 6.4.1 to 6.4.2). But major version upgrades (e.g., 6.4 to 6.5) require manual intervention, and many site owners skip them out of fear that something will break. That fear is not entirely unfounded: plugins and themes can be incompatible with new core versions. But the alternative is far worse.
Consider CVE-2023-39999, a vulnerability in WordPress core that allowed contributors to read private or draft posts through the REST API. It was patched in WordPress 6.3.2, but sites running older versions remained exposed for months. Or take CVE-2024-31210, which allowed admin-level users to execute arbitrary code during plugin uploads under certain server configurations. These are not theoretical risks.
PHP End-of-Life: A Silent Killer
PHP 7.4 reached end of life in November 2022. PHP 8.0 went end-of-life in November 2023. Yet a significant portion of WordPress sites still run on these unsupported versions. When PHP stops receiving security updates, every known vulnerability becomes a permanent fixture of your stack.
The numbers are stark:
| PHP Version | Security Support Until | Status (Jan 2025) |
|---|---|---|
| PHP 7.4 | November 2022 | End of life, no patches |
| PHP 8.0 | November 2023 | End of life, no patches |
| PHP 8.1 | December 2025 | Security fixes only |
| PHP 8.2 | December 2026 | Active support |
| PHP 8.3 | December 2027 | Active support |
If your hosting provider still defaults to PHP 7.4, that is a red flag about their entire security posture. You should be running PHP 8.2 or 8.3 as a minimum in 2025.
The Plugin Ecosystem: WordPress's Greatest Strength and Weakness
A Dependency Chain You Don't Control
The WordPress plugin directory hosts over 60,000 plugins. Many of them are maintained by a single developer who may abandon the project at any time. When that happens, you're left with code that will never receive another security patch, running on your production server, processing your customers' data.
In 2024 alone, WPScan (now part of Automattic) tracked over 5,000 new vulnerability disclosures in WordPress plugins and themes. Some of the most severe:
- CVE-2024-27956 (WP Automatic Plugin): SQL injection allowing unauthenticated attackers to create admin accounts. CVSS score 9.8. Over 30,000 active installations at time of disclosure.
- CVE-2024-2876 (Email Subscribers by Icegram Express): Another SQL injection, unauthenticated, allowing full database extraction. Over 90,000 installations.
- CVE-2024-4345 (Starter Templates by Brainstorm Force): Stored cross-site scripting allowing privilege escalation. Over 1 million installations.
The pattern is always the same: a popular plugin with hundreds of thousands of installations contains a critical vulnerability that was trivially exploitable. Within hours of disclosure, automated scanners are probing every WordPress site on the internet for the vulnerable endpoint.
Supply Chain Attacks on Plugins
A newer and more insidious threat is supply chain compromise. In 2024, several WordPress plugins were taken over by new owners who injected malicious code into updates. The plugin Social Warfare incident from a few years back set the template: an attacker gains access to a plugin's repository (through social engineering, buying the plugin, or compromising the developer's account), then pushes an update containing a backdoor. Every site with auto-updates enabled installs it automatically.
This is not a hypothetical scenario. It happened with the Suspended AccessPress Themes incident, where dozens of themes and plugins were backdoored through a compromised developer account. For more on how plugin vulnerabilities cascade, see our analysis of CMS plugin vulnerabilities.
wp-admin Exposure and Brute Force Attacks
The Default Login Page Problem
Every default WordPress installation exposes /wp-admin and /wp-login.php to the entire internet. This is the equivalent of putting a "please try to break in here" sign on your front door. Automated bots scan IP ranges and domain lists 24/7, probing these endpoints with username/password combinations harvested from previous data breaches.
A typical WordPress site receives between 500 and 5,000 brute force login attempts per day. Sites with common admin usernames like "admin" or "administrator" get hit hardest. The attacks are distributed across thousands of IP addresses, making simple IP blocking insufficient.
We cover this topic in depth in our dedicated article on exposed admin pages and why they represent a persistent risk.
Credential Stuffing vs. Brute Force
There is an important distinction here. Traditional brute force tries every possible combination. Modern credential stuffing is smarter: attackers use username/password pairs leaked from other breaches (LinkedIn, Adobe, Dropbox, etc.) and try them against your WordPress login. Since people reuse passwords across services, this works disturbingly often.
Tools like WPScan make this trivially easy:
wpscan --url https://target.com --passwords leaked_passwords.txt --usernames admin,editor,john
This command will systematically try every password in the file against each username. It handles rate limiting, session management, and even CAPTCHA bypass in some cases.
XML-RPC: The Forgotten Attack Vector
WordPress ships with XML-RPC enabled by default. This protocol was originally designed to allow external applications (like mobile apps) to interact with WordPress. The problem is that the system.multicall method allows an attacker to try hundreds of username/password combinations in a single HTTP request, effectively bypassing rate limiting on the login form.
An XML-RPC brute force request looks like this:
POST /xmlrpc.php HTTP/1.1
Content-Type: text/xml
<methodCall>
<methodName>system.multicall</methodName>
<params>
<param><value><array><data>
<value><struct>
<member><name>methodName</name>
<value><string>wp.getUsersBlogs</string></value>
</member>
<member><name>params</name>
<value><array><data>
<value><string>admin</string></value>
<value><string>password123</string></value>
</data></array></value>
</member>
</struct></value>
</data></array></value>
</param>
</params>
</methodCall>
A single request can contain 500+ credential pairs. Most WordPress firewalls and rate limiters don't inspect XML-RPC payloads, so this vector remains wide open on unprotected sites. If you're not using XML-RPC (and most modern sites don't need it), block it entirely at the web server level.
SQL Injection Through Plugins
How WordPress Handles Database Queries
WordPress core uses the $wpdb->prepare() method for parameterized queries, which provides solid protection against SQL injection when used correctly. The problem is that plugin developers frequently bypass this mechanism, either through ignorance or laziness.
A vulnerable query in a plugin might look like:
$results = $wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}custom_table WHERE id = " . $_GET['id']
);
Versus the safe version:
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}custom_table WHERE id = %d",
intval($_GET['id'])
)
);
The first version directly concatenates user input into the SQL string. An attacker can append UNION SELECT statements, extract password hashes from the wp_users table, read arbitrary files from the filesystem, or in some cases achieve remote code execution through the INTO OUTFILE directive.
Real-World SQL Injection Chain
Here is how a typical SQL injection attack unfolds against a vulnerable WordPress plugin:
- Discovery: The attacker uses automated tools (SQLMap, custom scripts) to probe every GET and POST parameter on the site.
- Confirmation: A parameter in a contact form or search plugin returns a database error when injected with a single quote character.
- Extraction: The attacker uses
UNION SELECTto pull the admin user's password hash fromwp_users. - Cracking: WordPress uses phpass hashing by default. With a GPU cluster, weak passwords fall within minutes.
- Access: The attacker logs into wp-admin with the cracked credentials.
- Persistence: A backdoor PHP shell is uploaded through the theme editor or plugin uploader.
- Exfiltration: Customer data, payment information, and other sensitive data is extracted.
This entire chain can execute in under an hour. The entry point is a single unparameterized query in a plugin that the site owner probably installed years ago and forgot about.
File Upload Vulnerabilities
When Media Upload Becomes Code Execution
WordPress allows users to upload files through the media library and through various plugins (contact forms, profile pictures, document management). Each upload handler is a potential code execution vector if it doesn't properly validate file types.
The classic attack involves uploading a PHP file disguised as an image. If the server is configured to execute PHP in the uploads directory (which is the default on many shared hosting setups), the attacker can execute arbitrary commands on the server.
A malicious file might be named image.php.jpg or use null byte injection (shell.php%00.jpg) to bypass extension checks. Some plugins only check the Content-Type header sent by the browser, which the attacker controls entirely.
Mitigating Upload Risks
Proper file upload security requires multiple layers:
- Validate the file extension against an allowlist (not a blocklist)
- Check the file's MIME type using server-side detection (e.g.,
finfo_file()), not the client-provided Content-Type - Rename uploaded files to prevent directory traversal
- Store uploads outside the web root when possible
- Add an
.htaccessfile in the uploads directory that disables PHP execution:php_flag engine off - Use a Web Application Firewall (WAF) that inspects file contents
Why Many Agencies Don't Update
The Business Model Problem
Here is the uncomfortable truth about the WordPress ecosystem: the standard business model for web agencies doesn't incentivize security. A typical agency builds a WordPress site, hands it over to the client, and moves on. There may be a maintenance contract, but it often covers "uptime monitoring" rather than actual security patching.
Updating WordPress core, plugins, and themes takes time. Testing after updates takes more time. Fixing compatibility issues after updates takes even more time. Most maintenance contracts don't budget for this work, so agencies avoid it. The client doesn't know enough to demand it. The site sits on an increasingly outdated stack until someone finds a vulnerability.
We have seen Swiss businesses running WordPress 4.x installations with PHP 5.6, completely unpatched for years. Not because they couldn't afford updates, but because nobody told them it mattered.
The Testing Gap
Even agencies that want to update face a practical challenge: there is no staging environment. Most budget WordPress setups run directly in production with no way to test updates before deploying them. The agency is stuck in a bind: update and risk breaking the site, or don't update and risk getting hacked. Without a proper CI/CD pipeline and staging server, most choose to do nothing.
Concrete Hardening Checklist for WordPress in 2025
If you're running WordPress and cannot migrate to a more secure architecture, here are the minimum steps you should take:
1. Update Everything, Regularly
- Enable automatic minor core updates (they're on by default, don't disable them)
- Set up a staging environment for testing major updates
- Update all plugins and themes at least monthly
- Remove any plugin or theme you're not actively using
- Run PHP 8.2 or 8.3
2. Lock Down Authentication
- Enforce strong, unique passwords for all accounts
- Enable two-factor authentication (TOTP, not SMS)
- Rename or relocate the login URL
- Implement rate limiting on login endpoints
- Disable XML-RPC unless you specifically need it
- Restrict admin access by IP if possible
3. Minimize the Attack Surface
- Audit every installed plugin: do you actually need it?
- Remove the default "Hello Dolly" plugin and unused themes
- Disable the built-in file editor (add
define('DISALLOW_FILE_EDIT', true);to wp-config.php) - Disable directory listing on the web server
- Remove the WordPress version number from the HTML source
4. Harden the Server
- Use HTTPS everywhere (no mixed content)
- Set proper security headers:
X-Frame-Options,Content-Security-Policy,X-Content-Type-Options,Strict-Transport-Security - Restrict file permissions: directories at 755, files at 644, wp-config.php at 400
- Block PHP execution in
wp-content/uploads/ - Use a Web Application Firewall (Cloudflare, Sucuri, or server-level with ModSecurity)
5. Monitor and Respond
- Set up file integrity monitoring
- Monitor login attempts and block repeat offenders
- Keep backups (off-site, tested, automated)
- Subscribe to vulnerability feeds (WPScan, Wordfence intelligence)
- Have an incident response plan: who do you call when something goes wrong?
When WordPress Isn't the Right Choice
For many businesses, the question isn't how to secure WordPress but whether WordPress is the right tool at all. If your site is primarily informational (company website, portfolio, blog), a static site generator eliminates entire vulnerability classes. No database means no SQL injection. No server-side runtime means no remote code execution. No login page means no brute force attacks.
We explore this topic in detail in our article on static vs. dynamic site security. For companies in Lugano and across Switzerland looking for a secure web presence, the architecture decision is often more impactful than any security plugin.
Conclusion
WordPress security is not a set-and-forget proposition. It requires continuous attention, regular updates, and a clear understanding of the attack surface you're exposing. The vulnerabilities we've covered here are not edge cases; they are the bread and butter of automated attacks happening right now against sites just like yours.
If you're running a WordPress site for your business and haven't reviewed its security recently, get in touch with our team. We can perform a thorough security assessment and help you decide whether hardening your existing setup or migrating to a more secure architecture is the right path forward.
Want to know if your site is secure?
Request a free security audit. In 48 hours you get a complete report.
Request Free Audit