Skip to content

How to audit a WordPress site for security weaknesses

A security audit is a written inventory of a working site. It covers what is installed, who can log in, how the site is configured, what it shows from outside, whether a backup restores, and who holds the hosting and domain logins. Each finding gets a date to fix it or a reason to accept it.

By
WP Ministry
Updated

In short

  • An audit is a written inventory of a site that is working. It finds known weaknesses before someone else does.
  • Start with software. Record every version, every pending update, and every plugin that is inactive, closed or no longer looked after.
  • Every administrator should be a person you can name, who still needs that role and uses two-factor login.
  • A backup is a finding until someone has restored it and written down the date.
  • The hosting account and the domain are part of the site. Record who holds each login and whether renewal is automatic.
  • It is not a penetration test, and it cannot find a flaw nobody has reported yet.

A security audit of a WordPress site is an inventory with a record. You go through six areas of a site that is working: what is installed, who can log in, how it is configured, what it shows from outside, whether it could be restored, and who holds the hosting and domain accounts. For each area you write down what you found. Plan an afternoon for it.

Nothing in the audit changes the site. The fixes come afterwards, in an order you choose, and WordPress security: what to do, in order of what matters most has the steps for most of them. If your question is whether someone has already got in, that is a different job: see how to check whether your WordPress site has been hacked.

Keep a record as you go

Open a spreadsheet before you start. Give each finding one row.

AreaFindingActionWhen
SoftwareA gallery plugin is inactive and has an update waitingDelete itToday
AccountsA designer who left is still an administratorDelete the account and keep the postsToday
BackupsBackups are taken daily. Nobody has restored one.Restore the newest to a staging copyThis month
HostingThe site shares a server with other customers' sitesLook again when the plan renewsAccepted

Record what was in order too, with the date. Never put a password in the record.

The dashboard is enough for most of the audit. The commands on this page need SSH access and WP-CLI, which you can ask your host about. Run them from the site's main folder. None of them installs, updates or deletes anything.

Software: what is installed

WordPress's hardening guide says older versions of WordPress are not maintained with security updates. It also says to keep plugins updated and to delete the ones you do not use. So the first area is a list of everything installed, with its version.

In the dashboard, go to Tools, then Site Health. The Status tab raises "You have plugins waiting to be updated" and "Your site is running an outdated version of PHP, which requires an update" as critical issues. On the Info tab, the WordPress section gives the version, the Server section covers PHP, and "Active Plugins", "Inactive Plugins", "Active Theme" and "Inactive Themes" give each item's version and whether auto-updates are enabled. The tab can copy all of it to the clipboard for your record.

With WP-CLI, it takes five steps.

  1. Step 1: Record the WordPress version and whether a newer one exists

    The first command prints the version. The second lists newer versions in a table, or prints a success message when the site is up to date. Put your WordPress and PHP versions into the WordPress and PHP end-of-life checker to see whether they still get security fixes, and until when.

    bash
    wp core version
    wp core check-update
  2. Step 2: List every plugin and theme

    Each row gives the name, the status, whether an update is available, the installed version, the version an update would bring, and whether auto-updates are on. A plugin's status is one of active, active-network, inactive, must-use and dropin. A theme's is active, parent or inactive. The last two commands narrow the table to plugins with an update waiting and plugins that are switched off.

    bash
    wp plugin list
    wp theme list
    wp plugin list --update=available
    wp plugin list --status=inactive
  3. Step 3: Check whether each plugin is still on WordPress.org

    wporg_status should read active. Rely on that value only: closed can also be shown for a plugin that was never on WordPress.org, such as a paid or custom one, so for anything but active open the plugin's own page on WordPress.org. That page also shows when the plugin was last updated.

    bash
    wp plugin list --fields=name,version,wporg_status
  4. Step 4: Look up each plugin in a vulnerability database

    WPScan describes its database as cataloging WordPress core, plugin and theme vulnerabilities. Search its plugin list by name, or open https://wpscan.com/plugin/ followed by the plugin's name from the first column above. Each record gives the date it was published, a title that names the affected versions, the version it was "Fixed in", and a CVSS score. Compare "Fixed in" with the version you run.

    A plugin with no record has nothing on file there. That is not the same as having no flaws.

  5. Step 5: Confirm that WordPress's own files match

    This compares WordPress's files with the checksums WordPress.org holds for your version. A clean run prints "Success: WordPress installation verifies against checksums." If a file does not verify, stop the audit and go to the page on checking for a hack, linked at the top.

    bash
    wp core verify-checksums

