---
id: 2026-10-undici-october-15-eight-cve-batch-cache-poisoning-tls-pinning-bypass-cve-2026-109829-109383
title: "undici (Node.js fetch): eight CVEs on 2026-10-15, cross-user cache poisoning (CVE-2026-109829), TLS pinning silently dropped (CVE-2026-109383), five DoS, one SRI bypass; fixed 6.29.1, 7.30.1, 8.12.2"
date_disclosed: 2026-10-15
last_updated: 2026-10-28
severity: high
status: patched
ecosystems: [npm, nodejs, nextjs, ai-agents]
tools_affected: ["undici (npm) 4.0.0 to 6.29.0, 7.0.0 to 7.30.0 and 8.0.0 to 8.12.1 (ranges differ per CVE)", "Node.js 22.x, 24.x and 26.x before the 2026-10-21 security releases (bundled undici; the release post lists an undici update without mapping it to a CVE)", "any server, agent or MCP client that calls fetch(), request() or EventSource/WebSocket through undici, including Next.js route handlers and server actions", "apps that pin certificates through a checkServerIdentity callback in Agent tls options", "apps composing undici's redirect and cache interceptors with a shared store"]
tags: [undici, nodejs, fetch, cache-poisoning, tls, certificate-pinning, dos, sri, websocket, eventsource, ghsa-batch, patched]
---

## TL;DR
The OpenJS CNA published eight undici CVEs on 2026-10-15, all fixed in `undici` 6.29.1, 7.30.1 and 8.12.2 the same day; the GitHub Advisory Database reviewed three of them on 2026-10-27, which is how they surfaced here. Two change what an app trusts: with `compose(redirect(), cache())` on an originless `Agent` and a shared cache store, a response produced after a cross-origin redirect is cached under the trusted original URL, so an attacker who controls a redirect target poisons the cache for every later caller and a private user-specific response can be served to others (CVE-2026-109829, 7.4); and `Agent` deep-cloned its options through JSON, so a `tls.checkServerIdentity` pinning callback was silently dropped and a certificate the callback was written to reject was accepted on the default dispatcher behind `fetch()` (CVE-2026-109383, 7.4). Of the other six, three end the process on a response from a malicious server (TLS 1.2 renegotiation CVE-2026-87018 7.5, excess content-encodings CVE-2026-109869 7.5, the `decompress` interceptor CVE-2026-87029 5.9), two exhaust memory (EventSource CVE-2026-109924, WebSocket PONG CVE-2026-109932, both 5.9), and one is a Subresource Integrity bypass through a non-lowercase algorithm token (CVE-2026-109841, 5.9). Node.js's 2026-10-21 releases bundle the fixed lines: 26.12.1 carries undici 8.12.2, 24.22.1 carries 7.30.1 and 22.23.4 carries 6.29.1, per the Node changelogs. Upgrade the package where you depend on it directly, and Node where you do not.

## What happened

undici is the HTTP client under Node.js's global `fetch()`, and the package most agent SDKs, MCP clients and Next.js servers make outbound requests through whether they name it or not. On 2026-10-15 the undici maintainers (mcollina, UlisesGascon) published eight advisories on the `nodejs/undici` tab, the OpenJS Foundation CNA issued the CVE records the same day, and the 8.12.2 release notes list all eight. The database reviewed CVE-2026-109869 on 10-23 and the three below on 10-27, and the Node.js project's dependency-vulnerability bot opened an issue on 10-20 for CVE-2026-109829 against undici 8.11.2 in Node 26.x, with no maintainer comment as of 2026-10-28. The CNA records, read this sweep:

- **CVE-2026-109829 / [GHSA-4w7w-5xrc-9h26](https://github.com/nodejs/undici/security/advisories/GHSA-4w7w-5xrc-9h26) — cache poisoning and cross-user disclosure via cross-origin redirects (7.4, CWE-346, CWE-524).** Affected 7.0.0 to 7.30.0 and 8.0.0 to 8.12.1 (the cache interceptor arrived in 7.0.0). When an originless `Agent` composes the redirect and cache interceptors in that order with a shared `MemoryCacheStore` or `SqliteCacheStore`, the cache key is built from the original request URL before the redirect handler changes the origin, so the response produced after a cross-origin redirect is stored under the original key; an attacker who controls the target of a redirect from a trusted URL has their response cached under that URL for later callers, and a `private, no-store` redirect response to a user-specific resource can be stored and served to later unauthenticated callers. The fix verifies the producing origin before storing and preserves each hop's cache-control policy. Workarounds: `compose(cache(), redirect())`, per-origin dispatchers and stores, or no shared caching for redirect-capable requests. Finders Kushalkhemka, mayank-jangid-moon, skigeek16; reporter bengsky13.
- **CVE-2026-109383 / [GHSA-2m5v-pch6-74hx](https://github.com/nodejs/undici/security/advisories/GHSA-2m5v-pch6-74hx) — TLS certificate validation bypass via dropped `tls` options in `Agent` (7.4, CWE-295).** Affected 4.0.0 to 6.29.0, 7.0.0 to 7.30.0, 8.0.0 to 8.12.1. `Agent` passed its constructor options through a JSON deep clone before forwarding them to each per-origin pool, JSON cannot carry functions, so a caller-supplied `tls.checkServerIdentity` callback (the usual way to pin a certificate or public key) was silently dropped before the TLS layer; a peer whose certificate the callback should reject but which passes Node's default hostname and chain checks is accepted. `Agent` is the default dispatcher behind `request`, `fetch` and `setGlobalDispatcher`, and `EnvHttpProxyAgent`'s direct and `NO_PROXY` routes are affected too; the same options through `connect` are not. The advisory calls it the `Agent` counterpart of CVE-2026-84961, which covered `BalancedPool`. Workaround: pass TLS options via `connect` instead of `tls`. Reporters euriconicacio, BlueN0r, ksanjeev284.
- **CVE-2026-87018 / [GHSA-qrxm-fqhp-jwvm](https://github.com/nodejs/undici/security/advisories/GHSA-qrxm-fqhp-jwvm) — process crash via TLS 1.2 certificate-changing renegotiation (7.5, CWE-248, CWE-617).** Affected 4.2.1 to 6.29.0, 7.0.0 to 7.30.0, 8.0.0 to 8.12.1. A TLS 1.2 server that renegotiates after the connection is up and presents a different CA-trusted certificate with a non-matching hostname makes Node destroy the socket with a certificate-altname error, which undici's established-socket handler asserted could never happen, so the assertion is an uncaught exception that ends the process on both HTTP/1.1 and HTTP/2 paths. The attacker controls only the endpoint. Workaround: `minVersion` and `maxVersion` of `TLSv1.3` in `connect` options where the targets allow it. Reporter benzdeus.
- **CVE-2026-109869 / GHSA-xjj6-f33q-929c — crash via unhandled error on excessive content-encodings (7.5).** Affected 6.23.0 to 6.29.0, 7.18.0 to 7.30.0, 8.0.0 to 8.12.1. A server that sends more than five content codings and closes early leaves an orphaned internal stream whose error is unhandled.
- **CVE-2026-87029 — unhandled exception in the `decompress` interceptor (5.9)**, 7.15.0 to 7.30.0 and 8.0.0 to 8.12.1; **CVE-2026-109841 — Subresource Integrity bypass via non-lowercase algorithm tokens (5.9)**, same ranges; **CVE-2026-109924 — unbounded memory in the EventSource parser (5.9)**, 6.5.0 to 6.29.0, 7.0.0 to 7.30.0, 8.0.0 to 8.12.1; **CVE-2026-109932 — WebSocket client unbounded automatic PONG buffering (5.9)**, 5.15.0 to 6.29.0, 7.0.0 to 7.30.0, 8.0.0 to 8.12.1. All fixed in 6.29.1, 7.30.1 and 8.12.2; the four 5.9 records were read from CVE Services this sweep and their advisory pages were not opened.

What this means for the audience. An agent is an HTTP client that fetches URLs a model chose, and every URL a model chose is a redirect an attacker may control; the two 7.4s are the trust-boundary ones. The cache-poisoning case needs the specific interceptor composition and a shared store, which is a deliberate server-side setup rather than a default, so check for it rather than assume it. The pinning case is the opposite: anyone who added `checkServerIdentity` to an `Agent` to pin a provider or an internal CA has been running with the pin silently off since undici 4.0.0, and the default `fetch()` dispatcher is `Agent`. The five crash records are the usual shape for a client library, a malicious or compromised server ends the process, and for a long-running agent or MCP host that is a denial of service with one response. On versions: the 8.12.2 fix release and the eight records are dated 2026-10-15; Node.js's 2026-10-21 security post lists "Undici on 26.x, 24.x, 22.x" among dependency updates without saying which CVE it closes; the Node changelogs settle it, with 26.12.1 updating undici to 8.12.2 (PR #66721), 24.22.1 to 7.30.1 (PR #66764) and 22.23.4 to 6.29.1 (PR #66765), all three the fixed versions. `next@16.4.3` declares no undici dependency of its own and uses the runtime's `fetch`, so a Next.js app's exposure is the Node version it runs on, plus any direct `undici` pin in its lockfile.

## Am I affected?

```bash
# Direct dependency: below 6.29.1, 7.30.1 or 8.12.2 is affected (ranges above differ per CVE)
npm ls undici 2>/dev/null | grep undici
grep -n '"undici"' package-lock.json pnpm-lock.yaml 2>/dev/null | head

# Bundled with Node: the 2026-10-21 security releases updated it; check your runtime
node -p 'process.versions.undici + " in node " + process.version'

# The two trust-boundary cases
grep -rn 'checkServerIdentity' --include='*.js' --include='*.ts' --include='*.mjs' . | grep -v node_modules
grep -rnE 'compose\(\s*(interceptors\.)?redirect' --include='*.js' --include='*.ts' . | grep -v node_modules
```

A `checkServerIdentity` passed inside `tls:` to `new Agent(...)` or `setGlobalDispatcher(new Agent(...))` was not running on an affected version. A `compose(redirect(), cache())` with a shared store is the poisoning setup.

## If you are affected

Upgrade `undici` to 6.29.1, 7.30.1 or 8.12.2, or Node to the 2026-10-21 lines (22.23.4, 24.22.1, 26.12.1 per the [Node.js file](2026-10-nodejs-october-21-security-release-brotli-decoder-rce-cve-2026-111497-tls-hostname-bypasses.md)). If you pinned a certificate through `Agent` `tls` options, decide whether anything connected to a host the pin should have rejected; there is no log of it. If a shared cache sat behind a redirect-capable dispatcher, clear it. [auditing a vibe-coded repo](../playbooks/auditing-a-vibe-coded-repo.md) for the dependency sweep.

## Prevention

- Keep the runtime on a supported Node line and read the security-release post's dependency list as a CVE list; the bundled undici is where `fetch()` lives.
- Pass TLS pinning through `connect`, not `tls`, on undici dispatchers, which the advisory names as the safe path on every version.
- Treat the URL an agent fetches as attacker-chosen and deny egress by default; [agent-sandboxing](../prevention/agent-sandboxing.md).
- [supply-chain-attack-surface](../prevention/supply-chain-attack-surface.md).

## Sources

- [CVE Services — CVE-2026-109829](https://cveawg.mitre.org/api/cve/CVE-2026-109829), [CVE-2026-109383](https://cveawg.mitre.org/api/cve/CVE-2026-109383), [CVE-2026-87018](https://cveawg.mitre.org/api/cve/CVE-2026-87018), [CVE-2026-109869](https://cveawg.mitre.org/api/cve/CVE-2026-109869), [CVE-2026-87029](https://cveawg.mitre.org/api/cve/CVE-2026-87029), [CVE-2026-109841](https://cveawg.mitre.org/api/cve/CVE-2026-109841), [CVE-2026-109924](https://cveawg.mitre.org/api/cve/CVE-2026-109924), [CVE-2026-109932](https://cveawg.mitre.org/api/cve/CVE-2026-109932) — queried 2026-10-28: CNA openjs, all published 2026-10-15, titles, affected and unaffected version boundaries, CVSS 3.1 scores and vectors, descriptions.
- [GitHub Advisory Database — GHSA-4w7w-5xrc-9h26](https://github.com/advisories/GHSA-4w7w-5xrc-9h26), [GHSA-2m5v-pch6-74hx](https://github.com/advisories/GHSA-2m5v-pch6-74hx), [GHSA-qrxm-fqhp-jwvm](https://github.com/advisories/GHSA-qrxm-fqhp-jwvm) — fetched 2026-10-28: vendor-published 2026-10-15, database-published and reviewed 2026-10-27, CWEs, mechanisms, workarounds, credits, references; [GHSA-xjj6-f33q-929c](https://github.com/advisories/GHSA-xjj6-f33q-929c) — fetched 2026-10-28: reviewed 10-23, the five-codings mechanism.
- [nodejs/undici — release v8.12.2](https://github.com/nodejs/undici/releases/tag/v8.12.2) — fetched 2026-10-28: dated 15 Oct, the eight-row security table with CVE and GHSA ids and severities.
- [GitHub Advisory Database — agent listing, sorted by publication](https://github.com/advisories?query=agent+sort%3Apublished-desc) — fetched 2026-10-28: the three undici rows reviewed 10-27.
- [nodejs/node — CHANGELOG_V26.md](https://raw.githubusercontent.com/nodejs/node/main/doc/changelogs/CHANGELOG_V26.md), [CHANGELOG_V24.md](https://raw.githubusercontent.com/nodejs/node/main/doc/changelogs/CHANGELOG_V24.md), [CHANGELOG_V22.md](https://raw.githubusercontent.com/nodejs/node/main/doc/changelogs/CHANGELOG_V22.md) — fetched 2026-10-28: the 2026-10-21 entries for 26.12.1, 24.22.1 and 22.23.4 each carry a "deps: update undici" line to 8.12.2, 7.30.1 and 6.29.1 respectively.
- [nodejs/nodejs-dependency-vuln-assessments — issue #482](https://github.com/nodejs/nodejs-dependency-vuln-assessments/issues/482) — fetched 2026-10-28: opened 2026-10-20 by the bot, CVE-2026-109829 in undici 8.11.2 on v26.x, no comments.
- [Node.js — October 2026 Security Releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) — fetched 2026-10-28: the ten Node CVEs and the dependency list "Undici on 26.x, 24.x, 22.x" with no CVE mapping.
- npm registry, `npm view undici time`, queried 2026-10-28: 8.12.1 2026-10-14, 6.29.1, 7.30.1 and 8.12.2 2026-10-15, 8.12.3 2026-10-19; `npm view next@latest dependencies` (16.4.3) declares no undici.
