The Fedora Project has shipped an emergency update for WordPress on Fedora 43, pulling in WordPress 6.9.9 — a dedicated security release that patches CVE-2026-87902, an unauthenticated path traversal vulnerability in WordPress core's page-template resolution logic that can be chained into critical remote code execution under specific conditions. The advisory (Fedora FEDORA-2026-5c9d8e41a9) packages the upstream WordPress 6.9.9 security release, which follows the 6.9.8 security release in rapid succession — a signal that the WordPress security team is treating this class of flaw with maximum urgency.
Let me be direct: unauthenticated, remotely reachable path traversal in the world's most-deployed CMS is about as bad as it gets from an exposure standpoint. WordPress powers well over 40% of the public web. Any flaw in core template resolution is reachable before authentication, before plugin logic, and often before WAF rules that administrators assume are protecting them. When that traversal can be conditioned into arbitrary code execution — by resolving a template from an attacker-controlled path, such as a file uploaded through a legitimate media or avatar endpoint — you have a pre-auth RCE chain.
If you run WordPress on Fedora 43 (or any distribution consuming upstream WordPress), treat this as a patch-now event.
Technical Analysis
Affected Products and Versions
- Product: WordPress core
- Fixed version: WordPress 6.9.9 (security release)
- Prior security release: WordPress 6.9.8
- Affected versions: WordPress releases prior to 6.9.9 containing the vulnerable page-template resolution code path
- Distribution: Fedora 43, package update
wordpress(advisory FEDORA-2026-5c9d8e41a9, published via linuxsecurity.com) - Note: Sites using WordPress's automatic background updates for security releases should already be on 6.9.9 — verify, don't assume.
The Vulnerability: CVE-2026-87902
Class: CWE-22 (Improper Limitation of a Pathname to a Restricted Directory — Path Traversal), chained to code execution
Attack vector: Network, unauthenticated
The flaw resides in how WordPress resolves page templates. When WordPress renders a page, it determines which PHP template file to load based on the request — via the template hierarchy and, in certain code paths, template hints derived from user-controllable input (query parameters, request URIs, or block-theme template references). The vulnerable code path fails to adequately canonicalize and constrain the resolved template path to the theme directory.
From a defender's perspective, the exploitation chain looks like this:
- Traversal primitive: An unauthenticated attacker crafts a request that injects directory traversal sequences (
../, URL-encoded variants%2e%2e%2f,%252e, or path-normalization bypasses such as....//) into the template resolution input, causing WordPress to resolve a PHP template outside the intended theme directory. - Conditional code execution: The traversal alone yields file inclusion. Escalation to code execution is conditional — it requires the attacker to control the contents of a file reachable by the traversal. The classic primitive is a PHP file planted via a legitimate upload channel (media library on misconfigured sites, avatar/comment attachment endpoints, a writable plugin upload path, or a second plugin vulnerability), or abuse of attacker-controllable files such as log/session content on shared hosting.
- Execution: WordPress
includes the resolved template file within the PHP interpreter context, executing attacker-controlled code as the web server user (apache/nginx/php-fpm), which typically has read access towp-config.php— meaning database credentials, authentication keys, and salts are immediately compromised.
Post-exploitation, expect webshell drops in wp-content/uploads/, rogue administrator account creation, malicious plugin/theme installation for persistence, and database content injection (SEO spam, redirect kits, credit-card skimmers on WooCommerce).
Exploitation Status
The WordPress security team shipped this as an out-of-cycle security release, which historically correlates with either reported exploitation or a vulnerability simple enough to weaponize that mass exploitation is expected within days of disclosure. Path traversal in a pre-auth code path of WordPress core is trivially scannable — automated probes for traversal patterns against WordPress sites typically begin within 24–48 hours of a public advisory. Treat this as exploitation imminent/expected, patch on an emergency change window, and hunt retroactively across logs from the disclosure date backward.
Detection & Response
This is a technical threat. The detections below target the three most reliable observables: (1) traversal strings in HTTP requests to WordPress template-relevant endpoints, (2) the web server PHP process spawning child processes or writing PHP files into upload directories, and (3) webshell artifacts on disk.
Sigma Rules
---
title: WordPress CVE-2026-87902 Path Traversal in Template Resolution Request
id: 3f8c1a42-7b9d-4e51-a6c2-9d4e5f6a7b8c
status: experimental
description: Detects HTTP requests containing directory traversal sequences targeting WordPress template-resolution parameters or URIs, consistent with exploitation of CVE-2026-87902 (unauthenticated path traversal in page-template resolution).
references:
- https://linuxsecurity.com/advisories/fedora/fedora-43-wordpress-2026-5c9d8e41a9
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/04/10
tags:
- attack.initial_access
- attack.t1190
logsource:
category: webserver
detection:
selection_uri:
cs-uri-query|contains:
- '../'
- '..\\'
- '%2e%2e%2f'
- '%2e%2e\\'
- '%252e%252e'
- '....//'
selection_wp:
cs-uri-query|contains:
- 'template'
- 'pagename'
- 'page_id'
- 'wp-content/themes'
condition: selection_uri and selection_wp
falsepositives:
- Legitimate theme/plugin developers testing template paths
- Broken internal links with malformed relative paths
level: high
---
title: Web Server Process Spawning Shell or Command Interpreter
id: 8a2d4e61-3c7b-4f92-b1d5-6e8a9c0d1e2f
status: experimental
description: Detects Apache, Nginx, or PHP-FPM worker processes spawning command shells or interpreters — a strong post-exploitation indicator following WordPress code execution such as CVE-2026-87902 template-include RCE.
references:
- https://linuxsecurity.com/advisories/fedora/fedora-43-wordpress-2026-5c9d8e41a9
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/10
tags:
- attack.execution
- attack.t1059.004
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/httpd'
- '/apache2'
- '/nginx'
- '/php-fpm'
- '/php-cgi'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/curl'
- '/wget'
- '/python'
- '/python3'
- '/perl'
- '/nc'
- '/ncat'
- '/base64'
condition: selection_parent and selection_child
falsepositives:
- Rare legitimate plugin functionality invoking system commands (e.g., image processing, backups) — investigate parent-child context before dismissing
level: critical
---
title: PHP File Written to WordPress Uploads Directory
id: c5e7f2a9-1d4b-48e6-93a1-2b3c4d5e6f70
status: experimental
description: Detects creation of PHP files inside wp-content/uploads — a canonical webshell drop location following WordPress RCE exploitation such as CVE-2026-87902. The uploads tree should never legitimately contain executable PHP.
references:
- https://linuxsecurity.com/advisories/fedora/fedora-43-wordpress-2026-5c9d8e41a9
- https://attack.mitre.org/techniques/T1505/003/
author: Security Arsenal
date: 2026/04/10
tags:
- attack.persistence
- attack.t1505.003
logsource:
category: file_event
product: linux
detection:
selection:
TargetFilename|contains: '/wp-content/uploads/'
TargetFilename|endswith:
- '.php'
- '.phtml'
- '.php5'
- '.php7'
- '.phar'
condition: selection
falsepositives:
- Extremely rare; some broken plugins write PHP into uploads — any hit warrants triage
level: critical
KQL — Microsoft Sentinel / Defender
These queries assume web server access logs (Apache/Nginx) are ingested via Syslog/CEF, or that WordPress hosts are onboarded to Defender for Endpoint. Hunt retroactively from the disclosure date backward at least 14 days.
// Hunt 1: Traversal sequences in requests to WordPress template parameters (Apache/Nginx via Syslog ingestion)
Syslog
| where TimeGenerated > ago(14d)
| where ProcessName in~ ("httpd", "apache2", "nginx", "php-fpm") or Computer has "web"
| extend RawMsg = tostring(SyslogMessage)
| where RawMsg has_any ("../", "%2e%2e", "%252e", "....//")
| where RawMsg has_any ("template", "pagename", "page_id", "wp-content/themes", "index.php")
| extend HttpRequest = extract(@"GET ([^ ]+)", 1, RawMsg)
| summarize RequestCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
by Computer, SourceIP = HostIP, HttpRequest
| order by RequestCount desc
;
// Hunt 2: Web server process spawning shell/interpreter child processes (Defender for Endpoint)
DeviceProcessEvents
| where TimeGenerated > ago(14d)
| where InitiatingProcessFileName in~ ("httpd", "apache2", "nginx", "php-fpm", "php-cgi")
| where FileName in~ ("sh", "bash", "dash", "curl", "wget", "python3", "perl", "nc", "ncat", "base64")
| project TimeGenerated, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, AccountName, InitiatingProcessCommandLine
| order by TimeGenerated desc
;
// Hunt 3: PHP files created under wp-content/uploads (webshell staging)
DeviceFileEvents
| where TimeGenerated > ago(14d)
| where FolderPath has "wp-content/uploads"
| where FileName endswith ".php" or FileName endswith ".phtml" or FileName endswith ".phar"
| project TimeGenerated, DeviceName, FolderPath, FileName, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| order by TimeGenerated desc
Velociraptor VQL
Use this artifact for rapid triage across suspected WordPress hosts: enumerate PHP webshell candidates in uploads, then correlate with web-server child processes.
-- WordPress CVE-2026-87902 triage: PHP files in uploads + suspicious web-server child processes
-- Part 1: PHP/executable files planted under wp-content/uploads (webshell candidates)
SELECT FullPath, Size, Mtime, Ctime
FROM glob(globs='/var/www/**/wp-content/uploads/**/*.php')
WHERE Mtime > now() - 1209600 -- last 14 days
ORDER BY Mtime DESC
-- Part 2: Web server processes with shell/interpreter children (live RCE indicator)
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ '(/bin/(ba|da|z)?sh|curl|wget|python|perl|ncat|base64)'
OR Name =~ '^(sh|bash|dash|nc|ncat)$'
-- Part 3: Recently modified files in theme directories (template overwrite persistence)
SELECT FullPath, Size, Mtime
FROM glob(globs='/var/www/**/wp-content/themes/**/*.php')
WHERE Mtime > now() - 1209600
ORDER BY Mtime DESC
Remediation & Verification Script (Bash — Fedora 43)
#!/usr/bin/env bash
# CVE-2026-87902 remediation & verification — Fedora 43 WordPress
# Run as root. Stops on error; prints verification evidence for change records.
set -euo pipefail
echo "=== [1/5] Current WordPress package version ==="
rpm -q wordpress || echo "wordpress package not installed via rpm — check manual installs under /var/www"
echo "=== [2/5] Applying Fedora 43 security update (FEDORA-2026-5c9d8e41a9) ==="
dnf -y upgrade wordpress --advisory=FEDORA-2026-5c9d8e41a9 || dnf -y upgrade wordpress
echo "=== [3/5] Verifying patched version (must be 6.9.9 or later) ==="
WP_VER=$(rpm -q --qf '%{VERSION}' wordpress 2>/dev/null || echo "0")
echo "Installed WordPress version: ${WP_VER}"
if [[ "$(printf '%s\n' "6.9.9" "${WP_VER}" | sort -V | head -n1)" != "6.9.9" ]]; then
echo "[!] WARNING: WordPress version ${WP_VER} is BELOW 6.9.9 — still vulnerable to CVE-2026-87902"
fi
# For non-rpm installs, check version.php directly:
# grep -h '\$wp_version' /var/www/*/wp-includes/version.php
echo "=== [4/5] Hunting for webshell artifacts in uploads (should return empty) ==="
find /var/www -type d -path '*wp-content/uploads*' -exec find {} -type f \( -name '*.php' -o -name '*.phtml' -o -name '*.phar' \) -mtime -14 -ls \; 2>/dev/null || true
echo "=== [5/5] Hunting logs for traversal probes against template parameters ==="
journalctl -u httpd -u nginx --since "14 days ago" 2>/dev/null | grep -Ei '(\.\./|%2e%2e|%252e|\.\.\.\.//).*(template|pagename|page_id)' | tail -50 || \
grep -Ehi '(\.\./|%2e%2e|%252e|\.\.\.\.//).*(template|pagename|page_id)' /var/log/httpd/*access*log /var/log/nginx/*access*log 2>/dev/null | tail -50 || echo "No matches — retain logs for IR timeline anyway"
echo "=== Hardening reminder: disable PHP execution in uploads ==="
cat <<'EOF'
# Add to your Apache config / .htaccess inside wp-content/uploads:
# <FilesMatch "\.(php|phtml|phar)$">
# Require all denied
# </FilesMatch>
# For nginx, add a location block returning 403 for PHP under /wp-content/uploads/.
EOF
Remediation
- Patch immediately. On Fedora 43:
sudo dnf upgrade wordpress --advisory=FEDORA-2026-5c9d8e41a9. Confirm the installed version is WordPress 6.9.9 or later. For sites tracking upstream directly, update via the WordPress admin dashboard orwp core update. Do not rely on background auto-updates without verification — checkwp-includes/version.php. - Verify every site, not just production. Staging, dev, and forgotten marketing microsites running WordPress are frequently the initial entry point. Inventory all WordPress instances on your infrastructure, including containerized and LEMP/LAMP-stack deployments outside package management.
- Block PHP execution in
wp-content/uploads. This neutralizes the most common conditional-RCE escalation path (planted PHP file + traversal include). Enforce it at the web server layer as shown in the script above — this is a durable hardening control, not just a CVE workaround. - Hunt retroactively. Exploitation of pre-auth traversal primitives scales fast. Run the KQL hunts above across at least the last 14 days of web logs. Any traversal hit against template parameters followed within minutes by a PHP write to uploads is a confirmed compromise — invoke your IR plan, isolate the host, rotate
wp-config.phpcredentials and all authentication keys/salts (rotating salts force-invalidates all sessions and cookies), and audit administrator accounts and installed plugins/themes for persistence. - WAF as a compensating control, not a fix. If patching must be scheduled, deploy virtual patching: block requests containing traversal sequences (
../,%2e%2e, double-encoded variants) in query strings against WordPress endpoints. Understand that encoding-bypass variants make WAF rules brittle — they buy time, they do not close the hole. - Reduce post-exploitation blast radius. Ensure the PHP-FPM/Apache user has read-only access to the WordPress core tree (ownership split: root owns code, web user owns only
wp-content/uploads), restrictALLOW_UNFILTERED_UPLOADS, and enforce least-privilege database credentials.
References: Fedora advisory FEDORA-2026-5c9d8e41a9 and the WordPress 6.9.9 Security Release notes on wordpress.org/news. Monitor CISA KEV for addition of CVE-2026-87902 — WordPress core RCE flaws are historically cataloged quickly once exploitation is confirmed.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.