A finding is any of these:

  • WordPress or PHP on a version that no longer gets security fixes, or any update left waiting.
  • A plugin or theme that is inactive. Its files are still on the server.
  • A plugin on a version lower than the "Fixed in" of a record against it.
  • A closed plugin. Its WordPress.org page says "This plugin has been closed and is no longer available for download." A security issue is one of the reasons a plugin is closed.
  • A plugin whose last update is years old. It may be abandoned, or small and finished. How to choose a WordPress plugin shows how to read its listing.
  • A row marked must-use or dropin, or a plugin from outside WordPress.org, that nobody can explain.

Write down every version, every update waiting, and for each plugin from outside WordPress.org, who installed it and where its updates come from.

Accounts: who can log in

Go to Users. The links above the table filter the list by role. Start with the administrators. From the command line:

bash
wp user list --role=administrator --fields=user_login,user_email,user_registered

WordPress's documentation defines an Administrator as somebody with access to all the administration features of a site, and an Editor as somebody who can publish and manage posts, including other people's. A person who writes and edits rarely needs more than Editor.

Then go to Settings, then General, and read three things. "Anyone can register" decides whether a stranger can create an account. "New User Default Role" is the role a new account is given. "Administration Email Address" is where WordPress sends recovery mode and critical error notices, so it has to be a mailbox your organization can open.

A finding is any of these:

  • An account for someone who no longer works on the site.
  • One login shared by several people. You cannot remove one of them, and you cannot tell who did what.
  • An administrator who only writes or edits.
  • An administrator without two-factor login. How to set up two-factor authentication in WordPress shows where to check what each one has enabled.
  • Registration open on a site that does not need it, or a default role above Subscriber.
  • An administration email address that belongs to a past developer.

Write down each administrator's login, the person behind it, why they need the role, and whether two-factor login is on.

An administrator nobody can account for is a sign of a break-in, not a finding to file. The page on checking for a hack says what to do.

Configuration: how the site is set

SettingWhere to lookA finding is
HTTPSSite Health, Info tab, WordPress section: "Is this site using HTTPS?""No", or an http:// address that does not end on https://
File editing in the dashboardwp config get DISALLOW_FILE_EDITAnything other than true
Debug outputSite Health, Status tab"Your site is set to display errors to site visitors" or "Your site is set to log errors to a potentially public file"
File permissionsThe permissions column in your host's file managerA folder or file at 777, or a wp-config.php everyone can read
XML-RPCYour list of what connects to the sitexmlrpc.php open when nothing uses it
  • HTTPS. Type the http:// form of your address into the redirect checker. The last address it shows should begin with https://.
  • File editing. WordPress's hardening guide says the dashboard by default lets administrators edit plugin and theme files, and gives a constant that takes that ability from every user. If the line is missing from wp-config.php, the command answers that the constant "is not defined in the 'wp-config.php' file." Look in the dashboard as well: if you can open a theme or plugin file editor there, editing is on. The security guide linked at the top has the line to add.
  • Debug output. WordPress's documentation says its debug tools are not recommended on live sites. wp config get WP_DEBUG should print false, or answer that the constant is not defined.
  • File permissions. WordPress's guidance is 755 for folders, 644 for files, and a wp-config.php that only you and the web server can read. WordPress file permissions shows how to read the modes and correct them.
  • XML-RPC. WordPress's guidance calls xmlrpc.php a frequent target for password guessing, and names Jetpack and mobile apps as things that use it. How to protect WordPress from brute force attacks shows how to tell whether it answers and how to close it.

Write down each setting as you found it.

What the site shows from outside

