Guide

WordPress Brute Force Attack Detection from Logs

Security plugins block attacks. But do you know how many are happening, when they spike, and which endpoints are targeted? Your logs do.

Every WordPress site is being probed right now

If you run a public WordPress site, bots are trying to log in to it as you read this. They run twenty-four hours a day, against tens of millions of WordPress sites, with credentials harvested from breaches and leaks across the internet. The pattern is industrial: rotate through username and password combinations, spray a few thousand attempts per IP, move on, come back later from a different network. They are not targeting you specifically. They are targeting WordPress, and your site is a number in their queue.

Most teams don't notice. The security plugin blocks the obvious attempts and shows a counter in the dashboard. The site keeps running. Uptime is fine. The narrative becomes "we have a security plugin, we are protected." That narrative is partially true and dangerously incomplete. Blocking individual attempts is not the same as understanding the attack pattern, and "blocked" is not the same as "safe." This guide covers what brute-force attacks against WordPress actually look like, what your security plugin does and does not show you, and how to detect attacks from logs in a way that gives you the full picture.

How brute-force attacks against WordPress actually work

There are several attack shapes, and they target different endpoints.

wp-login.php credential stuffing

The classic. The attacker sends POST requests to /wp-login.php with username/password pairs from a credential dump. They try common usernames (admin, administrator, the domain name, the company name, "info") with common passwords (123456, password, the year, the company name, "Welcome1"). Volume: tens to hundreds of attempts per minute from a single IP. Detection: easy at the IP level, harder if the attacker rotates IPs through a botnet.

xmlrpc.php multi-call amplification

XML-RPC has a system.multicall method that lets a single HTTP request execute multiple API calls. Attackers use it to attempt hundreds of logins in one request — circumventing per-request rate limits. Many security plugins focus their attention on wp-login.php and leave xmlrpc.php under-protected. If you don't actively use XML-RPC (most modern WordPress sites don't), it is a backdoor.

REST API authentication probes

The WP REST API supports application passwords and basic-auth on certain endpoints. Newer attack tooling probes /wp-json/wp/v2/users and other authenticated endpoints. Some security plugins were written before this attack surface was prominent and don't monitor it.

Slow distributed brute force

The smartest variant. Instead of hammering from one IP, the attacker rotates through hundreds or thousands of IPs from a botnet and submits attempts at a low rate per IP — say, one attempt per IP per hour. Per-IP rate limits never trip. The aggregate volume across all IPs is high. This is the pattern that catches plugins flat-footed: each individual IP is "below threshold," but the targeted-username pattern across the population is unmistakable.

Username enumeration before the attack

Before brute-forcing, attackers often enumerate valid usernames via /?author=N redirects, the REST users endpoint, or comment-author fields. Knowing real usernames makes the brute-force phase 10x more efficient. Logs of suspicious enumeration attempts are an early-warning signal that an attack is being prepared.

What security plugins do — and what they don't show you

Security plugins do real work. They block individual IPs that exceed thresholds, they enforce 2FA, they patch known vulnerabilities. They are necessary. They are also not sufficient — for a specific reason.

  • They block, but they don't measure. The dashboard says "120 attacks blocked today." Useful as a counter. Useless for understanding pattern, trend, or targeting. Is 120 normal for your site? Was it 50 yesterday? Is the targeted username "admin" or has it shifted to "wpadmin"? You can't tell from a counter.
  • xmlrpc.php is often left exposed. Many security plugins have wp-login.php protection turned on by default and xmlrpc.php protection as an opt-in setting. Most users don't opt in. Most attackers know this.
  • REST endpoints are often unmonitored. Authentication probes against the REST API don't always trip the same protections as wp-login.php attacks.
  • No cross-endpoint correlation. If an attacker hits wp-login.php with one username and immediately tries the same username on xmlrpc.php and the REST API, that's coordinated targeting. A plugin that monitors each endpoint in isolation doesn't see the coordination.
  • No cross-site visibility. If you manage multiple WordPress sites, each plugin reports independently. The same attacker probing your entire portfolio is invisible without aggregation. Multi-site log monitoring closes that gap.
  • No post-success detection. The most dangerous moment is not the failed attempts. It's the successful login that follows a long series of failures from the same IP — or for the same username. Plugins that only watch failures miss the compromise itself.
  • Slow-distributed attacks slip through. Per-IP thresholds don't catch attacks deliberately tuned to stay below them.

