{
  "id": "nodejs-oct-2026",
  "url": "https://ohshit.app/incidents/nodejs-oct-2026/",
  "title": "Node.js October security releases for 22, 24 and 26: ten CVEs, including a Brotli RCE and TLS hostname bypasses",
  "level": 4,
  "level_name": "septic-tank-blew",
  "date": "2026-10-21",
  "date_is_approximate": false,
  "updated": null,
  "tags": [
    "Node.js",
    "TLS",
    "RCE"
  ],
  "ecosystems": [
    "node"
  ],
  "summary": "Four HIGH, three MEDIUM and three LOW. An out-of-bounds write in the Brotli decoder, dns.resolve truncating names at a NUL byte, and IP spellings that sneak past certificate hostname checks. The release also rejects the compromised eMudhra keys.",
  "splash": "Node.js 22.x, 24.x, 26.x and every end-of-life line",
  "wipe": "Upgrade to 22.23.4 / 24.22.1 / 26.12.1, rebuild containers, then restart so old TLS sessions drop",
  "in_the_wild": "n/a",
  "source_exception": null,
  "cves": [
    {
      "id": "CVE-2026-111497",
      "name": "Brotli decoder out-of-bounds write",
      "description": "Decompressing attacker-controlled Brotli data can write out of bounds, leading to possible code execution.",
      "plain": "someone flushes a brick, and the pipes burst into your server room."
    },
    {
      "id": "CVE-2026-105482",
      "name": "dns.resolve truncates at NUL",
      "description": "Hostnames containing a NUL byte are cut short, so the name you check is not the name you resolve."
    },
    {
      "id": "CVE-2026-105483",
      "name": "Fullwidth-digit IP hostname bypass",
      "description": "An IP address written with fullwidth digits can pass TLS hostname verification. Affects 24.x and 26.x only."
    },
    {
      "id": "CVE-2026-106069",
      "name": "Loose IP resolution hostname bypass",
      "description": "Hosts that loosely resolve to an IP address can slip past TLS hostname checks. Affects all three lines."
    },
    {
      "id": "CVE-2026-105481",
      "name": "Premature keep-alive response",
      "description": "A keep-alive socket can process a response written before its request was sent. Affects 22.x, 24.x and 26.x."
    },
    {
      "id": "CVE-2026-106072",
      "name": "Non-canonical IPv4 certificate validation",
      "description": "DNS SANs can authenticate IP endpoints through non-canonical IPv4 hostnames. Affects 22.x, 24.x and 26.x."
    },
    {
      "id": "CVE-2026-106074",
      "name": "Repeated entropy after startup snapshots",
      "description": "Startup snapshots and SEAs preserve randomUUID and randomInt entropy caches, repeating values across processes. Affects 22.x, 24.x and 26.x."
    },
    {
      "id": "CVE-2026-106070",
      "name": "Invalid ZIP header prefix returned",
      "description": "ZipFile can return attacker-controlled prefix bytes after header validation fails. Affects 26.x."
    },
    {
      "id": "CVE-2026-106071",
      "name": "Filesystem wildcard permission over-grant",
      "description": "Wildcard radix lookup can grant excessive filesystem permissions. Affects 26.x."
    },
    {
      "id": "CVE-2026-106073",
      "name": "realpathSync permission bypass",
      "description": "fs.realpathSync can bypass the Permission Model. Affects 22.x, 24.x and 26.x."
    }
  ],
  "fixed": [
    {
      "product": "Node.js 26",
      "branch": "26",
      "version": "26.12.1",
      "status": "Current"
    },
    {
      "product": "Node.js 24",
      "branch": "24",
      "version": "24.22.1",
      "status": "Active LTS"
    },
    {
      "product": "Node.js 22",
      "branch": "22",
      "version": "22.23.4",
      "status": "Maintenance LTS"
    },
    {
      "product": "Node.js 20 and older",
      "version": "none",
      "status": "End of life, affected, no fix"
    }
  ],
  "checklist": [
    {
      "title": "Inventory Node versions",
      "hint": "Servers, Lambda/Vercel/Cloud Run runtimes, Docker base images, CI"
    },
    {
      "title": "Upgrade to 22.23.4 / 24.22.1 / 26.12.1",
      "hint": "Bump .nvmrc, engines and base images too"
    },
    {
      "title": "Rebuild and redeploy containers",
      "hint": "node:22-alpine from last week is still vulnerable"
    },
    {
      "title": "Restart long-running services",
      "hint": "Resumed TLS sessions are not re-verified against the new CA store"
    },
    {
      "title": "Get off end-of-life Node",
      "hint": "Node 20 and older are affected and get no fix"
    }
  ],
  "sources": [
    {
      "name": "Node.js blog",
      "url": "https://nodejs.org/en/blog/vulnerability/october-2026-security-releases",
      "says": "Official advisory with all ten CVEs and fixed versions",
      "primary": true
    },
    {
      "name": "Vercel KB",
      "url": "https://vercel.com/kb/bulletin/node-js-security-advisory",
      "says": "Platform guidance; notes resumed TLS sessions are not re-verified",
      "primary": false
    }
  ],
  "headline": "Node.js: a Brotli RCE and two ways to fool TLS hostname checks",
  "one_liner": "Send a server a crafted Brotli-compressed body and it writes past a buffer; or present a certificate for an IP written in a weird way and Node may accept it for a host it does not belong to.",
  "in_the_wild_note": "No exploitation reported",
  "mitigation": null,
  "timeline": [
    {
      "date": "Oct 21, 2026",
      "title": "Node.js ships security releases for 22, 24 and 26",
      "body": "Ten CVEs in total, plus dependency bumps for c-ares, ca-cert, OpenSSL (22/24), SQLite (22) and Undici."
    },
    {
      "date": "Oct 21, 2026",
      "title": "Bundled CA store updated to NSS 3.131.1",
      "body": "TLS chains that contain the eight compromised eMudhra keys are now rejected."
    }
  ],
  "body_markdown": "A routine-looking security release with a few nasty pieces. The headline item is an **out-of-bounds write\nin the Brotli decoder** (CVE-2026-111497). Anything that decompresses untrusted Brotli data, such as HTTP\nbodies, uploads or proxied responses, should treat this as a remote code execution risk.\n\nTwo separate bugs (CVE-2026-105483 and CVE-2026-106069) let unusual IP spellings pass **TLS hostname\nverification**. That is the check that makes sure the certificate actually belongs to the server you meant\nto reach.\n\nThe same release ships a `ca-cert` update that **rejects TLS chains containing the compromised eMudhra keys**.\nSee the [eMudhra incident](/incidents/emudhra-ca/). Already-resumed TLS sessions are not re-checked, so\nrestart services after upgrading.\n\nWe grade it **L4**. It is a core runtime with a remotely reachable memory bug, but there is no\nexploitation in the wild yet."
}