The WordPress Security Audit I Run on Every New Client Site

Most WordPress sites look fine. The site loads, the contact form works, nobody has called to complain. That’s usually the problem.

Security issues don’t announce themselves. They sit there quietly until someone finds them. By the time you notice, you’ve got injected spam links, a blacklisted domain, or a compromised customer database.

I run the same audit on every new client site I take on. Here’s what’s on it.

User Accounts and Authentication

The first thing I look at is who has access and how they’re protecting it.

  • Is two-factor authentication enabled for every admin account?
  • Are there admin accounts that shouldn’t exist anymore?
  • Is user registration disabled if nobody needs to sign up?
  • Is the default user role set to subscriber?

Stale admin accounts are one of the most common attack vectors I see. A contractor finishes a project, their account sits there for two years, their email gets phished, and suddenly someone has admin access to your site. Preventable. Just not prevented.

Exposed Endpoints

WordPress ships with several endpoints that attackers actively probe.

/xmlrpc.php should be blocked outright. It’s a legacy API that most sites don’t use but attackers love for brute-force attacks. No reason to leave it open.

REST API user enumeration should be protected. By default, WordPress exposes usernames through the API. That hands attackers half of what they need. Author archive enumeration does the same thing from a different angle. Visiting /?author=1 on an unprotected site returns the admin’s username in the URL.

These aren’t theoretical. They’re the first things automated scanners try.

Plugins and Updates

I check every plugin against the same criteria: Is it actively maintained? Has it been updated in the last 6-12 months? Does it have known vulnerabilities?

Abandoned plugins are a real problem. A plugin that hasn’t had an update in two years isn’t being patched when new vulnerabilities surface. It’s just sitting there.

Wordfence is on every site I manage. Brute-force lockouts, file change monitoring, alert emails. Auto-updates enabled, alerts going to an inbox someone actually reads.

Custom Code

If a site has a custom theme or custom plugins, those get their own review. I’m looking for:

  • eval() and base64_decode() calls
  • Direct database queries that bypass $wpdb->prepare()
  • AJAX handlers without nonce verification
  • REST API endpoints missing a proper permission_callback
  • Output that isn’t escaped correctly for context

These are the things that turn a functional custom build into a SQL injection or XSS waiting to happen. I’ve found all of them in production code.

Files and Permissions

wp-config.php should not be readable over HTTP. readme.html and license.txt advertise your WordPress version to anyone who looks. The uploads directory should block PHP execution.

Directory permissions should be 755, file permissions 644. wp-config.php gets 600. That’s not optional.

These are simple checks. They’re also missed constantly.

Server and SSH Hardening

SSH password authentication should be disabled. Key-based auth only. If someone can brute-force SSH passwords, everything else on this list is irrelevant.

MySQL should not be externally accessible. PHP version exposure should be off. PHP errors should be logged privately, not displayed publicly. High-risk functions like exec, shell_exec, and passthru should be disabled unless there’s a documented reason they’re needed.

Cloudflare

Every site I manage runs behind Cloudflare. But putting a site behind Cloudflare and configuring it correctly are two different things.

SSL mode should be Full Strict. Not Flexible. Flexible means traffic between Cloudflare and your origin server is unencrypted, which defeats the purpose.

WAF managed rules should be on. Bot protection should be configured. Cache rules should not be caching admin pages, checkout, or anything behind authentication.

Email and DNS

SPF, DKIM, and DMARC. All three. DMARC monitoring before you move to strict enforcement.

Authentication should go through a real SMTP provider, not default PHP mail(). Default PHP mail is unreliable, unauthenticated, and frequently blacklisted.

DNS records should be documented. Domain expiration monitoring should be active. I’ve seen businesses lose their domain because nobody was watching the renewal date.

Backups

Backups stored on the same server as the site aren’t backups. If the server gets compromised or has a hardware failure, you’ve lost both.

Backups should be off-server. They should be tested. There should be a documented rollback plan before any significant update.

Ask yourself: if the site went down right now, how long would it take to restore it? If you don’t have a number, that’s your answer.

Monitoring and Alerting

Uptime monitoring should check the real public site, not just whether the server responds. SSL expiration monitoring should be active. Alert emails should go to an inbox someone actually reads.

Security without monitoring is theater. You need to know when something goes wrong before your customers tell you.

Credentials and Access

When an agency, contractor, or vendor ends their relationship with you, their access should end too. API keys should be rotated. Admin accounts should be removed.

I’ve audited sites where former contractors still had full admin access two years after their engagement ended. That’s not a hypothetical risk. That’s an open door.

What a Real Audit Looks Like

Running through this takes time. Not every site needs every check on the same day. But every site needs someone who knows what to look for.

Most of what I find isn’t catastrophic on its own. It’s the combination of a stale admin account, an outdated plugin, and no monitoring that creates real exposure.

If you want me to run this on your site, reach out. We’ll go through it systematically, document what we find, and you’ll walk away with a prioritized list of what to fix and in what order.

Leave a Reply

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

Fill out this field
Fill out this field
Please enter a valid email address.
You need to agree with the terms to proceed