Two checks read the site as a stranger does.

  • The WordPress site health check reads one page and shows what it shows a visitor: whether it answers, how it is secured, what search engines are told, and which WordPress, theme and plugins it shows.
  • The hacked-site check looks for the signs of a break-in that show from outside: visitors from search sent somewhere else, links hidden in the page, and code written to hide what it does.

A finding is an out-of-date version on show. The fix is the update, not hiding the number. Any sign from the second check ends the audit and starts the hack check. Write down the date and what each check returned.

Backups and recovery

WordPress's documentation says a backup has two parts, the database and the files, and that you need both to restore a site. It advises keeping at least three to five recent backups, with copies in different places. Answer these in the record:

  • Does each backup hold both parts?
  • Where are the copies, and is at least one away from the site's server?
  • How many are kept, and how far back do they reach?
  • When was one last restored, by whom, and how long did it take?
  • Who can start a restore if you cannot be reached?

A finding is a backup with one part missing, copies kept only beside the site, or no date for a restore. How to schedule automatic WordPress backups has the steps for restoring one to a private copy of the site.

The hosting account and the domain

Whoever controls these controls the site, whatever WordPress is set to. List every account the site depends on: the hosting panel, SFTP or SSH, the domain registrar, DNS if it is somewhere else, and wherever backups are stored. For each one, record:

  • whose name and email address it is in;
  • who knows the password, and whether it is shared;
  • whether its login has a second step;
  • whether renewal is automatic, and whether the card on file is still valid.

A finding is an account in the name of a past developer or employee, a password passed around by email, a domain that renews only by hand, or file access over plain FTP. The hardening guide says to connect with SFTP, so the password is encrypted on the way.

The same guide notes that on a shared server, a break-in on another site on that server can reach yours. That is a line for the record, and often one to accept. The WordPress maintenance checklist covers reading the domain and certificate dates each quarter.

Turn the findings into a short list

Sort the record into three groups.

  1. Step 1: Fix today

    These have a known hole with a fix ready, or leave access with someone who should not have it. Apply waiting updates, above all for a plugin below its "Fixed in" version. Switch off a plugin that was closed for a security issue. Delete the accounts of people who have left: WordPress asks what to do with their posts, so attribute them to another user. Turn off errors shown to visitors. Take a backup before you update anything. How to safely update WordPress, plugins and themes has the order to work in.

  2. Step 2: Fix this month

    These need arranging or a trial first: two-factor login for every administrator, lower roles, a replacement for an abandoned plugin, a supported PHP version tried on a staging copy, a restore of the newest backup, and accounts moved into the business's name.

  3. Step 3: Accept, in writing

    Some findings stay: the shared server, XML-RPC left open for an app you use, an old plugin that does one small job. For each, write the reason, who decided, and a date to look again.

Keep the record. The next audit starts by comparing with it.

What this audit does not tell you

  • It is not a penetration test. In one, a specialist tries to break in, with your permission, and reports how far they got. This audit attempts nothing.
  • It does not find a flaw nobody has reported yet. A database and an update notice know only what has been found and published.
  • It does not prove nobody is inside. The checksum step covers WordPress's own files and nothing else.

When to get help

  • A client or a payment provider asks you for a penetration test. That is work for a specialist firm.
  • A finding has no fix you can apply, such as a closed plugin the site depends on.

A care plan from our WordPress security service keeps the site updated, scanned and backed up offsite.

Common questions

Is a security plugin's scan the same as an audit?

No. A scan reads the site. It does not know who has left your business, whether last night's backup restores, or whose name the domain is in. WordPress security plugins compared sets out what each plugin scans.

How often should I do this?

Whenever the people change: a new developer, an agency you have stopped using, a new host. Between audits, the maintenance checklist covers updates, the list of users and a test restore.

Can I do it without SSH or WP-CLI?

Yes, apart from the checksum step. Site Health's Info tab lists the versions, plugins and themes, and the Users screen lists the accounts. For each plugin, open its WordPress.org page and look for a closed notice and the date of its last update.

The audit found nothing. Is the site secure?

It means the things you looked at had no known weakness on the day you looked. WordPress's hardening guide describes security as reducing risk, not removing it.

More on this subject

Not sure what is wrong?

Tell us what you see. We reply with the cause and a fixed quote, and the diagnosis is free.