OpenAI's Codex Found a Node.js Brotli RCE. Imperva Ran Code on an Official Build OpenAI Codex Security researchers reported CVE-2026-111497, a high-severity flaw in Node.js's bundled Brotli decoder that lets an invalid block switch be treated as a need for more input, causing the streaming decoder to write past an eight-byte internal buffer and potentially enabling unauthenticated remote code execution. Imperva reproduced code execution on the official Node.js 24.22.0 Linux arm64 image and on Express 5.0.0–5.3.0 with body-parser 2.0.0–2.3.0, though it said execution took multiple attempts. The upstream fix landed in Brotli in February 2026 and ships in Node 22, 24 and 26; Node 20 will not receive a patch. Eight bytes. That is the size of the internal buffer the Brotli decoder inside Node.js kept writing past, according to the Node.js security advisory of October 21 https://nodejs.org/en/blog/vulnerability/october-2026-security-releases . Feed it the wrong compressed stream and, in the advisory's words, an attacker "can corrupt process memory, which can lead to a crash, disclosure of process memory, or remote code execution." The bug is CVE-2026-111497. The advisory https://nodejs.org/en/blog/vulnerability/october-2026-security-releases credits researchers from OpenAI Codex Security with reporting it. On October 23, OpenAI described it on X https://x.com/openai/status/2113766354386084338 as "a vulnerability that allows for unauthenticated remote code execution in Brotli." The same day, The Hacker News reported https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html that Imperva had run code through it on the official Node.js 24.22.0 image for Linux arm64, with no debugger and no custom build. If you run Node 22, 24 or 26 anywhere, the fix is an upgrade. If you run Node 20, no fix is coming. Brotli is the compression format behind Content-Encoding: br . Node ships its own copy of Google's decoder and exposes it through node:zlib https://nodejs.org/api/zlib.html . The advisory gives the root cause in one sentence: "An invalid block switch was reported as a temporary need for more input instead of a permanent format error, so the streaming decoder kept appending input bytes to an eight-byte internal buffer." The decoder hit an impossible state, decided it was waiting for more data, and kept writing. Node.js rates the bug high , not critical advisory https://nodejs.org/en/blog/vulnerability/october-2026-security-releases . Some outlets, such as Crypto Briefing https://cryptobriefing.com/openai-brotli-remote-code-execution-vulnerability/ , have printed a CVSS score of 9.2. The Hacker News https://thehackernews.com/2026/10/nodejs-brotli-decoder-bug-could-allow.html notes the flaw "is rated high rather than critical." Go by the vendor's rating. The upstream fix is older than the CVE. The change first landed in Brotli's source in February 2026, per The Hacker News https://thehackernews.com/2026/10/nodejs-brotli-decoder-bug-could-allow.html , and the Brotli 1.2.1 changelog https://github.com/google/brotli/blob/v1.2.1/CHANGELOG.md , dated October 21, lists the CVE under SECURITY. The change was labelled a security fix only in the October releases. Eight slots, more bytes: the decoder kept appending input to a buffer that had no room for it. You don't have to call zlib yourself to be exposed. Imperva's analysis https://www.imperva.com/blog/node2shell-from-brotli-data-to-remote-code-execution/ names two paths. Responses you fetch. Node's built-in fetch decoding a compressed response from another server reached the vulnerable decoder. A service that calls a third-party API, follows a webhook URL or fetches a URL a user typed is on this path when the server it fetches from can be controlled by an attacker. Request bodies you parse. Express 5's body parsers, express.json , express.urlencoded , express.text and express.raw , decode Brotli request bodies alongside gzip and deflate The Hacker News https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html . Imperva reproduced execution on Express 5.0.0 to 5.3.0 and body-parser 2.0.0 to 2.3.0. A plain node:http server does not decode a Brotli body unless middleware or your own code does it. Keep the result in proportion. Imperva says "execution took multiple attempts in our setup," and the team tested only arm64 on the 24.x line The Hacker News https://thehackernews.com/2026/10/researchers-demonstrate-node2shell-rce.html . An earlier public proof of concept reached code execution only on a deliberately weakened build; on a standard build its author got a crash and a limited memory read The Hacker News https://thehackernews.com/2026/10/nodejs-brotli-decoder-bug-could-allow.html . No exploitation in the wild had been reported as of October 22, per the same article. A crash is still a denial of service, and the arm64 result shows code execution on a stock build is reachable. The October 21 releases https://nodejs.org/en/blog/vulnerability/october-2026-security-releases fix it in: | Line | First fixed version | |---|---| | 22.x LTS | 22.23.4 | | 24.x LTS | 24.22.1 | | 26.x Current | 26.12.1 | | 20.x and older | none, end of life | The advisory is blunt about the last row: "End-of-Life versions are always affected when a security release occurs." It lists no workaround. Upgrading is the fix. The same release patches nine other CVEs, three more of them high: two TLS certificate hostname bypasses and a dns.resolve truncation on NUL characters advisory https://nodejs.org/en/blog/vulnerability/october-2026-security-releases . One upgrade covers all of them. Your laptop is the easy one. The Node binaries baked into container images, CI runners and VMs are the ones a dependency audit misses. Imperva says to check the Node version inside each deployed image or host, because "a package inventory can miss an older runtime bundled in a container" Imperva https://www.imperva.com/blog/node2shell-from-brotli-data-to-remote-code-execution/ . Save this as check-node.mjs and run it with node check-node.mjs , or inside an image with docker run --rm -v "$PWD":/w your-image node /w/check-node.mjs : js // check-node.mjs: exit 1 if this Node lacks // the CVE-2026-111497 fix const fixed = { 22: 23, 4 , 24: 22, 1 , 26: 12, 1 }; const maj, min, pat = process.versions.node .split '.' .map Number ; const f = fixed maj ; const ok = Boolean f && min f 0 || min === f 0 && pat = f 1 ; console.log process.versions.node, ok ? 'patched' : 'NOT patched' ; process.exit ok ? 0 : 1 ; Any major not in the table, including 20, fails on purpose. A major newer than 26 will fail too, so extend the table when one ships. Run it as a CI step and the next advisory becomes a one-line table edit. Then find the places your own code decodes Brotli directly: git grep -nE "BrotliDecompress|brotliDecompress" \ -- ' .js' ' .ts' ' .mjs' ' .cjs' For the version floor, engines in package.json takes a semver range, so you can join one floor per supported line with || : { "engines": { "node": "^22.23.4 || ^24.22.1 || =26.12.1" } } npm only warns on an engines mismatch by default, so treat it as documentation, not a gate. Pin your Dockerfile's base image to a fixed release and rebuild. A running container keeps the Node it was built with. The Node that matters is the one inside the image you deployed, not the one on your laptop. Vercel https://vercel.com/kb/bulletin/node-js-security-advisory deployed WAF rules on October 21 that block the inbound attack for every project, and it manages patch versions for its 22.x and 24.x runtimes. Its bulletin also says what that does not cover: the WAF "does not cover responses your functions fetch from other servers," and it "does not replace patching." Projects still on Node 20 have to move to 22 or 24 and redeploy. Imperva https://www.imperva.com/blog/node2shell-from-brotli-data-to-remote-code-execution/ has added WAF rules as well, and says a Node.js update is still required for full remediation. A WAF filters what comes in. A fetch call pulls Brotli in from servers you don't control, and that response never passes an inbound rule. Add check-node.mjs to the build of every image tag you still deploy, then see which ones fail. Which of your images would you have forgotten? The hard part of this fix is knowing where your runtimes live: base images, CI runners, the platform's managed Node, the one VM nobody has touched in a year. Ship It https://www.amazon.com/dp/B0GW2NTCR5 covers that stretch between localhost and production for a small team, from hosting and deploys to CI/CD and the monitoring that tells you what you're actually running. I also build Hermes IDE https://hermes-ide.com/download , so weigh this with that in mind: it's source-available BSL 1.1 , runs on macOS, Windows and Linux, and gives each task its own branch and worktree so Claude Code and Codex can work side by side. It's on GitHub https://github.com/hermes-hq/hermes-ide .