Security

Diagnose a spike in failed login attempts from raw server logs

A pasted chunk of access log lines hammering wp-login.php, read the way a responder reads logs, telling credential stuffing apart from targeted brute force and checking whether any attempt actually got through.

Works with Claude / GPT356 uses 4.2

The prompt

security-failed-login-spike-log-diagnosis
Access log excerpt, roughly 90 seconds of a much longer spike:

[203.0.113.5 - - [14/Jul/2026:02:11:03 +0000] "POST /wp-login.php HTTP/1.1" 200
4523 "-" "Mozilla/5.0"
198.51.100.9 - - [14/Jul/2026:02:11:04 +0000] "POST /wp-login.php HTTP/1.1" 200
4523 "-" "python-requests/2.31.0"
192.0.2.44 - - [14/Jul/2026:02:11:04 +0000] "POST /wp-login.php HTTP/1.1" 200
4523 "-" "python-requests/2.31.0"
203.0.113.5 - - [14/Jul/2026:02:11:06 +0000] "POST /wp-login.php HTTP/1.1" 302
0 "-" "Mozilla/5.0"
198.51.100.201 - - [14/Jul/2026:02:11:07 +0000] "POST /wp-login.php HTTP/1.1" 200
4523 "-" "python-requests/2.31.0"]
and roughly 6,000 more lines like it over 40 minutes, targeting usernames drawn
from a short list rather than one single account.

Read this the way a responder reads logs, not just as noise to block:
1. Identify the attack pattern from the shape of the traffic: many distinct
   source IPs each trying a short list of usernames points to credential
   stuffing against a leaked username/password list, not a single-source brute
   force. State what pattern would look different if it were the latter (one or
   two IPs, high request rate, single username).
2. Find the signal that matters most in this excerpt: the response at
   02:11:06 returns 302 with a 0-byte body instead of 200 with a 4523-byte body
   like every failed attempt around it. Explain why a differing status code and
   response size is exactly what a successful login looks like next to a wall of
   failures, and that it needs to be checked immediately, not batched into the
   eventual cleanup.
3. Recommend the next diagnostic step: correlate that 302 response's timestamp
   against the WordPress login log or user activity to identify which account,
   if any, actually authenticated.
4. Give immediate mitigations sized to this specific pattern: rate limiting or
   temporary IP blocks for the offending ranges, and why blocking single IPs is
   a losing game against a distributed list like this compared to a login
   attempt cap per username.
5. Recommend what ongoing log monitoring or alerting would have caught this
   earlier than 6,000 lines in.

Paste in whatever log format your host or WAF gives you (Nginx, Apache, or a security plugin’s own log export); the pattern-matching logic transfers even if the exact fields don’t match this example.