The patch for CVE-2026-87902 shipped September 22. Patchstack blocked the first exploit attempt at 11:49 UTC the same day. Within 24 hours, traffic was up 10x and payloads had escalated to writing PHP files to disk via pearcmd.php. Five days earlier, 7.1.1 had already forced one emergency update. Two core updates in five days, with exploitation measured in hours — that is the tempo your update pipeline now has to match.
The numbers behind the urgency
- Mandiant M-Trends 2026: mean time-to-exploit ≈ -7 days (exploitation on average begins before disclosure; mean, not median — driven by zero-day campaigns).
- Rapid7 2026 via CSA: median disclosure → KEV listing compressed 8.5 → 5.0 days (not disclosure → exploit); exploited high/critical CVEs 71 → 146 YoY.
- Fortinet 2026: 4.76 days → 24–48h is the critical-outbreak window, not a general median.
- Censys Jun 2026 (latest release then 7.0): only 14% of visible WP sites on latest patch; 70%+ outdated PHP; 20%+ on PHP 7.4 (EOL Nov 2022).
The morning-after verify (commands, not vibes)
Auto-updates miss hosts where the feature is disabled, overridden, or tracking the wrong branch. Verify with ground truth:
# What version am I actually on?
wp core version
# Update core to latest security release
wp core update
# Audit plugin drift — anything not current is attack surface
wp plugin list --fields=name,version,update --format=table
# Check the PHP exposure signal for LFI-to-RCE chains
php -i | grep -i register_argc_argv
# want: register_argc_argv => Off (for web SAPI)
In php.ini for web requests:
register_argc_argv = Off
That single setting breaks the classic pearcmd.php?+config-create argument-injection path Ressl and Patchstack both flag — but it does not fix the underlying inclusion. Seatbelt, not brakes — the patch is still the fix.
The full RCE chain needed three preconditions, not two: a theme with a top-level page-* directory, a readable local PHP file on the server (here, pearcmd.php), and register_argc_argv on. Check the theme per change — it was one leg of a three-legged chain:
ls -d $(wp theme path $(wp theme list --status=active --field=name))/*/ | grep -i 'page-'
Event-driven scanning in CI/CD
Scheduled scans are necessary but insufficient. Wire a scan trigger into the deploy path so every change re-baselines security posture:
# Example: post-deploy hook (adapt to your scanner's API)
curl -s -X POST "https://scanner.example/api/scan" \
-H "Authorization: Bearer $SCAN_TOKEN" \
-d '{"target":"https://shop.example","profile":"full"}'
# Quick self-checks you can run from cron today
curl -sI https://shop.example | grep -iE 'strict-transport|content-security|frame-options'
echo | openssl s_client -connect shop.example:443 2>/dev/null | openssl x509 -noout -dates
Cadence that matches the threat data: daily automated scans for anything handling payments, weekly minimum for standard sites, an on-demand scan after every deploy or plugin update, and a quarterly manual review for logic flaws scanners miss. Findings go to a tracker with SLAs (critical: 24h, high: 7d) — scan reports in an unread inbox are theater.
The takeaway for your pipeline
Exploit generation now costs ~$1 and 10-15 minutes per CVE with LLM assistance (CSA, 2026). Your patch cycle cannot beat that on speed — but verified auto-updates plus event-driven scanning compress your exposure window to roughly the update lag alone, instead of update lag plus months of undetected drift. That is the whole game now.
Originally published on WardenBit — the full post adds the shop-owner walkthrough and key statistics with sources.
Top comments (1)
The morning-after check is a useful habit. After an update, it also helps to review new files, admin users, and recent logs.