How to detect brute-force activity from logs manually

If you have shell access to your server and time to spend, you can extract a lot of signal from existing logs. None of this is sustainable in the long run, but it will tell you whether you have a problem right now.

1. Count requests to wp-login.php in the last hour

awk -v d="$(date -u -d '1 hour ago' '+%d/%b/%Y:%H')" '$0 ~ d && /wp-login.php/' /var/log/nginx/access.log | wc -l

Anything above a few dozen for a low-traffic site is suspicious. Hundreds is an active attack.

2. Identify top attacking IPs

grep "POST /wp-login.php" /var/log/nginx/access.log \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

Concentrated volume from a small set of IPs is a single-actor attack. Spread across hundreds of IPs is a botnet.

3. Check xmlrpc.php traffic

grep "POST /xmlrpc.php" /var/log/nginx/access.log | wc -l
grep "POST /xmlrpc.php" /var/log/nginx/access.log | awk '{print $1}' \
  | sort | uniq -c | sort -rn | head -10

If you don't actively use XML-RPC, any meaningful volume is hostile.

4. Look for username enumeration

grep -E '\?author=[0-9]' /var/log/nginx/access.log | wc -l

Sequential author probes (?author=1, ?author=2, ...) are username enumeration. This usually precedes a brute-force attempt.

5. Watch for successful logins after failures

This is the part the access log alone won't tell you, because it doesn't know which logins succeeded. You'd need to correlate access-log entries with PHP-side auth events — which is exactly the gap that log-based monitoring fills.

How to harden against brute force, in priority order

Detection without response is anxiety with extra steps. Once you can see the attacks, here is what to do about them.

1. Enforce strong, unique passwords for every account

If credentials don't appear in any breach corpus, credential stuffing is mathematically futile. The bots will still try; they just won't succeed. Use a password manager, generate 20+ character passwords, ban the obvious passwords (WordPress core has filters for this). This is the highest-leverage thing you can do.

2. Turn on two-factor authentication

Even with a perfect password, 2FA is the difference between "hard" and "essentially impossible" for credential-stuffing attacks. Use TOTP (Google Authenticator, Authy, 1Password) rather than SMS where possible.

3. Disable XML-RPC if you don't use it

Most modern WordPress sites have no use for XML-RPC. The Jetpack plugin needs it, the WordPress mobile app needs it, but otherwise you can shut it off completely. In Nginx:

location = /xmlrpc.php {
    deny all;
    return 403;
}

4. Rate-limit at the web-server level

Nginx limit_req on the login endpoint, or Apache mod_evasive, blocks volume from individual IPs before requests reach PHP. Cheaper than plugin-based rate limiting and catches the dumb attacks.

5. Move the login endpoint

Plugins like WPS Hide Login change /wp-login.php to a custom path. Security through obscurity, but obscurity is a real layer against bots that only know the default URL.

6. Monitor and alert on patterns

All of the above are preventive. None tell you when an attack is in progress, which patterns are being tried, or whether anything got through. That's the role of log-based monitoring.

How Logystera detects WordPress brute force from logs

The Logystera WordPress plugin captures every authentication attempt as a structured event — including the endpoint (wp-login.php, xmlrpc.php, or REST API), the username tried, the IP, the user agent, and the result (success or failure). The processor derives metrics from those events: failed-auth rate by endpoint, failed-auth rate by username, successful-auth rate after extended failure runs, and aggregate auth pressure across the entire portfolio for multi-site customers.

Pre-built detection rules then run against those metrics:

Detection patterns Logystera ships:

  • Auth-rate spike: failed logins exceed N per minute on any endpoint
  • Targeted-username attack: repeated failures against a single username from many IPs
  • Endpoint coordination: same username probed across wp-login + xmlrpc + REST in a short window
  • Post-failure success: successful login from an IP/username after extended failure run — possible compromise
  • Username-enumeration ramp: sequential author probes preceding the attack
  • Slow-distributed signature: sustained low-rate failures from many IPs hitting the same username pool

When a rule fires, you get the alert with the exact attempts that triggered it: which IPs, which usernames, which endpoints, the timeline. You can drill from the alert into the raw event stream and see what is actually happening. None of this requires you to write detection logic — the rules are tuned on real production attack data and shipped pre-configured.

For agencies running portfolios of sites, the cross-site view is where the model pays off. The same actor probing fifteen of your sites in sequence is one alert, not fifteen.

Real example: 501 failed logins, and the part the plugin missed

A nonprofit WordPress site — small, nothing obviously valuable, ran a content-management workflow for a community group — experienced 501 failed login attempts at wp-login.php in a single thirty-minute window. The security plugin blocked most of them and reported the count in its weekly digest. So far, business as usual.

What the digest didn't show: 14 attempts also hit xmlrpc.php with the same username pattern in the same window, and those weren't being blocked because the plugin's xmlrpc protection wasn't enabled. Logystera's alert correlated the cross-endpoint activity, flagged the xmlrpc gap, and surfaced the targeted username — which turned out to be the actual administrator's.

The team disabled xmlrpc.php within the hour, rotated the admin password, and turned on 2FA. No account was compromised. The attack would have continued for days against an unmonitored xmlrpc endpoint with no visible indicator.

Related guides

Frequently asked questions

Is brute-force detection enough, or do I still need a security plugin?

You need both. A security plugin actively blocks attempts at the application layer — that's prevention. Log-based detection tells you the volume, pattern, and post-attack outcomes — that's visibility. Prevention without visibility leaves you guessing whether your defenses are working. Visibility without prevention leaves you watching attackers roll over you. Run both layers.

Should I disable xmlrpc.php on every WordPress site?

If you don't use the WordPress mobile app, the Jetpack site-stats / publicize features, or any pingback/trackback functionality, then yes — disable it entirely. For most modern sites, xmlrpc is unused legacy attack surface. If you do use one of those features, restrict xmlrpc.php to known-good IPs at the firewall level rather than leaving it globally open.

What's the difference between a brute force and a credential-stuffing attack?

Brute force tries a wide range of passwords against a known username — exhaustive search. Credential stuffing tries known username/password pairs harvested from breaches at other sites — assuming users reuse credentials. Credential stuffing is much more efficient and far more common in 2024+. Detection looks similar — high failure rate, targeted usernames — but credential stuffing has a higher success rate per attempt because the credentials it tries are real.

How can I tell if an attacker actually got in?

Look for a successful login from an IP that previously had a long run of failures, or for a successful login on a username that was being targeted heavily. Logystera's "post-failure success" rule fires specifically on this pattern. Other tells: new admin user created, new plugin installed, theme functions.php modified, sudden burst of outbound traffic. Application-layer monitoring catches the auth signals; file-integrity tools and WAFs catch the post-compromise activity.

Why don't IP blocks stop the attacks?

Modern attack infrastructure runs on botnets — networks of compromised machines, residential IPs from infected home routers, and rented cloud instances. The attacker has access to thousands or millions of IPs. Blocking one or a hundred is rounding error. The right defense layers are credential strength, 2FA, rate limiting, attack-surface reduction (disable xmlrpc), and visibility — not IP blocklists.

See what's actually happening in your WordPress system

Connect your site. Logystera starts monitoring within minutes.

Logystera Logystera
Monitoring for WordPress and Drupal sites. Install a plugin or module to catch silent failures — cron stalls, failed emails, login attacks, PHP errors — before users report them.
Company
Copyright © 2026 Logystera. All rights reserved.