Safety#Security scan

OpenAI's red team found an unauthenticated RCE in Brotli (CVE-2026-111497): Node.js, Bun and Python libraries affected — the upstream fix shipped 8 months late

OpenAI's red team found an unauthenticated RCE in Brotli (CVE-2026-111497). Node.js, Bun and Python libs are hit; the upstream fix shipped 8 months late.

Macro photo of a black circuit board with a chip and surface-mount parts in shallow focus

OpenAI’s red team, Codex Security, found an unauthenticated out-of-bounds write that leads to remote code execution in Google’s Brotli compression decoder, now tracked as CVE-2026-111497. According to the Node.js security advisory, patched releases 22.23.4, 24.22.1 and 26.12.1 shipped on October 21; NVD listed the CVE the next day with a CVSS 4.0 score of 9.2. What turns this from a routine patch Tuesday into a wider problem is the timeline: the root-cause fix landed in Brotli’s mainline on February 27, but nobody flagged it as a security issue at the time, so no release carried it for eight months — and every piece of software that embeds Brotli sat exposed the whole time.

Key points

  • Node.js shipped security releases 26.12.1, 24.22.1 and 22.23.4 for the 26.x, 24.x and 22.x lines on October 21, rated High, crediting Khai Tran and Sylvie Mayer of OpenAI Codex Security.
  • The fix, commit 0ed4268a, merged into Brotli’s mainline on 2026-02-27, but the releases that carry it — 1.0.10, 1.1.1 and 1.2.1 — only shipped on October 21, per GitHub’s release log.
  • The blast radius goes beyond Node.js: Bun 1.4.4, Envoy Proxy, Istio and the PyPI Brotli and brotlicffi packages were confirmed affected between October 22 and 24; the fix lists are consolidated by OpenAI’s patchtheplanet.org/brotli (Node.js, Bun, Envoy, Istio, upstream Brotli) and by Aikido (the two PyPI packages).

Background

Brotli is Google’s HTTP compression format, and Node.js, Bun and a long list of server software compile the decoder straight into their binaries — which is why one upstream library flaw reaches nearly the whole industry. OpenAI hit the defect during a red-teaming exercise in February and reported it upstream; the root-cause fix was merged then, but per Aikido’s October 24 update it was never treated as a security issue, so no version shipped with the fix embedded. On October 21 Google Brotli published v1.0.10, v1.1.1 and v1.2.1 and Node.js issued its advisory the same day; on the evening of October 23 OpenAI claimed the find publicly on X and launched patchtheplanet.org/brotli, an OpenAI Daybreak initiative, listing affected software, fixed versions and mitigations. AI-driven bug hunting is now routine — earlier this month XBOW chained three Chrome bugs into Google’s first $250k full-chain reward.

How the bug works

Per the Node.js advisory, the decoder mishandles an invalid block switch: input that should be a permanent format error is reported as a temporary need for more data, so the streaming decoder keeps appending bytes into an eight-byte internal buffer until it writes past the end. An attacker only needs the application to decompress Brotli data they control. Aikido’s teardown lists the three common paths: Express 5 and body-parser 2.x decompress request bodies sent with Content-Encoding: br; fetch() decompresses responses automatically, so a malicious or compromised upstream server reaches your service through what it sends back; and any code that passes untrusted input to node:zlib’s Brotli functions. The outcomes range from a crash and memory disclosure to code execution. NVD’s record puts the affected range at Google Brotli 1.0.3 through 1.2.0 on all platforms.

Affected software and fixes

The table consolidates the fix list from patchtheplanet on October 23 and Aikido’s posts of October 23–24:

ProjectAffectedFixed versions
Node.jsearlier patch levels of 26.x / 24.x / 22.x26.12.1 / 24.22.1 / 22.23.4 (Oct 21)
Bunversions before 1.4.41.4.4 (bundles Brotli 1.2.1, Oct 22)
Envoy Proxydeployments with Brotli decompression configured1.40.0 / 1.39.3 / 1.38.6 / 1.37.8
Istiomeshes with Brotli decompression configured1.29.9 / 1.30.6 / 1.31.2
Google Brotli upstream1.0.3 – 1.2.01.2.1 (older lines: 1.0.10 / 1.1.1)
PyPI Brotli package1.2.0 and earlier1.2.1
PyPI brotlicffi package1.2.0.xexact fixed version unverified

Python is the layer confirmed last, on October 23–24: HTTP clients such as requests, httpx and aiohttp load the Brotli or brotlicffi decoder automatically whenever it is installed, and Aikido puts the Brotli package at 82.8 million downloads per month. There is also a scanning gap — as of October 23, advisory databases had not mapped the CVE to either PyPI package, so pip-audit, Dependabot and Safety flag nothing.

What others say

Severity comes with two labels: the Node.js advisory says High, while NVD’s CVSS 4.0 secondary metric scores it 9.2, Critical. Both exist; cite each with its source. Aikido’s write-up has the most detail on exploit progress: the first public proof of concept, published October 22, reached code execution only against a deliberately weakened test build; the same day, researchers reported getting it to run on an unmodified Node.js 24.22.0 image on Linux arm64, though not on every attempt. Aikido also relays that no exploitation in the wild had been reported as of October 22. Dania Durnas at Aikido retitled the story from Node2Shell to HTTP2Shell in her October 23 update, on the grounds that any library or application speaking HTTP may be exposed. Bun’s own 1.4.4 blog post mentions only “security fixes for TLS, WebSocket, the database clients and the package manager,” with Brotli appearing in a list of affected protocols but the CVE never named — for Bun, the affected-and-fixed chain rests on the patchtheplanet page and Aikido’s reporting.

Mitigation and checks

patchtheplanet’s stopgap is to stop Brotli-decoding untrusted data until you can patch: on Envoy, remove the Brotli decompressor filter while keeping gzip and zstd; on Python clients, keep Accept-Encoding to gzip/deflate and reject br responses before decoding. Aikido cautions that changing Accept-Encoding alone is not enough — a malicious server can send a Brotli response regardless, and urllib3 picks its decoder from the response’s Content-Encoding header. For a quick sweep: run node --version on hosts and CI runners, check each image with docker run --rm <image> node --version, and inspect Python environments with pip show brotli brotlicffi. Rebuild container images after upgrading — an image pinned to an old tag stays vulnerable.

Our take

Two groups should move first: teams running Node or Bun services should verify versions and rebuild images today, and Python services should check Brotli and brotlicffi. The honest catches: scanners cannot see the Python packages yet; brotlicffi’s exact fixed version still renders as a placeholder on Aikido’s page, so we could not verify it; and distro-packaged Node on Debian, Alpine and friends may link the system Brotli, in which case the fix arrives through the distro’s advisory, not the Node version number. The eight-month lag is the same disease as Rust’s borrow-checker soundness bug that lived for 11 years: the upstream fix existed, and nobody downstream knew to follow. And once a PoC is public, probes only get faster — cohttp’s fix PR was probed within ten minutes of publication, back in August. If you cannot upgrade yet, taking Brotli out of your decoding path is the only dependable stopgap.