Core, PHP or server
Brotli CVE-2026-111497 reaches stock WordPress through pingbacks
WordPress does not ship Brotli, but its outbound HTTP calls hand compressed replies to the system's Brotli decoder. A pingback to xmlrpc.php lets anyone trigger CVE-2026-111497 and crash a PHP worker. The fix is the patched OS package.
A memory bug in Google's Brotli decoder, CVE-2026-111497, can be triggered on a default WordPress install by anyone who sends a pingback to xmlrpc.php, according to Patchstack's October 30 analysis. WordPress fetches the pingback's source URL, the attacker's server replies with a body compressed with Brotli, and libcurl decodes it before WordPress sees any of it. On an unpatched library the decoder writes outside its buffer and the PHP worker crashes or stalls. No WordPress or plugin update fixes this. The fix is the operating system's patched Brotli package (1.0.10, 1.1.1 or 1.2.1, or your distribution's backport), so confirm with your host that it is installed and close the pingback route in the meantime.
| Software | Brotli decoder (libbrotli), used by libcurl for WordPress outbound HTTP |
|---|---|
| CVE | CVE-2026-111497 |
| Severity | CVSS 9.2, scored by Google |
| Type | Out-of-bounds heap write; worker crash or denial of service in practice |
| Affected versions | Brotli 1.0.3 through 1.2.0 |
| Fixed in | Brotli 1.0.10, 1.1.1 and 1.2.1 (October 21, 2026); Debian and Ubuntu backport under 1.1.0 |
| Conditions | Unauthenticated via pingback when XML-RPC is reachable and a published post accepts pingbacks (the default); also via plugins that fetch user-supplied URLs, oEmbed (Contributor or higher) and admin-configured feeds |
| Exploited | Yes. Per CISA's KEV listing (October 27, 2026), which is not WordPress-specific; public WordPress tooling only crashes workers (Patchstack, October 30, 2026) |
The Requests cURL transport unpacks Brotli replies for WordPress
WordPress routes its outbound HTTP calls through WP_Http, which uses the bundled Requests library and that library's cURL transport. That transport tells libcurl to accept any compression and unpack it automatically, on every handle, with no setting to turn that off, so a reply labeled with Brotli content encoding goes straight into the system's decoder. Passing decompress => false to the HTTP API does not help; that only governs what WordPress does with a body libcurl has already unpacked. A web application firewall has little to work with either, because the harmful bytes arrive in the reply from the attacker's server and the decode happens below PHP.
One request can crash a PHP worker
Crashing a worker works on any build, so one request takes out one PHP process and a few hundred can hold a site down. Code execution needs a chain tuned to a specific binary; working shells exist against stock Node.js and Bun builds, and no public chain targets PHP under Apache or PHP-FPM. A lab write-up dated October 27 drove the bug through pingback and recorded a killed worker and a worker stuck at 100% CPU from a payload of under a hundred bytes, with no code execution included. Patchstack's advice is to plan for downtime now; memory disclosure and code execution are the harder outcomes the 9.2 score reflects.
Plugins fetching visitor URLs reach the decoder
Pingback is the route built into core that needs no account, but any plugin or theme that fetches a visitor-supplied URL (URL and image importers, link previews, avatar proxies, webhook verifiers) lands in the same decoder, as do oEmbed discovery and the oEmbed proxy for Contributor accounts and higher, and feed fetches through SimplePie for admin-configured feeds. The safe wrapper does not help: wp_safe_remote_get() only adds an SSRF filter that rejects internal addresses and unusual ports and never inspects the response encoding.
Test whether xmlrpc.php still accepts pingbacks
Many sites already have this route shut. Plenty of managed hosts refuse requests to xmlrpc.php before they reach WordPress, and common hardening snippets have turned it off for a long time. Verify it, because "XML-RPC is disabled" means two things. A web server block closes the route. The common xmlrpc_enabled filter, which many plugin toggles use underneath, only gates methods that need a login, and pingback needs none.
Patchstack describes a safe self-test: send a pingback.ping call to your own xmlrpc.php with a source address on 127.0.0.1, which WordPress rejects before fetching anything. Read the reply this way:
- A 403, 404 or non-XML reply means the server blocks the route.
- A fault reporting that pingback.ping is not a known method means it has been removed, so the route is closed.
- Any other XML-RPC response, including other faults, shows that pingback_ping() executed, so the route is still open.
Patchstack notes that a stock install has XML-RPC on, default_ping_status set to open and at least one pingable post, so unless you or your host blocked xmlrpc.php or removed the pingback method, expect the open result.
Debian backports keep the old version number
Upgrade the library to a fixed release (1.0.10, 1.1.1 or 1.2.1) or apply the libbrotli1 security update from your Linux distribution. Two details complicate the check.
The upstream version number may not change. Debian and Ubuntu have applied the fix to the 1.1.0 package they already ship, so a server can be fully patched and still show version 1.1.0. Look at the package revision:
dpkg-query -W -f='${Version}\n' libbrotli1
# 1.1.0-2+b7 vulnerable
# 1.1.0-2+deb13u1 patched on Debian 13 (suffix varies by distro and release)
As of Patchstack's October 30 post, the official wordpress:latest Docker image still installed a vulnerable libbrotli1, so check your image's libbrotli1 revision rather than assuming a fresh pull fixes it. If it is unpatched, upgrade the package in your own image layer:
apt-get update && \
apt-get install -y --no-install-recommends --only-upgrade libbrotli1
The NVD record for CVE-2026-111497 has the official entry.
Disabling libcurl decompression keeps attacker replies from the decoder
None of these fix the bug; they cut off the ways to reach it. The broadest option stops libcurl from decompressing anything for WordPress, which Patchstack says keeps attacker-controlled bodies from reaching the Brotli decoder through WordPress's own HTTP requests. WordPress then stops requesting compressed responses, a cost Patchstack calls negligible, and still unpacks gzip in PHP if a server compresses anyway. Place this in a must-use plugin:
add_action( 'http_api_curl', function ( $handle ) {
curl_setopt( $handle, CURLOPT_ENCODING, 'identity' );
curl_setopt( $handle, CURLOPT_HTTP_CONTENT_DECODING, 0 );
}, 10, 1 );
To remove the unauthenticated path, unregister the pingback methods rather than matching the method name in a firewall rule, since WordPress decodes XML character references and CDATA before dispatch and a string match can be bypassed:
add_filter( 'xmlrpc_methods', function ( $methods ) {
unset( $methods['pingback.ping'] );
unset( $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
Or deny xmlrpc.php at the web server (Require all denied in a Files block on Apache 2.4, or a deny all location on nginx). Pair any of these with the decompression filter, audit plugins that fetch visitor-supplied URLs, and where possible send outbound HTTP through a proxy that only allows known hosts.
Signal 11 exits point to a crashed PHP worker
Outbound traffic is the clearest signal. A WordPress fetch that comes back Brotli-encoded is unusual, and a tiny compressed body that balloons or a chunked reply that stalls is stronger still; a logging forward proxy shows all of it. At the edge, watch for bursts of unauthenticated POSTs to xmlrpc.php whose source URLs point at domains the site has no reason to contact.
On the host, Apache logs AH00051 child exits on signal 11 and PHP-FPM logs children dying on signal 11; a core dump with libbrotlidec.so in the backtrace confirms it. Not every hit crashes: the lab also pinned a worker at full CPU, so watch for stuck workers and timeouts too. Evidence of more than a crash is a www-data process, parented by PHP or Apache, spawning a shell or curl to an unfamiliar host. If you see that, standard incident handling applies (this is general practice, not a step Patchstack prescribes): take the host offline, keep logs and core dumps, rotate its credentials and rebuild from a clean image with the patched library.
Put this alongside the WordPress core RCE (CVE-2026-119977) in this week's patch checks.
Brotli release and CISA listing dates
- October 21, 2026: Brotli 1.0.10, 1.1.1 and 1.2.1 released with the fix.
- October 27, 2026: CISA adds the CVE to its Known Exploited Vulnerabilities catalog with a November 10 federal deadline.
- October 27, 2026: A lab reproduces a worker crash through WordPress pingback.
- October 30, 2026: Patchstack publishes its WordPress analysis, noting wordpress:latest still carries the vulnerable libbrotli1.
The bigger picture
Fewer moving parts to patch
Patch first; that is the job today. Once the site is safe, it is worth asking why this keeps happening. On WordPress every plugin is PHP that runs with full access to the site, the database and the file system, so one bug in one plugin is a bug in the whole site. Hatamoto, the open-source CMS this site runs on, is built the other way round.
| Typical WordPress site | Hatamoto | |
|---|---|---|
| What you patch | WordPress core, PHP, extensions and every plugin, on their own schedules | One binary and Postgres. No PHP |
| Updates | Core, plugins and PHP from different places | One signed release channel you can verify by hand |
| A bad plugin | Can read and change the whole site | Runs as WebAssembly with only the permissions you granted |
What this does not mean. Hatamoto has bugs too, and a sandbox only limits what a bad plugin can reach. Weak passwords, a compromised server or a plugin you gave broad permissions can still hurt you. Fewer layers just means fewer of these mornings.
See what your WordPress site would look like on Hatamoto.
The importer reads your site over the REST API and gives you a report first: what moves across, which of your plugins it recognises, and what it cannot bring. Your WordPress site is not changed.