Wordfence Reproduces the Brotli Flaw as Remote Code Execution Through WordPress, but the Public Exploit Was Written for One Docker Image and Posted a Day After CISA Called the Bug Exploited
Wordfence reproduced CVE-2026-111497 as unauthenticated code execution through WordPress in a lab, but the public exploit was written for one pinned Docker image, was posted a day after CISA’s...
Wordfence said on November 2 that it reproduced CVE-2026-111497, the Brotli decoder flaw that circulates as HTTP2Shell and Node2Shell, as unauthenticated remote code execution through WordPress in an isolated lab. The exploit it used was written for one environment: the public repository that holds it describes itself as “CVE-2026-111497 RCE PoC for one pinned Docker Official Image for WordPress.” That repository was created on October 28, the day after CISA added the flaw to its Known Exploited Vulnerabilities (KEV) catalog, so CISA’s evidence on October 27 did not come from it. Wordfence also says it “found no independently reviewable public report” documenting a successful production compromise or a compromise through WordPress.
Table Of Content
This follows our October 26 report, which said that none of the sources we read described attacks in the wild and that CISA’s catalog did not list the flaw. Both statements are now out of date, and we have added a note to that post. Below: what Wordfence tested, what changed, how WordPress reaches the decoder, who has shipped a fix, and what the exploitation reports do and do not show. We did not run, fetch or link any exploit code.
What Wordfence tested
Despite the nickname, Wordfence and Check Point both say HTTP/2 is not involved; the flaw is in how Brotli’s decoder handles a crafted compressed stream. Wordfence’s write-up says its team ran the public proof of concept in isolated containers “using its exact target environment”: WordPress 7.1.3 on Debian 13.7 with Apache 2.4.69, PHP 8.3.36 running as mod_php and Debian’s vulnerable libbrotli1 1.1.0-2+b7 package, with memory randomization on. The unauthenticated request executed code. After Wordfence updated only Brotli to Debian’s fixed package, the same sequence no longer did.
Wordfence writes that “the same payload did not execute against PHP 8.3.35,” and that in one vulnerable environment it crashed the PHP worker instead. Its assessment is that the public exploit “is not a universal request” and that it has “not demonstrated remote adaptation to an arbitrary WordPress server.” It warns, though, that payloads matched to a standard server image may be reusable and that attackers are already testing the flaw, so it calls the update urgent.
What changed since October 26
Our October 26 post recorded where each source stood. The table compares eight items against what we found on November 2; six moved.
| Item | Our October 26 post | November 2 |
|---|---|---|
| CISA KEV catalog | Not listed (catalog dated October 23) | Added October 27 “based on evidence of active exploitation”; due Tuesday, November 10; no forensic-triage flag |
| CISA entry in the CVE record (SSVC) | Exploitation none | Exploitation active, set at 19:53 UTC on October 27; NVD’s copy still carries an October 23 timestamp |
| Reports of exploitation | None in the sources we read | ELLIO (update dated October 26), Previdian (first seen October 27) and Check Point; none documents a compromised victim |
| NVD | Awaiting Analysis, Google’s CVSS 4.0 score only | Analyzed (last modified October 30), with NVD’s own CVSS 3.1 score of 9.8 |
| Ubuntu tracker priority | Medium | High, with the reason “CISA-KEV” |
| Red Hat | Important, CVSS 3.1 8.1 | Unchanged; fixes for RHEL 8, 9 and 10 shipped October 26 |
| Microsoft Security Update Guide | Exploited: No; “Exploitation More Likely” | Unchanged |
| Public WordPress exploit | None known | Repository created October 28 at 22:42 UTC; reproduced by Wordfence on November 2 |
The one rating that moved for a stated reason is Ubuntu’s: its tracker lists “Priority reason: CISA-KEV.” Red Hat has kept its Important rating, which rests on its reading of the attack requirement as high complexity, so the numeric scores still run from 8.1 (Red Hat and Microsoft) through Google’s 9.2 on CVSS 4.0 to NVD’s 9.8.
How a WordPress site reaches the decoder
The flaw is in Brotli, not in WordPress, and Wordfence says updating WordPress, a plugin or a theme “does not update this server-level library.” We read the source of WordPress 7.1.4 to see how a request ends up there. The path is short:
- Pingbacks fetch a URL the caller chooses. XML-RPC’s unauthenticated
pingback.pingtakes a source URL and a target post. WordPress checks that the target accepts pings and that the pingback is not already registered, waits one second, then fetches the source URL withwp_safe_remote_get, using a 10-second timeout, no redirects and a 150 KB response limit (class-wp-xmlrpc-server.php). - The request goes through libcurl when PHP has it. WordPress’s bundled Requests library tries its cURL transport first and falls back to PHP sockets (Requests.php). The cURL transport’s constructor calls
curl_setopt($this->handle, CURLOPT_ENCODING, '')when libcurl is 7.10.5 or newer (Curl.php), and none of the three HTTP files we read sets anAccept-Encodingheader, so as far as we can tell the header comes from libcurl itself. - An empty encoding list means every built-in decoder. The libcurl documentation says the option “enables decoding of a response when a Content-Encoding: header is received,” that an empty string asks for a header containing “all built-in supported encodings,” and that Brotli (
br) is supported since curl 7.57.0. A libcurl built with Brotli therefore advertises it and decodes any response that arrives with that encoding.
CloudLinux’s knowledge-base article describes the same route for hosting stacks: “The decoder is reached through the curl library behind the EasyApache PHP curl extension, and only when PHP code fetches URLs with CURLOPT_ENCODING set.” It adds that Apache’s mod_brotli “only compresses and never uses the vulnerable decoder,” so serving Brotli pages through Apache is not the exposure.
How much depends on the build shows up on any machine. On the Windows computer we use, we pointed two curl 8.21.0 builds at a local server that returns a plain body and recorded the Accept-Encoding header each sent. The curl bundled with Git for Windows reports brotli/1.2.0 in its version line, a release inside the affected range, and with --compressed it sent deflate, gzip, br, zstd. The curl.exe that ships with Windows lists no Brotli and sent deflate, gzip. Neither sent the header without the flag. No Brotli data was generated or sent, and we did not try to exploit either build.
On a Linux host the equivalent question is whether the PHP build serving the site uses a libcurl with Brotli. php -r 'print_r(curl_version());' prints the libcurl details. In the PHP 8.3 source that result carries a brotli_version entry (libcurl 7.57.0 or newer) and a CURL_VERSION_BROTLI flag in its features value (interface.c, curl.stub.php). A non-empty brotli_version or that flag means libcurl was built with Brotli. PHP is not installed on the machine we used, so we have not run this; run it with the PHP that serves the site, because command-line and web builds can differ.
Closing the demonstrated route is not the same as patching. WordPress’s documentation says the xmlrpc_enabled filter “does not control whether pingbacks or other custom endpoints that don’t require authentication are enabled,” and Wordfence says its own Disable XML-RPC authentication option “does not disable unauthenticated pingbacks.” Wordfence adds that changing XML-RPC or pingback behavior removes only the demonstrated route and may disrupt legitimate integrations.
Who has shipped a fix
Amazon Linux, Ubuntu and Red Hat had each published fixed packages by October 26, and Debian’s tracker lists fixes for releases 12 and 13. Compare the full revision, not just the first three numbers, because distributions backport fixes: Debian 13’s fixed package still begins 1.1.0, as Wordfence notes.
| Platform | Fixed package | Advisory and date |
|---|---|---|
| Debian 13 (trixie) | brotli 1.1.0-2+deb13u1 | DSA-6582-1, per Debian’s tracker |
| Debian 12 (bookworm) | brotli 1.0.9-2+deb12u1 | DLA-4855-1, per Debian’s tracker |
| Ubuntu 26.10, 26.04 LTS, 24.04 LTS, 22.04 LTS | 1.2.0-4ubuntu0.1, 1.2.0-3ubuntu0.1, 1.1.0-2ubuntu0.1, 1.0.9-2ubuntu0.1 | USN-8956-1, October 26; the tracker also lists +esm1 builds for 20.04, 18.04 and 16.04 |
| Red Hat Enterprise Linux 8, 9, 10 | brotli 1.0.6-5.el8_10, 1.0.9-10.el9_8.1, 1.1.0-8.el10_2.1 | RHSA-2026:90501, 90495 and 90449, October 26 |
| Amazon Linux 2023 | brotli 1.1.0-1.amzn2023.0.2 | ALAS2023-2026-3334, released October 24, updated October 26 |
| CloudLinux OS 7 and CentOS 7 ELS | brotli 1.0.9-10.el7.tuxcare.els1; ea-brotli 1.0.10-1 for EasyApache 4 | CloudLinux knowledge-base article, updated October 30 |
| CloudLinux OS 8 and 9 | System builds come from AlmaLinux | Same article; alt-php fixes not yet published (below) |
Three details matter for hosts.
Bundled copies. CloudLinux says “The alt-php extensions bundle their own copy of Brotli inside brotli.so and don’t use the system library,” so “All packages up to date” does not mean they are fixed. Its fixed extension builds (0.21.1-1 for alt-php70 to alt-php85, which bundle Brotli 1.2.1) sit in a beta repository on CloudLinux 7, and “On CloudLinux 8 and 9 the fixed builds are not published yet and there is no release date,” as of its October 30 update. The same article says the extension’s decoder is reached only when PHP code decodes untrusted data itself, through brotli_uncompress(), its streaming counterparts or the compress.brotli:// wrapper.
Restarts. CloudLinux tells administrators to restart PHP-FPM and Apache afterwards “because running processes keep the old library in memory,” and Wordfence says containers must be rebuilt, since “Restarting an existing container does not replace the vulnerable files inside it.”
Labels. Amazon Linux’s advisory describes the flaw as “A vulnerability in the Node.js Brotli decoder,” although the packages it ships are the brotli library itself, libbrotli among them. Red Hat’s record draws the same line for its own Node.js packages: some use the system copy and are fixed by updating brotli, while Node.js 24 on RHEL 8 and 9 bundles its own.
What the exploitation reports show
CISA’s October 27 alert says it added the flaw “based on evidence of active exploitation.” The catalog entry is titled Google Brotli Unchecked Return Value Vulnerability, describes a component that “could be used by different products,” and names no victim, no application that was attacked and no route. It sets a November 10 due date for federal civilian agencies. CISA’s record-enrichment entry changed its exploitation field from none to active at 19:53 UTC that day, which fits the listing.
The public reports that describe attacks concern other routes. ELLIO’s write-up, updated on October 26, says its sensors “have recorded CVE-2026-111497 exploit traffic in the wild,” aimed at Node.js; when ELLIO replayed the captured exploit chain against a vulnerable Node.js build in its own lab, the captured chain “scored zero hits in 50 attempts.” Previdian’s page lists 11 attempts from 7 addresses in five countries between October 27 and November 2 and says such observations “do not show that the target was vulnerable or that the attempt succeeded.” Check Point’s intrusion-prevention telemetry shows Brotli-encoded requests aimed at upload and ingestion endpoints, plus malformed payloads and HTTP 500 errors, and Check Point says its findings “do not establish successful compromise in the observed events.” None of the three says its sensors saw the WordPress pingback route used.
The timing also separates the two events. The WordPress repository Wordfence tested was created on October 28 at 22:42 UTC, about 27 hours after CISA’s entry flipped to active, so CISA’s evidence on October 27 did not come from that repository. Wordfence reaches the practical conclusion from the other side: it found no public report of a compromise through WordPress, and it notes that CISA’s entry names no application, route or outcome, so the absence of a public case “does not mean that no exploitation has occurred.”
What to do
- Compare full revisions. Check each host’s installed package against the table, and against the vendor’s notice if your distribution is not listed.
- Restart what loaded the library. After updating, restart PHP (lsphp or PHP-FPM) and Apache, and rebuild and redeploy containers from an updated base image.
- Find the other copies. On CloudLinux hosts that means the alt-php Brotli extensions and ea-brotli. Elsewhere it includes Node.js builds that bundle their own decoder and any image or application that vendors Brotli.
- Check PHP’s libcurl with the command above, using the PHP build that serves the site.
- Ask your host Wordfence’s question: “Is the process serving my WordPress site using a Brotli decoder patched for CVE-2026-111497, and were all affected services restarted or redeployed after the update?”
- Keep logs. Wordfence advises retaining web-server, PHP, process, firewall and outbound-network logs from before disclosure until each environment was patched and restarted, and looking for unexpected pingback requests, unusual outbound connections and PHP or web-server crashes. It adds that “These signs are not proof by themselves, and their absence does not prove that exploitation did not occur.”
What we could not check
We read only the public repository’s metadata through GitHub’s API and did not fetch, run or link its code. We have no PHP on the machine we used, so Wordfence’s lab results, including the failure on PHP 8.3.35, are its own and we have not reproduced them. Wordfence’s help page for its XML-RPC option returned nothing to our script, so that claim stands as Wordfence states it; the WordPress documentation quoted above supports the point about the filter. CISA has not said which application or route its evidence involved, the KEV entry carries no victim detail, and we found no source that names a compromised WordPress site. CloudLinux has given no date for alt-php fixes on versions 8 and 9.
Sources and method
We read Wordfence’s post through its RSS feed, because the page itself returns an empty response to scripts; CISA’s KEV catalog entry and feed (catalog 2026.10.30) and alert; the CVE record, the NVD record and the commit history of CISA’s SSVC data in cvelistV5 and Vulnrichment; Brotli’s release page; the Debian tracker, USN-8956-1 and Ubuntu’s CVE page, Red Hat’s CVE record, Amazon’s advisory, Microsoft’s Security Update Guide entry and CloudLinux’s article; the three exploitation reports linked above; and the WordPress, libcurl and php-src sources linked in the text. We fetched them on November 2 between about 19:10 and 19:30 UTC. The curl test used a local server and plain responses. The mapping from the repository’s creation time to CISA’s listing is our arithmetic from public timestamps, and our reading of the WordPress source is a reading, not a run.








No Comment! Be the first one.