# Node2Shell: Reproducing CVE-2026-111497 in the Node.js Brotli decoder

Out-of-bounds write in Google Brotli's decoder, reachable via Node.js fetch() and Express 5 body parsing, enabling heap read/write and potential RCE.

- Payout: Real-world hack
- Severity: critical
- Program: Google
- Analysis by: Datadog Security Labs
- Disclosed: 2026-10-29
- CVE: CVE-2026-111497
- Write-up quality: 8/10
- Original: https://securitylabs.datadoghq.com/articles/node2shell-cve-2026-111497-nodejs-brotli-decoder/
- Library page: https://bugbountylibrary.com/r/blog%3Asecuritylabs-datadoghq-com-articles-node2shell-cve-2026-111497-nodejs-brotli-decoder
- Tags: area:oss domain:oss impact:data-leak impact:rce kind:incident platform:threat-intel sev:critical tech:nodejs tech:python technique:incomplete-fix technique:source-review vuln:dos vuln:memory-corruption

**Target:** Brotli decompression in Node.js/Express and HTTP clients
**Root cause:** DecodeBlockTypeAndLength() returns a boolean conflating 'malformed stream' with 'need more input'; callers drop the return value on the fast path, so a forbidden block switch causes an unbounded copy into a small internal buffer.
**Steps:**
1. Craft a ~23MB Brotli stream of ordinary commands that drains the block length budget while producing no output.
2. End the stream with commands requesting a block switch the format forbids.
3. Send the stream as a Content-Encoding: br request body to Express 5/body-parser 2.x, or serve it as a br response to a Node.js fetch()/axios/got client.
4. Decoder parks unconsumed bytes in a small internal buffer without a bound check, writing past the buffer into adjacent decoder state.
5. Corrupted state redirects subsequent reads/writes; leaked heap bytes return in the decompressed response, or a redirected write crashes the process.
**How found:** Source review of the Brotli decoder's block-switch handling; noticed the boolean return conflates malformed vs. need-more-input and is dropped on the fast path, then built a stream that drains the block budget and requests a forbidden switch.
**Exploitation:** Attacker controls either an inbound compressed request body or an outbound response header (via user-supplied URL fetch). The crafted stream corrupts decoder state, yielding a repeatable heap read that exits through the decompressed response and a redirected write. Imperva demonstrated code execution on Node.js 24.22.0 Linux ARM64 after several attempts; public PoC produces a crash and a limited memory read.
**Escalation:** Heap read primitive used to stage further exploitation toward control-flow hijack; obstacles are ASLR, input-constrained corruption bytes, and managed-runtime defenses.
**Insight:** Boolean returns that conflate 'error' with 'need more input' are a recurring decoder bug class; also, Node.js fetch() auto-decodes Brotli regardless of Accept-Encoding, so user-supplied URL fetchers are a hidden attack surface.

## Write-ups of the same bug (oldest first)
- 2026-10-23: [Python packages are also vulnerable to the Node2Shell Brotli flaw (CVE-2026-111497)](https://bugbountylibrary.com/r/blog%3Aaikido-dev-blog-python-packages-vulnerable-node2shell-brotli-cve-2026-111497) — Aikido Security
- 2026-10-29: [Node2Shell: Reproducing CVE-2026-111497 in the Node.js Brotli decoder](https://bugbountylibrary.com/r/blog%3Asecuritylabs-datadoghq-com-articles-node2shell-cve-2026-111497-nodejs-brotli-decoder) — Datadog Security Labs (this one)

