WordPress Core CVE-2026-87902: Page-Template Path Traversal to pearcmd Remote Code Execution
get_page_template() / pagename) · exploited in the wild since 2026-09-22, hours after the patchExecutive Summary
What the attacker wants: code execution on an internet-facing WordPress host, reached without a credential and without a single byte of user interaction. CVE-2026-87902 is a path-traversal flaw in how WordPress core resolves which template file to load for a page. The pagename request parameter feeds get_page_template(); WordPress's own sanitiser strips literal ../ sequences but deliberately preserves percent-encoded octets, so a double URL-encoded traversal payload (%252e%252e) survives sanitisation, gets decoded later, and lets the attacker point the template loader at any readable local .php file outside the active theme. On its own that is an information-disclosure-grade local file inclusion. It becomes remote code execution when two ordinary conditions both hold: the active theme ships a top-level directory whose name starts with page- (Twenty Twelve, Twenty Fourteen, and third-party themes Neve, Hestia and Sydney all qualify), and PEAR's pearcmd.php is present and readable with register_argc_argv enabled in PHP, which is the default in the official PHP Docker image and in cPanel builds on PHP below 8.5. When both hold, the query string is exposed to pearcmd.php as $argv, and its config-create directive will write attacker-controlled PHP content to an arbitrary writable path.
Why it matters operationally: the gap between patch and exploitation was measured in hours, not days. WordPress 7.1.2 (plus 7.0.6, 6.9.9, 6.8.10 and backports to every branch down to 4.7.37) shipped 2026-09-22 alongside advisory GHSA-7hp8-65ch-5whp; Patchstack logged the first probing attempt at 11:49 UTC that same day and the first successful file-write attempt at 15:34 UTC. By 2026-09-23 a named Nuclei template and dedicated scanner tooling were in public circulation, CrowdSec's virtual-patch rule went live, and traffic had moved from reconnaissance to active file-write attempts. CISA added the flaw to the Known Exploited Vulnerabilities catalog on 2026-09-25 with a federal remediation deadline of 2026-09-28. CrowdSec's network recorded 322,680 matching signals between 2026-09-23 and 2026-09-27 alone, distinct source addresses growing from 237 to 23,321 across those five days and reaching 30,813 cumulative unique IPs by 2026-09-28, while signals per source fell from roughly 63 to roughly 5, the textbook signature of an exploit moving from a handful of operators into commodity mass-scanning tooling.
The highest-value defensive angle for Falcon: not the HTTP request, the consequence of a successful chain. A Falcon sensor on the web server never sees a pagename parameter, a percent-encoded traversal sequence, or the cve-2026-87902-poc/1.0 user agent; those live in web-server, WAF and CDN logs. What the sensor sees cleanly is what happens after the include succeeds and the dropped payload runs: a web-server or PHP process (httpd, nginx, php-fpm, php-cgi, or w3wp.exe on IIS) spawning a shell or scripting interpreter. That parent-child relationship is close to zero in a healthy estate, it fires regardless of which of the reported dropped-file names appears, and it is the pack's spine. The atomic indicators (two literal dropped filenames, two scanner user agents, a handful of request markers) are useful corroboration, not the plan.
Defender priority: confirm every WordPress host you own is running 7.1.2, 7.0.6, 6.9.9, 6.8.10 or a later backport, then assume the window from 2026-09-22 to your patch time was hostile and hunt it. Disabling register_argc_argv and removing pearcmd.php breaks the RCE escalation specifically, but the underlying LFI persists until you patch. Run Q1 and Q2 (Section 8) across the last 30 days before you close this out, and do not assume auto-updates saved you. The exposure concentrates precisely on the sites where someone turned them off.
Source Review & Web Hunter Notes
| Tier | Source | Key finding | Carry forward |
|---|---|---|---|
| 1 | GitHub Security Advisory GHSA-7hp8-65ch-5whp (WordPress/wordpress-develop, published by johnbillion) | Primary vendor advisory. Full affected/patched version matrix per branch (7.1.0-7.1.1 through 4.7.0-4.7.36), CVSS 4.0 vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N (9.2 Critical), CWE-98, the two preconditions verbatim, and credit to discoverer Robert Ressl. | Yes, authoritative |
| 1 | NVD (nvd.nist.gov, via the NVD 2.0 REST API) and the MITRE CVE Program record (cveawg.mitre.org) | Independent CVSS 3.1 scoring at 8.1 High (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H), CWE-98 confirmed, CISA SSVC data (exploitation: active, automatable: no), cisaExploitAdd: 2026-09-25, cisaActionDue: 2026-09-28, CISA-assigned name "WordPress Core Remote File Inclusion Vulnerability". | Yes |
| 1 | CISA Known Exploited Vulnerabilities catalog (cisa.gov, JSON feed) | Confirms KEV addition date 2026-09-25, due date 2026-09-28, knownRansomwareCampaignUse: Unknown, forensicTriage: Yes. | Yes |
| 1 | Patchstack, "Attackers Started Probing WordPress Sites Hours After the Patch" (two-part post, updated 2026-09-23) | Deepest operational detail available anywhere: the three-stage attack progression (recon → pearcmd reachability check → file write), exact pagename query-string shapes for each stage, the three pearcmd.php install paths attackers try, the dropped filenames, the two scanner user agents, payload variation (traversal depth, encoding case, GET vs POST, direct /index.php targeting), and the detection guidance this pack's native hunts are built from. | Yes, primary hunt-angle source |
| 1 | CrowdSec, VulnTracking Report "30,000 Addresses in Five Days" (crowdsec.net, published 2026-09-28) | Quantified exploitation telemetry: 322,680 signals 2026-09-23 to 2026-09-27, daily volume 14,938 → 124,154, distinct sources 237 → 23,321, 30,813 cumulative unique IPs by 2026-09-28, signals-per-source collapsing from ~63 to ~5 (mass commoditisation signature), CrowdSec virtual-patch rule id crowdsecurity/vpatch-CVE-2026-87902, explicit statement that a matching request is an attempt, not a confirmed compromise. | Yes |
| 2 | The Hacker News, "Attackers Exploit WordPress CVE-2026-87902 Within Hours of Disclosure" (2026-09-24, updated with the 2026-09-25 KEV addition) | Independent confirmation of the preconditions and timeline. Additionally reports a named third-party vendor (Previdian) honeypot observation: a single attacking IP and a GitHub-hosted PHP uploader used in one observed chain. See the provenance note below: this detail is carried as context only, not as a shipped indicator. | Partial, see note |
| 2 | SecurityWeek, "Critical WordPress Vulnerability Exploited Immediately After Disclosure" | Independent corroboration of the timeline, the three-stage progression, and the theme/pearcmd preconditions, citing Patchstack directly. | Yes |
Conflict noted, not resolved: WordPress's own advisory scores this CVSS 4.0 9.2 Critical, where the theme and server preconditions are modelled as "Attack Requirements" and complexity stays Low. NVD and CISA score the same flaw CVSS 3.1 8.1 High, where the identical preconditions are modelled as High Attack Complexity. Same vulnerability, two scoring frameworks, two numbers. This pack treats it as critical on the basis of unauthenticated code execution and CISA KEV inclusion, and records the disagreement rather than picking a winner. Verify against your own risk register's scoring convention before quoting a single number.
Single-sourced detail, deliberately not shipped as an indicator: The Hacker News quotes Previdian's founder describing honeypot traffic from one IP address (in the New Jersey area) that chained pearcmd.php inclusion, a file write to /tmp/, and then a second inclusion of a PHP uploader hosted on GitHub. This is a real and specific report, but it is corroborated by none of the other four sources in this table, and per this pack's provenance standard nothing ships as a confirmed indicator on a single citation. The IP and the GitHub path are discussed here for analyst context only; neither appears in Section 4's IOC table, Section 8's CQL, or Section 10's machine-readable appendix.
Provenance discipline: the raw fetched text of every source above is saved alongside this file in WordPress-CVE-2026-87902-RFI-Hunt-sources/ (eight snapshots: Patchstack, CrowdSec, The Hacker News, SecurityWeek, NVD, CISA KEV, the GHSA advisory, and the MITRE CVE record). Every atomic indicator shipped in Section 10 traces to one of those snapshots. Nothing in this pack was written from memory, and no fetched page contained instructions directed at an automated agent.
Hunt Brief & Attack Chain
Attack chain
| # | Step | Telemetry | Hunt angle |
|---|---|---|---|
| 1 | Stage-one recon: pagename traversal pointed at a harmless core file (wp-links-opml.php, wp-includes/feed-rss2.php, wp-cron.php, wp-login.php, install.php) to confirm the inclusion is live | Web server / WAF / CDN access log | Native hunt only (Section 7 N1). NO ENDPOINT TELEMETRY |
| 2 | Stage-two probe: pagename repointed at one of three known pearcmd.php install paths with +config-show appended, confirming PEAR is present and the $argv trick works | Web server access log | Native hunt only. NO ENDPOINT TELEMETRY |
| 3 | Stage-three write: same path with +config-create and attacker-controlled PHP content, writing a file to /tmp or /var/tmp | Web server access log; on the host, a new file appearing outside the web root | Native hunt N1/N3; Q3 if FIM covers those paths (rare, see caveat) |
| 4 | Dropped file is later reached, typically via a second LFI inclusion through the same pagename parameter, since files under /tmp are not normally web-reachable directly, and its PHP content executes inside the PHP-FPM/Apache worker | No new OS process yet; execution happens inside the existing web worker | Native hunt (web log for the second inclusion request) |
| 5 | If the payload calls shell_exec()/system()/proc_open(), the web-server worker spawns a shell or interpreter: the first point Falcon can see anything at all | ProcessRollup2 parent/child | Q1, the pack's highest-fidelity signal |
| 6 | Discovery: whoami, id, uname, hostname | ProcessRollup2 | Q2 |
| 7 | Second-stage retrieval via curl/wget/certutil.exe/powershell.exe | ProcessRollup2, NetworkConnectIP4 | Q5 |
| 8 | Persistence: cron entry, systemd unit, scheduled task, or an SSH authorized_keys drop | ProcessRollup2 | Q6, Q7 |
| 9 | Outbound C2 or exfiltration from the compromised web-tier host | NetworkConnectIP4 | Q8 |
Hunt hypotheses (ordered by fidelity)
| # | Hypothesis | MITRE | Falcon events | Expected FP sources | Conf |
|---|---|---|---|---|---|
| H1 | A web-server or PHP process on a WordPress host spawned an interactive shell or interpreter shortly after the flaw's disclosure window: the execution moment of the pearcmd-written payload | T1190, T1505.003, T1059.004, T1059.003 | ProcessRollup2 / SyntheticProcessRollup2 | CMS cron/health-check scripts, backup plugins, WP-CLI wrappers, deploy hooks legitimately shelling out as the web user | HIGH |
| H2 | Host and user discovery commands ran under a web-server process tree in the same window | T1033, T1082 | ProcessRollup2 | Monitoring agents and container health checks running as the web user | HIGH |
| H3 | A web-server process launched a download utility with a URL in the command line, pulling a second stage | T1105 | ProcessRollup2 | Plugin/theme update routines, composer/npm installs run as the web user | HIGH |
| H4 | Persistence was established from a web-server process tree (cron, systemd, scheduled task) or an SSH key was written/modified from that tree | T1053.003, T1053.005, T1098.004 | ProcessRollup2 | Shared-hosting control panels that register cron as the web user | MEDIUM |
| H5 | A new PHP file was written outside the theme directory or under /tmp, /var/tmp by a web-server process | T1505.003 | CriticalFileModified (FIM-dependent) | Legitimate temp-file usage by session handlers, caching layers, upload processing | MEDIUM |
| H6 | The exact reported dropped filenames (wp-pear-rce-flag.php, poc87902.php, or the luci_/zeta_ random-prefix pattern) appear in file-write telemetry | T1505.003 | CriticalFileModified, NewExecutableWritten, ELFFileWritten | None expected: these are scanner-generated proof-of-execution markers, not benign filenames | HIGH |
| H7 | A WordPress web-server host made an outbound connection to a destination outside its normal CDN/package-mirror allowlist shortly after a Q1 hit | T1071.001, T1105 | NetworkConnectIP4 | Legitimate plugin/theme update traffic, license-check callbacks, analytics beacons | LOW-MEDIUM |
| H8 | A rare, never-before-seen child process appeared under a web-server parent across the estate | T1190, T1505.003 | ProcessRollup2 | High by design: this is a stack-ranking hunt, not an alert | MEDIUM |
Consolidated IOC Table
| Type | Value | Conf | Action | Context | Expiry |
|---|---|---|---|---|---|
| filename | wp-pear-rce-flag.php | HIGH | hunt | Dropped stage-three artifact in /tmp or /var/tmp (Patchstack, The Hacker News). Not a Falcon Custom IOC importable type, see Section 10. | 2026-12-29 |
| filename | poc87902.php | HIGH | hunt | Dropped stage-three artifact; harmless proof-of-execution marker (Patchstack, The Hacker News) | 2026-12-29 |
| filename-pattern | luci_<random>.php | MEDIUM | hunt | Randomised dropped-filename prefix observed by Patchstack and The Hacker News. Hunted as a regex, not an exact string. | 2026-12-29 |
| filename-pattern | zeta_<random>.php | MEDIUM | hunt | Randomised dropped-filename prefix (Patchstack, The Hacker News) | 2026-12-29 |
| user-agent | cve-2026-87902-poc/1.0 | HIGH | detect | Named PoC/scanner user agent (Patchstack, CrowdSec). Web/proxy logs only, invisible to the endpoint sensor. | 2026-12-29 |
| user-agent | nuclei-cve-2026-87902/1.0 | HIGH | detect | Named public Nuclei template user agent (Patchstack, CrowdSec). Web/proxy logs only. | 2026-12-29 |
| uri-param | pagename containing .. or %2e%2e (incl. double-encoded %252e%252e) | HIGH | hunt | Core traversal marker (Patchstack). Query string or POST body. Web logs only. | 2026-12-29 |
| uri-param | pagename beginning with templates/ or another page- directory name | HIGH | hunt | Payload must continue a real page-* directory before it can traverse out (Patchstack). Web logs only. | 2026-12-29 |
| uri-param-pair | pagename and page_id present together on the site root or /index.php | HIGH | hunt | Without a resolvable page_id the vulnerable code path is never reached, so this pairing rarely occurs in benign traffic (Patchstack). Web logs only. | 2026-12-29 |
| uri-marker | request containing pearcmd, +config-show or +config-create | HIGH | hunt | Stage-two/stage-three escalation markers (Patchstack, CrowdSec, The Hacker News). Web logs only. | 2026-12-29 |
| uri-path | wp-links-opml.php, wp-cron.php, wp-includes/feed-rss2.php requested via pagename, with a 200 response returning OPML or RSS content | MEDIUM | hunt | Stage-one confirmation signal: the response body proves the inclusion ran (Patchstack). Web logs only. | 2026-12-29 |
| rule-id | crowdsecurity/vpatch-CVE-2026-87902 | INFO | control | CrowdSec AppSec virtual-patch rule name (CrowdSec). This is a mitigating control, not an indicator of compromise. | n/a |
Read the Action column before you build anything from this table. Every row here is request-level or filesystem-level, not a hash or a network indicator, and none of it appears in Falcon endpoint telemetry directly. No malware hashes and no payload-hosting infrastructure have been confirmed across two or more of this pack's sources as of 2026-09-29 (see the single-sourced note in Section 2), so nothing here ships as a Falcon Custom IOC Management row. The commodity attacking-IP set CrowdSec measured (30,813 addresses and rising) is deliberately not listed as a blocklist: at that scale and turnover rate a static IP list is stale before it is imported, and blocking by source address teaches nothing about whether a given host was actually compromised.
Affected Surface & Telemetry Matrix
| Surface | Required telemetry | Priority | Gap risk |
|---|---|---|---|
| Linux WordPress hosts (Apache/nginx + php-fpm) | Falcon sensor, ProcessRollup2 with full parent lineage | CRITICAL | Low if the sensor is installed. This is where Q1/Q2/Q5/Q6/Q7 land. |
| Windows WordPress hosts (IIS + w3wp.exe / php-cgi.exe) | Falcon sensor, ProcessRollup2 | HIGH | Low. Rarer deployment for WordPress specifically, identical detection logic; every query in Section 8 includes the Windows web-server and shell binaries alongside the Linux ones. |
| Containerised WordPress (Docker / Kubernetes) | Falcon Container sensor or node-level sensor with container visibility | HIGH | GAP The official PHP Docker image ships with register_argc_argv enabled by default, per the vendor advisory, which makes containerised deployments disproportionately likely to hit the full RCE chain. A node-only sensor may lose pod attribution. Verify before trusting Q1 results here. |
| Managed / third-party WordPress hosting | None, no sensor deployable | HIGH | GAP Entirely dependent on the provider. Request patch attestation and access logs for the window from 2026-09-22 onward. |
| WAF / CDN / reverse proxy edge | HTTP access logs shipped to NG-SIEM or a log platform | CRITICAL | PARTIAL This is the only place the pagename traversal, the pearcmd markers and the two scanner user agents are visible. If these logs are not centralised, chain steps 1 through 3 are undetectable. |
| Filesystem outside the web root (/tmp, /var/tmp) | FileVantage/FIM policy explicitly extended to cover these paths, or scheduled host-side scanning | HIGH | GAP Falcon emits no generic write event for a PHP text file, and FIM policies covering /tmp specifically are unusual (most estates scope FIM to the web root, if at all). Without it, Q3 and Q4 return nothing regardless of compromise, and the host-side find in Section 7 N3 is the only coverage. |
| PHP runtime configuration (register_argc_argv, pearcmd.php presence) | Configuration management / asset inventory, not Falcon telemetry | CRITICAL | GAP Whether a given host is escalatable to RCE at all depends entirely on this setting and this file's presence, and Falcon has no native visibility into php.ini. Section 10's audit block covers this. |
ATT&CK Mapping
| Tactic | Technique | Observed behaviour | Query / control |
|---|---|---|---|
| Reconnaissance | T1595.002 : Active Scanning: Vulnerability Scanning | Stage-one probes against harmless core files to confirm the inclusion is live, at scale via a named Nuclei template | Native hunt N1/N2. NO ENDPOINT TELEMETRY |
| Initial Access | T1190 : Exploit Public-Facing Application | Unauthenticated pagename path traversal reaching get_page_template(), escalated through pearcmd.php | Native hunt N1/N2; controls H1, H2 |
| Execution | T1059.004 : Unix Shell | php-fpm/httpd/apache2/nginx spawning sh or bash once the dropped payload runs | Q1 |
| Execution | T1059.003 : Windows Command Shell | w3wp.exe or php-cgi.exe spawning cmd.exe or powershell.exe on IIS-hosted WordPress | Q1 |
| Persistence | T1505.003 : Server Software Component: Web Shell | Attacker-controlled PHP written via pearcmd config-create to /tmp or /var/tmp | Q3, Q4; native hunt N3 |
| Persistence | T1053.003 / T1053.005 : Cron / Scheduled Task | Scheduled execution created from the web-server process tree | Q6 |
| Persistence | T1098.004 : Account Manipulation: SSH Authorized Keys | SSH key material written or authorized_keys modified from a web-server process tree | Q7 |
| Defense Evasion | T1027 : Obfuscated Files or Information | Patchstack reports one payload family assembling its marker string via chained chr() calls rather than a literal string | Native hunt N3 (grep for the resulting marker or for chr( chains in dropped PHP) |
| Discovery | T1082 / T1033 : System & Owner/User Discovery | id, whoami, uname, hostname under a web-server parent | Q2 |
| Command and Control | T1105 : Ingress Tool Transfer | curl/wget/certutil.exe/powershell.exe pulling a second stage from a web-server parent | Q5 |
| Command and Control | T1071.001 : Web Protocols | Outbound connections from the compromised web-tier host to non-CDN, non-mirror destinations | Q8 |
| Discovery (of the estate) | T1190 (stack-rank) | Rare, never-before-seen children of web-server parents across the fleet, catching payload families with no published name | Q9 |
Native Audit-Log Hunts (non-CQL)
Why this section exists. Steps 1 through 3 of the attack chain (recon, pearcmd reachability check, file write) leave no endpoint trace at all. They live entirely in web-server, WAF and CDN logs. An EDR sensor cannot see a pagename parameter. Treat the checks below as first-class hunt work, not as an appendix to the CQL, and note explicitly: a request that never got past the theme-directory precondition leaves no artifact anywhere, on the host or in a response body that differs from a normal 404. Absence of a hit here is not proof the host was never probed.
N1 · Web-server access logs, exploitation attempts and successes
Run on each WordPress host, or against centralised HTTP logs. Cover 2026-09-21 onward, or from the last known-good backup if earlier.
# The two published exploitation/scanner user agents grep -aEi 'cve-2026-87902-poc|nuclei-cve-2026-87902' /var/log/nginx/access.log* /var/log/apache2/access.log* # Core traversal marker in the pagename parameter, query string or POST body, # single or double URL-encoded grep -aEi 'pagename=[^ ]*(%2e%2e|%252e%252e|\.\.)' /var/log/nginx/access.log* /var/log/apache2/access.log* # pearcmd escalation markers -- stage two (reachability) and stage three (write) grep -aEi 'pearcmd|\+config-show|\+config-create' /var/log/nginx/access.log* /var/log/apache2/access.log* # pagename and page_id co-occurring at the site root or /index.php -- the pairing # needed to actually reach the vulnerable code path grep -aEi '(\?|&)page_id=[0-9]+.*pagename=|pagename=.*(\?|&)page_id=[0-9]+' /var/log/nginx/access.log* /var/log/apache2/access.log* # Stage-one confirmation: a 200 response to a pagename-driven request for a core # file that should never render standalone awk '$0 ~ /pagename=/ && ($9 == 200)' /var/log/nginx/access.log | grep -aEi 'wp-links-opml|feed-rss2|wp-cron'
Read the response body, not just the status code, on that last check. Per Patchstack, a 200 response to a pagename-driven request for wp-links-opml.php or wp-includes/feed-rss2.php that actually returns OPML or RSS content is the confirmation the inclusion ran on that host. That is a materially stronger finding than a blocked or 404'd probe, and it means the exposure window should be treated as a confirmed vulnerable period, not merely a scanned one.
N2 · WAF / CDN edge
- Confirm a block rule exists for the
pagenametraversal pattern in both the query string and the POST body. WordPress readspagenamefrom the POST body in preference to the query string, and Patchstack reports POST has overtaken GET as the more common delivery method. - If you run CrowdSec, confirm the
crowdsecurity/vpatch-CVE-2026-87902AppSec rule is enabled and set to block, not log. - Confirm the rule matches traversal depth from one to twelve levels and both single and double percent-encoding (including uppercase hex), per the payload variation Patchstack has observed. A rule anchored to one exact depth or encoding will miss most of the traffic.
N3 · Filesystem outside the web root, dropped-payload hunt
# Any PHP file in /tmp or /var/tmp created or modified since the day before disclosure
find /tmp /var/tmp -maxdepth 2 -name '*.php' -newermt '2026-09-21' -printf '%T+ %s %p\n' 2>/dev/null | sort
# The two exact reported dropped filenames, anywhere under /tmp or /var/tmp
find /tmp /var/tmp -maxdepth 2 \( -name 'wp-pear-rce-flag.php' -o -name 'poc87902.php' \) 2>/dev/null
# The randomised-prefix pattern
find /tmp /var/tmp -maxdepth 2 -regextype posix-extended -regex '.*/(luci_|zeta_)[A-Za-z0-9]+\.php' 2>/dev/null
# Confirm whether pearcmd.php exists and is readable at any of the three known paths
for p in /usr/local/lib/php/pearcmd.php /usr/share/php/pearcmd.php /usr/share/pear/pearcmd.php; do
[ -r "$p" ] && echo "READABLE: $p"
done
# Suspicious shell-out primitives, or the chr()-assembled marker pattern Patchstack
# reported, in any PHP file dropped since disclosure
grep -rlE 'shell_exec|passthru|proc_open|popen|(chr\([0-9]+\)\s*\.\s*){6,}' /tmp /var/tmp --include='*.php' 2>/dev/null
A file in /tmp is not normally reachable over the web on its own; per Patchstack this is evidence of proof of execution, not necessarily a persistent web-reachable backdoor. Treat any hit above as a confirmed compromise regardless of whether the file is externally reachable, since the same file-write primitive can be pointed at a more useful location on a second attempt.
N4 · PHP runtime and theme precondition audit
- Check
register_argc_argvin everyphp.ini/ pool configuration in the estate.Onplus a readablepearcmd.phpis what turns this from an information leak into code execution. - Enumerate active themes for a top-level directory whose name starts with
page-. Twenty Twelve, Twenty Fourteen, Neve, Hestia and Sydney are named in the advisory as meeting this condition; a custom or unlisted theme can too. - Confirm WordPress core version on every install. Anything below 7.1.2 on the 7.1 branch, 7.0.6 on the 7.0 branch, 6.9.9 on the 6.9 branch, 6.8.10 on the 6.8 branch, or the equivalent backported fix on any older branch down to 4.7.37, is exposed to the LFI regardless of the RCE preconditions.
CrowdStrike LogScale CQL Hunt Queries
Scope note, endpoint telemetry only. None of the queries below can see an HTTP request path, a response code, or a user-agent string. Falcon's sensor observes processes, files and sockets, not the web server's request handling. Every query here therefore targets what the exploit chain does after the dropped payload executes. The request-level indicators are hunted in Section 7 against web and proxy logs. If you have HTTP logs in NG-SIEM the same markers can be queried there, but field names are parser-specific to your ingest and must be validated against a real sample row before use; this pack does not guess at them.
No query carries an in-query time filter. Set the window with the Falcon console time picker; each card records the intended lookback as a // LOOKBACK: comment. Start at 30 days and widen to cover the interval from 2026-09-22 to the moment your estate patched. Where a query targets both platforms, Linux and Windows events differ (ELFFileWritten is Linux-only, NewExecutableWritten is Windows-only, ProcessRollup2 covers both); each card's // REQUIRES line says which.
Looks for: the execution moment of the pearcmd-written payload, a PHP interpreter or web-server worker becoming the parent of a shell. This is the single highest-value query in the pack because it fires regardless of which dropped filename appears, regardless of whether the request ever gets logged centrally, and it is the first point in the whole chain where Falcon has any visibility at all. FP: CMS cron jobs, backup and migration plugins, WP-CLI wrappers and deploy hooks all legitimately shell out as the web user; baseline by parent command line and by host before alerting.
// HUNT: Web-server or PHP process spawning a shell or interpreter (post-exploitation execution) // MITRE: T1190, T1505.003, T1059.004, T1059.003 | CONF: high FP: medium COST: low // REQUIRES: ProcessRollup2 with parent lineage. Covers both Linux (php-fpm/httpd/nginx -> sh/bash) // REQUIRES: and Windows (w3wp.exe/php-cgi.exe -> cmd.exe/powershell.exe) web hosts in one query. // FALSE POSITIVES: CMS cron jobs, backup/migration plugins, WP-CLI wrappers, deploy hooks // TUNING: exclude your deploy and backup service accounts by UserName, and your CI/CD build hosts // TUNING: by ComputerName; then re-run and treat whatever remains as a genuine lead // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php[0-9.]*-fpm|php-cgi|httpd|apache2|nginx|lsphp|litespeed|w3wp\.exe)$/i | FileName=/^(sh|bash|dash|zsh|ksh|busybox|python[0-9.]*|perl|ruby|node|cmd\.exe|powershell\.exe|pwsh\.exe)$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: the first thing an operator runs after the dropped payload executes: basic host and identity orientation. Grouping by host and parent turns this into a short triage list rather than an event firehose. FP: monitoring agents and container health-check scripts run these constantly as the web user; exclude the specific parent command line of your monitoring stack rather than the binary names, which are the signal.
// HUNT: Discovery commands executed under a web-server parent (post-exploitation recon) // MITRE: T1033, T1082 | CONF: high FP: medium COST: low // REQUIRES: ProcessRollup2 with parent lineage on web hosts, Linux and Windows // FALSE POSITIVES: monitoring agents, container health checks and readiness probes running as the web user // TUNING: exclude the ComputerName of dedicated build and monitoring boxes; exclude the UserName your // TUNING: observability agent runs as. Do NOT exclude the binaries themselves - they are the signal. // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(sh|bash|dash|php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|w3wp\.exe)$/i | FileName=/^(whoami|id|uname|hostname|hostnamectl|ifconfig|ip|netstat|ss|ps|env|lsb_release|systeminfo\.exe|net\.exe|net1\.exe|nslookup)$/i | groupBy([ComputerName, UserName, ParentBaseFileName], function=[count(as=Hits), collect([FileName, CommandLine], limit=40)], limit=200) | sort(Hits, order=desc, limit=100)
Looks for: the pearcmd config-create write itself. Read this caveat before trusting an empty result: Falcon emits no generic write event for a PHP text file, so this query only returns data if a FileVantage or equivalent FIM policy has been explicitly extended to cover /tmp and /var/tmp, which is unusual (most FIM policies scope to the web root, if anywhere). On an estate without that coverage this query is silent no matter how many payloads were dropped, and the host-side find in Section 7 N3 is the only real coverage of this step. FP: legitimate temp-file usage by session handlers, upload processing and caching layers is common; correlate every hit against Q1 on the same host before escalating.
// HUNT: PHP file written under /tmp or /var/tmp (pearcmd config-create artifact) via FIM telemetry // MITRE: T1505.003 | CONF: medium FP: medium COST: low // REQUIRES: CriticalFileModified - needs a FileVantage/FIM policy covering /tmp and /var/tmp, which is // REQUIRES: atypical. Without that policy this query returns nothing even on a compromised host - see // REQUIRES: Section 7 N3 for the host-side scan that is the real coverage of this step. // FALSE POSITIVES: legitimate temp-file writes by session handlers, upload processing, caching layers // TUNING: correlate every survivor against Q1 on the same ComputerName within a few minutes; a lone // TUNING: temp-file write with no shell nearby is usually unrelated application behaviour // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^CriticalFileModified$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|w3wp\.exe)$/i | TargetFileName=/\/(tmp|var\/tmp)\/[^\/]+\.php$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, TargetFileName, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: the two exact reported filenames and the two randomised-prefix patterns, matched on basename only so no path separator needs escaping inside the regex. Same FIM-coverage caveat as Q3 applies; this query is a bonus check that costs nothing to run, not a substitute for the Section 7 N3 filesystem scan. FP: none expected. wp-pear-rce-flag.php and poc87902.php are scanner-generated proof-of-execution markers with no legitimate purpose; the luci_/zeta_ prefixes are similarly not a naming convention any real WordPress component uses.
// HUNT: Published CVE-2026-87902 dropped-payload filename in file-write telemetry // MITRE: T1505.003 | CONF: high FP: low COST: low // REQUIRES: CriticalFileModified - same FIM-on-/tmp caveat as Q3. Matched on basename via FileName so // REQUIRES: no path separator appears inside the regex. // FALSE POSITIVES: none expected - any hit is a confirmed incident // LOOKBACK: 90d (set in the console time picker) #event_simpleName=/^CriticalFileModified$/ | FileName=/^(wp-pear-rce-flag\.php|poc87902\.php|luci_[a-z0-9]{4,}\.php|zeta_[a-z0-9]{4,}\.php)$/i | table([@timestamp, ComputerName, UserName, FilePath, FileName, TargetFileName, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: second-stage retrieval, the step between "I have a one-shot marker-writing PoC" and "I have a functional implant." Requiring a URL-ish token in the command line keeps this quieter than matching the binaries alone. FP: plugin and theme update routines, composer and npm all fetch over HTTPS as the web user; exclude fetches to your package mirror and to wordpress.org rather than excluding curl outright.
// HUNT: Download utility launched by a web-server process (second-stage retrieval) // MITRE: T1105 | CONF: high FP: medium COST: low // REQUIRES: ProcessRollup2 with CommandLine, Linux and Windows // FALSE POSITIVES: plugin/theme update routines, composer and npm installs run as the web user // TUNING: exclude CommandLine values pointing at your internal package mirror and at wordpress.org; // TUNING: exclude CI/CD hosts by ComputerName. Keep curl and wget in scope - narrow the destination. // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|sh|bash|dash|w3wp\.exe)$/i | FileName=/^(curl|wget|fetch|bitsadmin\.exe|certutil\.exe|powershell\.exe|pwsh\.exe|python[0-9.]*)$/i | CommandLine=/(http:|https:|ftp:|--output|-OutFile|Invoke-WebRequest|DownloadString|DownloadFile|urlcache)/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: an attacker converting a one-shot LFI hit into something that survives a patch and a cleanup: a cron entry, a systemd unit, a scheduled task, or a new local account. The web-server user should essentially never invoke these. A hit here is one of the strongest single signals in the pack. FP: low; some shared-hosting control panels register cron as the web user, worth confirming once per estate and documenting.
// HUNT: Persistence mechanism created from a web-server process tree // MITRE: T1053.003, T1053.005 | CONF: high FP: low COST: low // REQUIRES: ProcessRollup2 with parent lineage, Linux and Windows // FALSE POSITIVES: rare - some shared-hosting control panels register cron jobs as the web user // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|sh|bash|dash|w3wp\.exe|cmd\.exe|powershell\.exe)$/i | FileName=/^(crontab|at|systemctl|systemd-run|schtasks\.exe|sc\.exe|reg\.exe|useradd|adduser|usermod)$/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: the specific persistence path called out for this hunt angle: an attacker appending their own public key to authorized_keys, or generating a new key pair, from a process tree rooted at the web server. This is a durable foothold that survives a WordPress-level cleanup entirely. FP: low; legitimate automation that manages SSH keys from a web-server account is rare and worth an explicit exception if found.
// HUNT: SSH key material touched from a web-server process tree (authorized_keys persistence) // MITRE: T1098.004, T1552.004 | CONF: medium FP: low COST: low // REQUIRES: ProcessRollup2 with CommandLine on Linux/Unix web hosts // FALSE POSITIVES: rare - configuration management tooling that legitimately provisions SSH keys // TUNING: exclude your CM tool's binary and its service account if it manages keys by design // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|sh|bash|dash)$/i | CommandLine=/(authorized_keys|ssh-keygen|\.ssh\/id_rsa|\.ssh\/id_ed25519)/i | table([@timestamp, ComputerName, UserName, ParentBaseFileName, FileName, CommandLine, aid]) | sort(@timestamp, order=desc, limit=200)
Looks for: C2 or exfiltration traffic leaving the web tier directly from the server process, rather than from a spawned child. No confirmed C2 infrastructure has been published for this campaign (see Section 2), so this query cannot key on a known-bad destination; it ranks every outbound peer instead and lets rarity surface the interesting ones. FP: high by construction. A public web server legitimately reaches package mirrors, license-check endpoints, CDNs and its own database; this must never be promoted to a Scheduled Search without a maintained CDN/mirror exclusion list built from your own baseline.
// HUNT: Web-server process making outbound connections, ranked by destination rarity // MITRE: T1071.001 | CONF: medium FP: high COST: medium // REQUIRES: NetworkConnectIP4, Linux and Windows web hosts // FALSE POSITIVES: high by design - package mirrors, license-check callbacks, CDN edges, your own DB // TUNING: run once to baseline, then exclude your known CDN/mirror/DB destinations by RemoteAddressIP4 // TUNING: or by ASN if your pipeline enriches it; re-run and read only what is left. Never promote this // TUNING: query to a Scheduled Search without that exclusion list built from your own baseline first. // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^NetworkConnectIP4$/ | ContextBaseFileName=/^(php|php-fpm[0-9.]*|php-cgi|httpd|apache2|nginx|w3wp\.exe)$/i | !cidr(RemoteAddressIP4, subnet=["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16","127.0.0.0/8"]) | groupBy([ComputerName, RemoteAddressIP4], function=[count(as=Hits), collect([RemotePort], limit=10)], limit=500) | sort(Hits, order=asc, limit=150)
Looks for: everything Q1 and Q2 did not think to name. Instead of an allowlist of suspicious binaries this ranks every child of a web-server parent by rarity, ascending, so payloads nobody has published a signature for yet float to the top. Run it once to build the estate baseline, then re-run weekly and read only the new arrivals. FP: high by construction; this is a stack-ranking hunt, not an alert, and must never be promoted to a Scheduled Search without a hard exclusion list.
// HUNT: Rare child processes of web-server parents (catch-all for unnamed payloads) // MITRE: T1190, T1505.003 | CONF: medium FP: high COST: medium // REQUIRES: ProcessRollup2 across every web host in the estate, Linux and Windows // FALSE POSITIVES: high by design. The common rows are your normal; the sparse tail is the signal. // TUNING: read only rows where Hosts is 1 or 2 - a child seen fleet-wide is infrastructure, not an // TUNING: intrusion. Once baselined, exclude your CMS cron and backup binaries by FileName. Never // TUNING: promote this query to a Scheduled Search without that exclusion list in place. // LOOKBACK: 30d (set in the console time picker) #event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ | ParentBaseFileName=/^(php|php-fpm[0-9.]*|php[0-9.]*-fpm|php-cgi|httpd|apache2|nginx|lsphp|litespeed|w3wp\.exe)$/i | groupBy([FileName], function=[count(as=Execs), count(ComputerName, distinct=true, as=Hosts), collect([CommandLine], limit=5)], limit=500) | sort(Execs, order=asc, limit=120)
Custom IOA Recommendations & Alert Packaging
Custom IOA candidates
| IOA name | Pattern | Exclusions | Action | From |
|---|---|---|---|---|
| WEBSHELL – Web Server Spawns Shell | Process creation where the parent image is php-fpm, php, httpd, apache2, nginx, lsphp or w3wp.exe and the child image is a shell or scripting interpreter | Deploy and backup service accounts; CI/CD hosts; documented control-panel helpers | Detect (Critical) on WordPress host groups; start in Monitor for 7 days | Q1 |
| WEBSHELL – Web Server Persistence Attempt | Parent image is a web-server or PHP process and the child image is crontab, systemctl, systemd-run, schtasks.exe, sc.exe, useradd or usermod | Control panels that register cron as the web user (document per host group) | Detect (High), very low volume, safe to promote quickly | Q6 |
| WEBSHELL – SSH Key Written by Web Server | Parent image is a web-server or PHP process and the command line references authorized_keys or ssh-keygen | Configuration management tooling with a documented service account | Detect (High) after one baseline cycle | Q7 |
| WEBSHELL – Web Server Retrieves Remote Payload | Parent image is a web-server or PHP process, child is curl/wget/certutil.exe, command line contains a URL scheme | Internal package mirror; wordpress.org update endpoints | Monitor first, noisier than the other three | Q5 |
Not IOA candidates: Q2, Q3, Q4, Q8 and Q9 stay Investigate-only. Q2 is a volume hunt best triaged in bulk, Q3 and Q4 depend on FIM policy coverage of /tmp that varies wildly by host group, Q8 and Q9 are explicitly stack-ranking hunts with FP high by design, and none of the four should fire an alert until they have been baselined per-estate. Promoting any of them without the tuning in their cards will train analysts to ignore the whole rule family.
Scheduled Search packaging (for the promoted IOAs)
| Field | Value |
|---|---|
| Scheduled Search name | DETECT - Web Server Spawns Shell (CVE-2026-87902 WordPress RFI) |
| Description | Fires when a PHP interpreter or web-server worker becomes the parent of a shell or scripting interpreter. This is the execution signature of the pearcmd-written payload for this campaign and of web-to-shell chains generally, so it retains value beyond this specific CVE. |
| Schedule | Every 15 minutes, 30-minute lookback with overlap |
| Alert subject | [CRITICAL] Detection: CVE-2026-87902 webshell execution, web server spawned a shell |
Alert email body (template)
WHAT FIRED
A web-server or PHP process spawned an interactive shell or scripting interpreter
on a host in the WordPress server group.
Host : {{ComputerName}}
User : {{UserName}}
Parent : {{ParentBaseFileName}}
Child : {{FileName}}
Command line : {{CommandLine}}
First seen : {{@timestamp}}
WHAT IT MEANS
A healthy web server almost never launches a shell. This parent-child pair is the
execution signature of a web shell. Given active in-the-wild exploitation of
CVE-2026-87902 (WordPress page-template path traversal to pearcmd RCE), treat this
as a probable post-exploitation event until proven otherwise.
IMMEDIATE ACTIONS
1. Do not reboot or reimage yet, capture volatile state first.
2. Network-contain the host in Falcon if the command line shows recon,
credential access, or an outbound download.
3. Confirm the WordPress version. Anything below 7.1.2 / 7.0.6 / 6.9.9 / 6.8.10
(or the branch-matched backport) is vulnerable; treat the host as compromised.
4. Run the Section 7 N3 filesystem hunt (/tmp, /var/tmp) on this host.
5. Preserve the web-server access log before rotation removes the request that
triggered the shell.
ESCALATION
Confirmed webshell -> incident response, severity 1
Unexplained but clean -> hunt lead, 24h follow-up
Matched exclusion -> tune the rule, record the exclusion, close
L1 triage checklist
- Record host, user, parent, child and full command line from the detection before touching anything.
- Check the WordPress version on the host. A vulnerable version plus this alert equals a presumed compromise.
- Pivot the host into Q2, Q5, Q6 and Q7 scoped to the same
ComputerNameand a window of a few hours either side. A lone shell is ambiguous; a shell followed bywhoamiandcurlis not. - Run the Section 7 N3 filesystem hunt on the host: recently modified PHP in
/tmp//var/tmp, the two exact filenames, and theluci_/zeta_pattern. - Grep the web-server access log for the
pagenametraversal marker, the pearcmd markers, and the two user agents, restricted to the hours before the alert. - Check whether
register_argc_argvis On and whetherpearcmd.phpis present and readable on the host. If both, the RCE precondition was met and this alert should be treated at higher confidence. - If two or more of steps 4 to 6 return findings, escalate to incident response and move to the Section 14 containment runbook. If all are clean and the parent command line matches a documented exclusion, tune and close with the exclusion recorded.
Machine-Readable IOC Appendix
type,value,action,severity,expiration,description,tags sha256,REPLACE_WITH_SHA256_OF_YOUR_OWN_RECOVERED_DROPPED_PHP_FILE,prevent,critical,2026-12-29,CVE-2026-87902 locally recovered pearcmd-dropped PHP payload,campaign:cve-2026-87902 # No file hashes and no payload-hosting infrastructure have been published across two # or more of this pack's sources as of 2026-09-29 (see Section 2 for the single-sourced # exception, which is deliberately not shipped here). The two reported dropped-file # names are literal filenames, not hashes or domains, and Falcon Custom IOC Management # accepts only sha256, md5, domain, ipv4 and ipv6 - a filename type cannot be imported. # They are hunted via FileName regex in Q4 and via the host-side find in Section 7 N3 # instead. If you recover a sample locally, compute its SHA256 and replace the row above. # wp-pear-rce-flag.php # poc87902.php # luci_<random>.php # zeta_<random>.php
PROCESS LINEAGE
php | php-fpm | php-cgi | httpd | apache2 | nginx | lsphp | w3wp.exe
-> sh | bash | dash | zsh | busybox | python | perl | cmd.exe | powershell.exe
same parents -> whoami | id | uname | hostname | ss | netstat
same parents -> curl | wget | certutil.exe (command line contains a URL)
same parents -> crontab | systemctl | schtasks.exe | useradd
same parents -> ssh-keygen | commands referencing authorized_keys
FILESYSTEM
new or modified *.php under /tmp or /var/tmp (NOT the WordPress web root - this
campaign drops outside it, unlike a typical webshell-in-plugins pattern)
exact filenames: wp-pear-rce-flag.php | poc87902.php
pattern filenames: luci_<random>.php | zeta_<random>.php
marker string CVE-2026-87902-POC-OK, or an obfuscated marker assembled via
chained chr() calls (reported form: LUCIFER-RCE-OK)
pearcmd.php present and readable at one of three install paths:
/usr/local/lib/php/pearcmd.php | /usr/share/php/pearcmd.php | /usr/share/pear/pearcmd.php
HTTP (web / WAF / proxy logs only - NOT visible to the endpoint sensor)
pagename parameter containing .. or %2e%2e, single or double encoded, in the
query string or the POST body (POST has overtaken GET as the common method)
pagename beginning with templates/ or another page-<name> directory
pagename and page_id present together on the site root or /index.php
request containing pearcmd, +config-show, or +config-create
User-Agent contains: cve-2026-87902-poc/1.0 | nuclei-cve-2026-87902/1.0
200 response to a pagename-driven request for wp-links-opml.php, wp-cron.php or
wp-includes/feed-rss2.php that returns actual OPML/RSS content (confirms the
inclusion ran, not just that it was attempted)
CAMPAIGN None. No vendor-assigned campaign or actor name has been published for this
exploitation activity; reporting refers to it by CVE only. CISA's assigned
vulnerability name is "WordPress Core Remote File Inclusion Vulnerability".
CVE CVE-2026-87902 WordPress core page-template path traversal / LFI, conditional RCE
CVSS 4.0: 9.2 Critical (WordPress/GHSA) CVSS 3.1: 8.1 High (NVD/CISA) - disputed, see Section 2
CWE-98 Remote File Inclusion (authoritative, MITRE CVE record). Patchstack additionally
describes it as "Path Traversal leading to Local File Inclusion" (CWE-22 family behaviour).
DISCOVERY Robert Ressl, via the WordPress HackerOne programme
DISCLOSED 2026-09-22 EXPLOITED ITW from 2026-09-22 11:49 UTC (Patchstack), first file-write attempt
2026-09-22 15:34 UTC. KEV added 2026-09-25, federal deadline 2026-09-28.
VULNERABLE 4.7.0 - 7.1.1 across every branch (full per-branch matrix in GHSA-7hp8-65ch-5whp)
PATCHED 7.1.2 | 7.0.6 | 6.9.9 | 6.8.10 and backports on every branch down to 4.7.37
ROOT CAUSE get_page_template() builds a template filename from the pagename request parameter.
WordPress's sanitiser strips literal ../ but preserves percent-encoded octets; a later
urldecode() turns a double-encoded traversal payload into a real path, and the resulting
file is loaded with include(). The code path skips the validate_file() check used
elsewhere in core for the same class of filename.
RCE PRECONDITIONS (both required)
1. Active theme has a top-level directory starting with page- (Twenty Twelve, Twenty
Fourteen, Neve, Hestia, Sydney are named; a custom theme can also qualify)
2. A readable local .php file exists for pearcmd.php RCE: register_argc_argv On
(default in the official PHP Docker image and cPanel PHP < 8.5) plus pearcmd.php
present at a standard PEAR install path
ATTACK PROGRESSION (Patchstack, three stages)
1. Recon: pagename points at a harmless core file to confirm the inclusion is live
2. pearcmd reachability: pagename + config-show confirms PEAR present and argv works
3. File write: pagename + config-create writes attacker PHP to /tmp or /var/tmp
SCALE (CrowdSec, 2026-09-23 to 2026-09-28)
322,680 signals over 5 days, daily volume 14,938 -> 124,154
distinct sources 237 -> 23,321; 30,813 cumulative unique IPs by 2026-09-28
signals-per-source fell from ~63 to ~5 (mass scanner commoditisation)
CAVEAT No malware hashes and no corroborated (two-plus-source) payload-hosting
infrastructure exist for this campaign as of 2026-09-29. Treat any IOC feed
claiming otherwise with the same scrutiny this pack applied in Section 2.
# 1. Enumerate WordPress versions across the estate
find / -name version.php -path '*wp-includes*' 2>/dev/null \
| while read -r f; do printf '%s ' "$f"; grep -m1 wp_version "$f"; done
# 2. With WP-CLI, per site root
wp core version --allow-root
wp core check-update --allow-root
wp theme list --fields=name,status --allow-root
# 3. Confirm the RCE preconditions on each host
php -i 2>/dev/null | grep -i register_argc_argv
for p in /usr/local/lib/php/pearcmd.php /usr/share/php/pearcmd.php /usr/share/pear/pearcmd.php; do
[ -r "$p" ] && echo "READABLE: $p"
done
find /var/www -maxdepth 3 -type d -iname 'page-*' -path '*wp-content/themes*'
# 4. Confirm the traversal is actually blocked at the edge post-mitigation.
# A 403/404 with NO OPML/RSS body is the pass condition.
curl -sk -o /dev/null -w '%{http_code} traversal probe\n' \
'https://SITE/?page_id=1&pagename=templates%252f..%252f..%252fwp-links-opml'
# 5. Falcon sensor coverage - every WordPress host must have one, containers included.
Provenance: both dropped-payload filenames, both randomised-prefix patterns, both user agents, and every request marker in the behavioural block above appear verbatim in the saved source snapshots 01-patchstack.txt and 03-thehackernews.txt. The SHA256 row is a labelled placeholder because no hash has been published; it is deliberately not filled with a guess. Everything else in this appendix is a behavioural pattern, a configuration check, or context, not an atomic claim requiring its own source trace.
Detection Validation Gates
| Gate | Check | Pass condition |
|---|---|---|
| 1 · Telemetry ready | Run #event_simpleName=/^ProcessRollup2$/ | groupBy([ComputerName], limit=500) restricted to your WordPress host group | Every WordPress host you believe you own appears. Any missing host is a blind spot, not a clean result; record it before proceeding. |
| 2 · Parent lineage populated | Confirm ParentBaseFileName is populated on those hosts, not empty | Q1, Q2, Q5, Q6, Q7 and Q9 all key on the parent. If it is blank on containerised hosts, every one of them is silently useless there. |
| 3 · FIM coverage on /tmp | Confirm whether a FileVantage or equivalent policy has been extended to cover /tmp and /var/tmp, not just the web root | Either it does and Q3/Q4 are live, or it does not and both are formally recorded as a gap covered by the Section 7 N3 host scan. An untested silent query is the worst of the three outcomes. |
| 4 · Benign baseline | Run Q1 and Q9 over 30 days before alerting | You can name every recurring parent-child pair. Undocumented pairs are hunt leads, and the exclusion list for the IOAs is derived from this run, not invented up front. |
| 5 · Positive test | On an isolated non-production WordPress host, have an authorised operator invoke a benign command through the normal PHP execution path (for example a maintenance script that calls id) and confirm Q1 and Q2 return it | Both queries return the event within the expected latency. This validates the detection path without creating or using any exploit code. |
| 6 · Web log path | Confirm HTTP access logs from every WordPress host and from the WAF reach a searchable platform | The Section 7 N1 and N2 hunts return data. Without this, chain steps 1 through 3 are permanently invisible and the pack's coverage tops out at post-exploitation. |
| 7 · Precondition audit complete | Run the Section 10 audit block's register_argc_argv and pearcmd.php checks across the estate | Every host is classified as RCE-capable or LFI-only. This does not change detection coverage, but it re-prioritises which Q1 hits get triaged first. |
| 8 · Promotion | Move Q1, Q6 and Q7 to Scheduled Searches in Monitor mode for 7 days, then to Detect | Fewer than roughly 5 unexplained hits per week per 100 web hosts. Above that, tune before promoting rather than raising the threshold. |
Hardening, Tiered
H1. Patch WordPress Core to 7.1.2, 7.0.6, 6.9.9, 6.8.10, or the matching backport on any older branch (down to 4.7.37). MITRE M1051 Update Software. This is the only complete fix for the underlying LFI; every other control on this page reduces blast radius or buys time. Verify with wp core version or the version enumeration in the Section 10 audit block, across production, staging and container images, not just the sites you remember.
H2. Reject pagename values containing a traversal sequence at the WAF or reverse proxy. MITRE M1037 Filter Network Traffic. A real page slug never contains .. or a percent-encoded dot, in either the query string or the POST body; per CIS Apache HTTP Server Benchmark and CIS Nginx Benchmark guidance on input filtering at the edge, this can be blocked with no effect on legitimate traffic. Cover both single and double encoding, uppercase and lowercase hex. Playbook P1.
H3. Disable register_argc_argv in php.ini. PHP hardening, CWE-98 mitigation. This does not fix the LFI, but it breaks the specific mechanism that turns it into code execution through pearcmd.php: without $argv populated from the query string, config-create cannot be triggered this way. Verify with php -i | grep register_argc_argv. Playbook P2.
H4. Remove or deny access to pearcmd.php. PHP hardening, attack-surface reduction. A production web server has no legitimate reason to serve PEAR's command-line tool over HTTP. Delete it, or deny it at the web-server layer, at all three commonly reported install paths. Verify with the readability check in the Section 10 audit block. Playbook P2/P3.
H5. Set open_basedir to confine PHP to the site's own webroot. PHP hardening, MITRE M1022 Restrict File and Directory Permissions. This is the single control that most directly addresses the root cause: even if get_page_template() is tricked into requesting a path outside the theme directory, open_basedir stops PHP from opening anything outside the configured tree, including pearcmd.php and anything in /tmp. TRADE-OFF some plugins that read shared assets or system temp paths outside the webroot will break; pilot before fleet rollout. Playbook P2.
H6. Audit every active theme for a top-level page-* directory and remove or rename it where the theme does not actually need one. Attack-surface reduction, follows directly from the vendor-published precondition. Twenty Twelve, Twenty Fourteen, Neve, Hestia and Sydney are named; a custom theme can also qualify. Eliminating the precondition on a given host removes the RCE escalation path entirely, independent of the pearcmd controls above.
H7. Extend FileVantage/FIM coverage to /tmp and /var/tmp on WordPress hosts, not just the web root. Detection prerequisite, not a MITRE mitigation. Validation gate 3 in Section 11 is the acceptance test. Without this, Q3 and Q4 are theoretical and the host-side N3 scan is the estate's only coverage of the file-write step. TRADE-OFF /tmp is a high-churn path on most Linux hosts; scope the policy narrowly (extension and depth limits) to keep the event volume manageable.
H8. Restrict disable_functions to remove shell_exec, system, passthru and proc_open from the web-facing PHP-FPM pool where the application does not need them. PHP hardening, MITRE M1042 Disable or Remove Feature. This is the specific mechanism that turns an included payload into a spawned shell (the event Q1 hunts for); removing it at the PHP layer is a second, independent control on top of the process-lineage detection. TRADE-OFF some legitimate plugins (media processing, backups) call these functions; audit before disabling estate-wide, and prefer a per-pool policy over a single global php.ini.
H9. Complete Falcon sensor coverage on every WordPress host, including containers, and confirm containerised images do not inherit register_argc_argv=On from the base image. Detection prerequisite; CIS Docker Benchmark for the runtime. The official PHP Docker image ships with this setting on by default per the vendor advisory, which makes an unaudited container fleet disproportionately exposed.
H10. Subscribe the WordPress estate to an inventory with version and theme attestation. MITRE M1051 supporting control. The recurring finding across CVE campaigns against WordPress is not difficulty of patching, it is not knowing which sites exist. Shadow installs on marketing subdomains and old staging copies are the standard blind spot. best-practice, no formal benchmark
H11. Make the web root, and any path PHP can reach including /tmp, read-only to the PHP worker except for the specific paths that need writes. MITRE M1022. If php-fpm cannot write outside a narrowly scoped upload path, the config-create primitive has nowhere to land regardless of whether the LFI or the pearcmd chain is ever fully patched on a given host.
H12. Segment the web tier from the rest of the internal network. MITRE M1030 Network Segmentation. Assume the next unauthenticated WordPress RCE lands too. The question that decides blast radius is what a compromised web server can reach: the database it needs, and as little else as possible.
H13. Establish an emergency CMS patching SLA with virtual patching as the bridge. MITRE M1051, M1037. The defining fact of this campaign is timing: exploitation began the same day as disclosure, and CrowdSec measured a hundred-fold growth in distinct attacking sources within five days. A patch cycle measured in weeks is no longer a sufficient control for internet-facing CMS software. Target managed WAF/virtual-patch deployment (such as the CrowdSec crowdsecurity/vpatch-CVE-2026-87902 rule, Section 7 N2) within hours of disclosure and core patching within 72 hours.
Deployable Playbooks
P1 · Web-server configuration, block pagename traversal at the edge
Apply on every reverse proxy and web server fronting WordPress, then reload. Test on one node before fleet rollout.
nginx
# /etc/nginx/snippets/cve-2026-87902-mitigation.conf
# 1. Block a pagename argument containing a traversal sequence, encoded or not,
# in the query string. Covers single and double percent-encoding.
if ($arg_pagename ~* "(\.\.|%2e%2e|%252e%252e)") { return 403; }
# 2. The same check for pagename delivered in the POST body needs request-body
# inspection (e.g. via ngx_http_lua_module or an AppSec/WAF component) -
# nginx's own directives cannot filter POST body content natively. If you run
# CrowdSec, its AppSec Component covers this out of the box via the
# crowdsecurity/vpatch-CVE-2026-87902 rule (see N2 in Section 7).
# 3. Deny direct access to pearcmd.php at all three commonly reported paths,
# belt-and-braces alongside removing the file per playbook P2.
location ~* /(usr/(local/lib|share)/php|usr/share/pear)?/?pearcmd\.php$ { deny all; return 403; }
# 4. Block the two published scanner/PoC user agents outright.
if ($http_user_agent ~* "(cve-2026-87902-poc|nuclei-cve-2026-87902)") { return 403; }
Apache 2.4
# /etc/apache2/conf-available/cve-2026-87902-mitigation.conf
RewriteEngine On
# Query-string pagename traversal, single or double encoded
RewriteCond %{QUERY_STRING} pagename=[^&]*(\.\.|%2e%2e|%252e%252e) [NC]
RewriteRule .* - [F,L]
# Deny direct access to pearcmd.php wherever it is reachable under the docroot
RewriteCond %{REQUEST_URI} pearcmd\.php [NC]
RewriteRule .* - [F,L]
# Block the two published scanner/PoC user agents
RewriteCond %{HTTP_USER_AGENT} (cve-2026-87902-poc|nuclei-cve-2026-87902) [NC]
RewriteRule .* - [F,L]
# POST-body pagename filtering needs mod_security or an equivalent request-body
# inspection module; Apache's rewrite directives alone cannot see the POST body.
Verify: nginx -t or apachectl configtest, reload, then run probe 4 from the Section 10 audit block. It must return 403 with no OPML/RSS content in the body.
P2 · PHP runtime hardening (php.ini / pool configuration)
; Add to php.ini or the relevant php-fpm pool .conf, then restart php-fpm. ; Breaks the pearcmd RCE escalation specifically: without argv populated from ; the query string, pearcmd.php cannot be driven via +config-show/+config-create ; even if it is included. register_argc_argv = Off ; Confines PHP's own file access to the site root, which is the control that ; most directly addresses this vulnerability's root cause: even a successful ; get_page_template() traversal cannot open a file outside this path. ; Set per-vhost/per-pool, not just globally, so each site is confined to its ; own tree rather than a shared one. open_basedir = /var/www/SITE_ROOT:/tmp ; Removes the specific functions this campaign's payloads use to turn a PHP ; include into a spawned shell. Audit for legitimate plugin usage first. disable_functions = shell_exec,system,passthru,proc_open,popen ; Belt-and-braces: rename or remove pearcmd.php entirely rather than relying ; on runtime settings alone. ; mv /usr/local/lib/php/pearcmd.php /usr/local/lib/php/pearcmd.php.disabled ; mv /usr/share/php/pearcmd.php /usr/share/php/pearcmd.php.disabled ; mv /usr/share/pear/pearcmd.php /usr/share/pear/pearcmd.php.disabled
Verify: php -i | grep -E 'register_argc_argv|open_basedir|disable_functions' reflects the new values, then restart php-fpm and confirm the site still renders normally end to end (theme, uploads, any plugin that touches the filesystem).
P3 · Theme audit and pearcmd removal script
#!/usr/bin/env bash
# Run per site root. Read-only theme audit plus pearcmd removal (with backup).
set -euo pipefail
SITE_ROOT="/var/www/example-site" # <-- set this
echo "[*] Themes with a top-level page-* directory (RCE precondition 1)"
find "${SITE_ROOT}/wp-content/themes" -maxdepth 2 -type d -iname 'page-*'
echo "[*] pearcmd.php presence at the three commonly reported install paths"
for p in /usr/local/lib/php/pearcmd.php /usr/share/php/pearcmd.php /usr/share/pear/pearcmd.php; do
if [ -e "$p" ]; then
echo " found: $p -- backing up and removing"
mkdir -p /var/backups/pearcmd-quarantine
cp -p "$p" "/var/backups/pearcmd-quarantine/$(basename "$p").$(date +%Y%m%d%H%M%S)"
chmod 000 "$p"
fi
done
echo "[*] Done. Confirm your PEAR-dependent tooling, if any, still works before removing"
echo " the quarantined copies permanently."
Pilot this one. A small number of hosting control panels and legacy PEAR-based tooling do call pearcmd.php for legitimate package management. Confirm nothing in your stack depends on it before removing it estate-wide; chmod 000 here is reversible, deletion is not.
P4 · Triage collection script (read-only)
#!/usr/bin/env bash
# Read-only evidence collection for a suspected CVE-2026-87902 compromise.
# Collects only, changes nothing. Run before any cleanup.
set -uo pipefail
SITE_ROOT="${1:-/var/www}"
OUT="/var/tmp/cve-2026-87902-triage-$(hostname)-$(date +%Y%m%d%H%M%S)"
mkdir -p "$OUT"
echo "[*] WordPress versions"
find "$SITE_ROOT" -name version.php -path '*wp-includes*' \
-exec grep -H -m1 wp_version {} + | tee "$OUT/versions.txt"
echo "[*] PHP files in /tmp and /var/tmp changed since the day before disclosure"
find /tmp /var/tmp -maxdepth 2 -name '*.php' -newermt '2026-09-21' \
-printf '%T+ %s %p\n' 2>/dev/null | sort | tee "$OUT/dropped-php.txt"
echo "[*] Exact and pattern-matched dropped filenames"
find /tmp /var/tmp -maxdepth 2 -regextype posix-extended \
-regex '.*/(wp-pear-rce-flag|poc87902|luci_[A-Za-z0-9]+|zeta_[A-Za-z0-9]+)\.php' \
2>/dev/null | tee "$OUT/named-dropped-php.txt"
echo "[*] pearcmd.php reachability"
for p in /usr/local/lib/php/pearcmd.php /usr/share/php/pearcmd.php /usr/share/pear/pearcmd.php; do
[ -r "$p" ] && echo "READABLE: $p"
done | tee "$OUT/pearcmd-status.txt"
echo "[*] register_argc_argv setting"
php -i 2>/dev/null | grep -i register_argc_argv | tee "$OUT/php-config.txt"
echo "[*] Themes with a page-* top-level directory"
find "$SITE_ROOT" -maxdepth 4 -type d -iname 'page-*' -path '*wp-content/themes*' \
| tee "$OUT/theme-precondition.txt"
echo "[*] Access-log hits"
grep -aEi 'pagename=[^ ]*(%2e%2e|%252e%252e|\.\.)|pearcmd|config-show|config-create|cve-2026-87902-poc|nuclei-cve-2026-87902' \
/var/log/nginx/access.log* /var/log/apache2/access.log* 2>/dev/null \
| tee "$OUT/access-hits.txt"
echo "[*] Cron and SSH keys for the web user"
crontab -l -u www-data 2>/dev/null | tee "$OUT/webuser-cron.txt"
cat /var/www/.ssh/authorized_keys 2>/dev/null | tee "$OUT/webuser-authorized-keys.txt"
echo "[+] Collected to $OUT - preserve this before remediating."
Containment Runbook
| Phase | Actions | Owner | Evidence to capture |
|---|---|---|---|
| 0 · Triage 0 to 30 min | Confirm the WordPress version on the alerting host and whether the RCE preconditions (page-* theme directory, register_argc_argv On, readable pearcmd.php) are met. Confirm whether the site was internet-reachable during 2026-09-22 to patch time. A vulnerable version plus a Q1 hit is a presumed compromise until disproven. | SOC L1 | Detection record, version output, precondition audit, exposure window |
| 1 · Isolate 30 to 60 min | Network-contain the host in Falcon. Do not reboot, do not reimage, do not delete anything under /tmp yet. If the site must stay up, fail over to a known-good build from before 2026-09-22 rather than cleaning in place. | SOC L2 | Containment timestamp; running process list; established connections |
| 2 · Preserve 1 to 3 h | Run playbook P4. Snapshot /tmp and /var/tmp. Copy access logs before rotation. Preserve the disk/volume snapshot if the host is a cloud instance. | IR | P4 output bundle, access logs, disk/volume snapshot |
| 3 · Scope 3 to 8 h | Run Q1, Q2, Q5, Q6 and Q7 across the whole web host group, not just the alerting host; the same scanner traffic hit everything you expose. Run Section 7 N1, N3 and N4 on every WordPress host. Reconcile the precondition audit (Section 10) fleet-wide. | IR + Hunt | Per-host findings matrix; list of every host with any hit or any met precondition |
| 4 · Eradicate 8 to 24 h | Rebuild from a known-good artefact where a Q1/Q4 hit or a filesystem finding confirms compromise; do not clean in place. Patch to the fixed version for the branch, apply P1, P2 and P3, rotate any credential a dropped shell may have touched, and remove any persistence found by Q6/Q7. | Platform + IR | Rebuild record, patch attestation, credential rotation log, removed persistence artefacts |
| 5 · Recover 24 to 72 h | Restore service from the rebuilt artefact behind the P1 WAF rules. Re-run the Section 10 audit block's traversal probe to confirm a 403 with no OPML/RSS content in the body. | Platform | Audit block output showing the probe blocked |
| 6 · Monitor 72 h to 30 d | Promote Q1, Q6 and Q7 to Scheduled Searches per Section 9. Re-run Section 7 N3 and N4 at day 7 and day 30; a second drop through a persistence mechanism missed in scoping will surface there. | SOC | Scheduled Search hit counts; day-7/day-30 rescan results |
Do not clean in place. The exploit writes attacker-controlled PHP outside the web root where routine web-root integrity tooling will never look, and the same primitive can be re-run to write somewhere more durable on a second attempt. Removing the one dropped file you found is not eradication if the precondition that let the attacker in is still standing. Rebuild from a known-good artefact and confirm the preconditions are closed (H3 through H6) before returning the host to service.
Detection Coverage Map
| Technique | Behaviour | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1595.002 | Reconnaissance probing against harmless core files via pagename | n/a | n/a | GAP Web/WAF logs only (Section 7 N1). No endpoint telemetry exists for this step, and an unsuccessful probe against a patched or precondition-clean host leaves no artifact anywhere. |
| T1190 | pearcmd reachability check and file-write exploitation request | n/a | n/a | GAP Web-log only (Section 7 N1, N2). Falcon has no visibility into HTTP request parameters. |
| T1505.003 | Attacker PHP written to /tmp or /var/tmp via pearcmd config-create | Q3, Q4 | n/a | PARTIAL Conditional on FIM policy explicitly extended to /tmp, which is atypical. Without it, Section 7 N3 is the only coverage. |
| T1059.004 / T1059.003 | Web-server process spawns a shell or interpreter when the dropped payload executes | Q1, Q9 | Yes | GOOD Primary detection. Fires regardless of which dropped filename or payload variant is used. |
| T1033 / T1082 | Discovery commands under a web-server parent | Q2 | n/a | GOOD |
| T1105 | Second-stage download by a web-server process | Q5 | Yes | GOOD |
| T1053.003 / T1053.005 | Persistence from a web-server process tree | Q6 | Yes | GOOD |
| T1098.004 / T1552.004 | SSH key written or modified from a web-server process tree | Q7 | Yes | GOOD |
| T1071.001 | Outbound C2/exfiltration from the compromised web tier | Q8 | n/a | GAP No confirmed C2 infrastructure exists in reporting for this campaign, so this is a rarity-ranked stack hunt rather than an indicator match. High effort per result. |
| T1027 | Obfuscated marker string assembled via chained chr() calls | n/a | n/a | GAP Filesystem-content hunt only (Section 7 N3 grep). No process-telemetry signature exists for PHP source obfuscation, since PHP never becomes a process image. |
Honest read on this map. Three of the first four steps in the attack chain (reconnaissance, the pearcmd check, and the file write itself) have no endpoint coverage at all, and that is a property of the vulnerability rather than a shortfall in the queries: everything up to and including the write happens inside HTTP request handling, a domain an EDR sensor cannot see into. The pack is therefore strong from the moment the dropped payload actually executes onward, and blind before it. Two consequences follow. First, the web-log hunts in Section 7 are not optional garnish, they are the only coverage for the first half of the intrusion, and validation gate 6 (Section 11) is the highest-leverage item in the whole pack. Second, because Falcon cannot distinguish a probe that never got past the theme precondition from a request that never happened at all, a clean Q1 result on a host that was never patched proves only that the payload was never triggered successfully, not that the host was never targeted. Validation: gates 1 through 3 must pass before any result from this pack is trusted; gate 4 must complete before Q1, Q6 or Q7 are promoted to Detect.
Hunt Summary Ticket
TITLE WordPress core page-template path traversal to pearcmd RCE (CVE-2026-87902)
SEVERITY Critical - unauthenticated code execution, exploited in the wild, on CISA KEV
SCOPE Every WordPress install in the estate, internet-facing first, including
shadow installs on marketing subdomains, staging copies, and container
images. Vulnerable: 4.7.0-7.1.1 across every branch. Patched: 7.1.2 |
7.0.6 | 6.9.9 | 6.8.10 and backports to 4.7.37. Hunt window: 2026-09-22
to the moment each site actually patched.
HYPOTHESIS An unauthenticated attacker sent a pagename parameter carrying a double
URL-encoded traversal sequence to get_page_template(), confirmed the
inclusion was live against a harmless core file, checked pearcmd.php
reachability, then used pearcmd's config-create directive to write PHP
content to /tmp or /var/tmp. If register_argc_argv was On and a page-*
theme directory existed, that payload later executed inside the PHP
worker and, if it called a shell function, spawned a shell.
QUERIES Q1 Web server spawns shell or interpreter PRIMARY
Q2 Discovery commands under web-server parent PRIMARY
Q3 PHP written to /tmp or /var/tmp (needs FIM) CONDITIONAL
Q4 Published dropped filename in file telemetry CONDITIONAL
Q5 Download utility launched by web server
Q6 Persistence created from web-server tree
Q7 SSH key material touched from web-server tree
Q8 Outbound to non-standard destination BASELINE SWEEP
Q9 Rare children of web-server parents BASELINE SWEEP
DO FIRST 1. Section 10 audit block - WordPress versions, register_argc_argv,
pearcmd.php reachability, and page-* theme directories, estate-wide.
2. Q1 and Q2 over 30 days across the web host group.
3. Section 7 N1 - grep web logs for the pagename traversal marker,
the pearcmd markers, and the two user agents.
Steps 1 and 3 do not require Falcon and can start immediately.
FINDINGS [ ] Unpatched WordPress instances found: ____
[ ] Hosts meeting both RCE preconditions: ____
[ ] Q1 / Q2 hits requiring triage: ____
[ ] Dropped payloads recovered from /tmp: ____
[ ] pagename traversal requests in web logs: ____
GAPS - No endpoint telemetry for chain steps 1-3 (HTTP request handling).
Web/WAF logs are the only coverage, and unsuccessful probes against
a patched or precondition-clean host leave no artifact at all.
- Q3/Q4 return nothing without FIM explicitly covering /tmp and
/var/tmp, which is atypical.
- Managed/third-party hosting has no sensor - provider attestation only.
- No malware hashes or corroborated payload infrastructure published
for this campaign as of 2026-09-29; nothing importable ships in the CSV.
ACTIONS [ ] Patch to 7.1.2 / 7.0.6 / 6.9.9 / 6.8.10 (or branch backport) H1 Immediate
[ ] Block pagename traversal at the WAF/edge H2 Immediate
[ ] Disable register_argc_argv H3 Immediate
[ ] Remove or deny access to pearcmd.php H4 Immediate
[ ] Set open_basedir per site H5 Immediate
[ ] Promote Q1, Q6, Q7 to Scheduled Search (Monitor 7d)
OWNER HuntPack
VERSION v0.1 - 2026-09-29
Changelog
References
| Tier | Source | Used for | Snapshot | Accessed |
|---|---|---|---|---|
| 1 | GitHub Security Advisory GHSA-7hp8-65ch-5whp | Primary vendor advisory: full version matrix, CVSS 4.0 vector, CWE-98, both RCE preconditions, discovery credit | 07-ghsa.txt | 2026-09-29 |
| 1 | NVD - CVE-2026-87902 (via the NVD 2.0 REST API) | CVSS 3.1 8.1 High, CISA SSVC data, KEV add/due dates, CWE-98 | 05-nvd.txt | 2026-09-29 |
| 1 | MITRE CVE Program record - CVE-2026-87902 (via the CVE Services API) | Independent confirmation of CWE-98, CVSS 3.1 vector, CISA ADP Vulnrichment timeline | 08-cve-mitre-record.txt | 2026-09-29 |
| 1 | CISA Known Exploited Vulnerabilities Catalog | KEV addition date 2026-09-25, remediation due date 2026-09-28 | 06-cisa-kev.txt | 2026-09-29 |
| 1 | Patchstack - Attackers Started Probing WordPress Sites Hours After the Patch | Three-stage attack progression, exact request shapes, dropped filenames, scanner user agents, detection guidance | 01-patchstack.txt | 2026-09-29 |
| 1 | CrowdSec - CVE-2026-87902: 30,000 Addresses in Five Days | Exploitation telemetry (signals, distinct sources, cumulative IPs), CrowdSec virtual-patch rule id | 02-crowdsec.txt | 2026-09-29 |
| 2 | The Hacker News - Attackers Exploit WordPress CVE-2026-87902 Within Hours of Disclosure | Independent confirmation of preconditions and timeline; single-sourced Previdian honeypot detail (not shipped as an indicator) | 03-thehackernews.txt | 2026-09-29 |
| 2 | SecurityWeek - Critical WordPress Vulnerability Exploited Immediately After Disclosure | Independent corroboration of the timeline and the three-stage progression, citing Patchstack directly | 04-securityweek.txt | 2026-09-29 |
The raw fetched text of every source above is saved in WordPress-CVE-2026-87902-RFI-Hunt-sources/ next to this file. No source contained instructions aimed at an automated agent, and no source was disqualified. Nothing in this pack was written from memory.