← Back to Feed CACHED · 2026-07-30 03:32:25 · CACHE_KEY CVE-2026-16729
CVE-2026-16729 · CWE-74 · Disclosed 2026-07-29

undici's setCookie function does not fully sanitize cookie attributes

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

Someone left a semicolon-sized gap in the cookie jar's lid, but you have to reach through a very specific shelf to exploit it

CVE-2026-16729 targets undici's setCookie() function — the cookie-management helper in Node.js's built-in HTTP client. Two injection paths exist: (1) the domain parameter is not checked for semicolons, so a value like example.com; SameSite=None passes through verbatim and appends an attacker-chosen attribute; (2) entries in the unparsed array are only checked for an equals sign without sanitizing for embedded semicolons, so X-Custom=val; HttpOnly injects an HttpOnly flag the caller never intended. Affected versions span undici < 6.28.0, 7.0.0–7.28.x, and 8.0.0–8.8.x. Because Node.js v18+ bundles undici for its global fetch() implementation, the vulnerable library is present on every active Node.js installation — but the *specific API* (setCookie) is far less commonly invoked than fetch() or request().

The vendor's MEDIUM 4.8 is broadly appropriate but slightly generous. The CVSS vector already encodes AC:H (high attack complexity), yet even that understates the real-world friction: the attacker must find an application that (a) imports and calls setCookie() directly, *and* (b) pipes user-controlled input into the domain or unparsed fields — a pattern almost exclusively found in multi-tenant reverse proxies or SSR frameworks that scope cookies to tenant-supplied domains. That is a small slice of the 139 million weekly npm downloads undici enjoys. The impact ceiling is cookie-security-attribute manipulation (stripping HttpOnly, downgrading SameSite, removing Secure), which is a *precondition* for CSRF or session-fixation — not a standalone compromise. noisgate downgrades slightly to 4.0.

"Cookie attribute injection in undici setCookie is real but demands a narrow, tenant-controlled-input code path"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a setCookie consumer with user-controlled domain input

The attacker surveys the target application for endpoints or configuration flows where a tenant or user supplies a domain value that is eventually passed to undici's setCookie(). Multi-tenant SaaS platforms that let tenants specify cookie-scoping domains, or reverse-proxy layers that reflect upstream Set-Cookie headers through undici's cookie jar, are the canonical targets. Without this specific code path, the vulnerability is unreachable.
Conditions required:
  • Target application uses undici's setCookie() API (not just fetch())
  • User-controlled data flows into the domain or unparsed parameter
Where this breaks in practice:
  • Most undici consumers use fetch() / request() — setCookie is a niche cookie-management helper
  • Multi-tenant cookie-scoping patterns are rare outside purpose-built proxy / SSR frameworks
Detection/coverage: SCA scanners (Snyk, Socket.dev, npm audit) flag the vulnerable undici version. No network-level detection is applicable since this is a library-level logic flaw.
STEP 02

Craft a semicolon-injected domain value

The attacker supplies a domain string like tenant.example.com; SameSite=None; Secure through the identified input channel. Because validateCookieDomain does not reject semicolons (unlike validateCookiePath, which does), the entire string is emitted verbatim into the Set-Cookie header. Alternatively, the attacker injects through the unparsed array with a value like X-Custom=val; HttpOnly to toggle or strip cookie flags.
Conditions required:
  • Input is not independently validated against RFC 1034 LDH character set before reaching setCookie
Where this breaks in practice:
  • Well-written apps validate domain inputs at the API boundary — semicolons are not legal in DNS names
  • WAF rules blocking semicolons in domain-type parameters would stop this trivially
Detection/coverage: Application-layer logging of setCookie arguments would reveal anomalous semicolons in domain values.
STEP 03

Victim browser receives manipulated cookie attributes

The downstream Set-Cookie header now carries attacker-injected attributes. The browser interprets the cookie with the manipulated SameSite, Secure, or HttpOnly flags. For example, stripping SameSite=Strict and injecting SameSite=None enables cross-site request forgery against the victim's session on the target application. Stripping HttpOnly allows JavaScript-based cookie theft via XSS if a separate XSS vulnerability exists.
Conditions required:
  • Victim visits or is redirected to the affected application
  • The manipulated Set-Cookie header reaches the browser without downstream sanitization
Where this breaks in practice:
  • Impact requires a *second* vulnerability (XSS or CSRF target endpoint) to produce meaningful compromise
  • Modern browsers enforce Lax-by-default SameSite policy if no attribute is present, limiting the blast radius of attribute stripping
Detection/coverage: Browser developer tools show unexpected cookie attributes. Server-side cookie-audit middleware can detect attribute mismatches.
STEP 04

Exploit weakened cookie security (CSRF / session fixation)

With SameSite downgraded to None and Secure potentially stripped, the attacker mounts a cross-site request forgery attack or, if HttpOnly was removed and an XSS exists, reads session tokens via document.cookie. The attacker can also perform session fixation by injecting a known session cookie value scoped to the manipulated domain. This is the terminal impact — account-level compromise of individual user sessions, not system-level access.
Conditions required:
  • A CSRF-exploitable state-changing endpoint exists without secondary CSRF tokens
  • OR an XSS vulnerability exists on the same origin to read non-HttpOnly cookies
Where this breaks in practice:
  • Applications using anti-CSRF tokens (e.g., Django CSRF, Express csurf, framework-provided double-submit) are not affected by SameSite downgrade alone
  • The chain requires *two* independent vulnerabilities to reach meaningful impact
Detection/coverage: CSRF exploit attempts are detectable via Referer/Origin header mismatches. XSS payloads are catchable by CSP and WAF.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. Not listed in CISA KEV. No campaigns or threat-actor usage reported as of 2026-07-30. Disclosed yesterday (2026-07-29).
Proof-of-conceptNo public PoC. The GHSA advisory (GHSA-v3r7-h72x-cjcm) describes the injection mechanism (semicolons in domain, unsanitized unparsed entries) but no exploit code is published. Reporter: Zelys-DFKH.
EPSS scoreNot yet scored — CVE was published 2026-07-29; FIRST EPSS data is not yet populated. Expected to be very low (<5th percentile) given AC:H and no public exploit.
KEV statusNot listed. No CISA Known Exploited Vulnerability catalog entry.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N — Network-reachable but high complexity. No privileges or user interaction required. Scope unchanged. Low C+I, no availability impact. The AC:H is driven by the requirement for user-controlled input flowing into a specific API.
Affected versionsundici < 6.28.0, 7.0.0 – 7.28.x, 8.0.0 – 8.8.x. The flaw has existed since setCookie was introduced. All three active major branches are affected.
Fixed versionsundici 6.28.0, 7.29.0, 8.9.0. Node.js bundled fixes: Node 22.23.2 (undici 6.28.0), Node 24.18.1 (undici 7.29.0), Node 26.5.1 (undici 8.9.0). Released 2026-07-29.
Scanning / exposure dataNot applicable for network scanning — this is a library-level logic flaw, not an exposed service. Shodan/GreyNoise/Censys cannot fingerprint it. Software composition analysis (SCA) is the detection vector. undici has ~139M weekly npm downloads but setCookie usage is a fraction of that.
Disclosure timelineCVE reserved 2026-07-23. GHSA + Node.js coordinated release 2026-07-29. Part of a batch fixing 10+ CVEs across Node.js 22/24/26.
Reporter / creditsZelys-DFKH (reporter). Remediation reviewed by mcollina and UlisesGascon (Node.js core team).
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (4.0/10)

The single most decisive factor is the narrow code path required for exploitation: the attacker must find an application that calls undici's setCookie() with user-controlled domain or unparsed input — a pattern confined to multi-tenant cookie-scoping proxies, which represent a small fraction of undici's 139M-weekly-download install base. Even when the chain succeeds, the terminal impact is cookie-attribute manipulation (SameSite/HttpOnly/Secure downgrade), which is a precondition for CSRF or session-fixation, not a standalone compromise.

HIGH Vulnerability mechanics and affected versions
HIGH No in-the-wild exploitation (1 day post-disclosure, no KEV, no campaigns)
MEDIUM Fraction of install base using setCookie with user-controlled input (estimated <5% but no hard data)
LOW EPSS projection (no data available yet)

Why this verdict

  • Narrow API surface: setCookie() is a cookie-management helper, not the primary fetch/request path. The vast majority of undici consumers never call it, and fewer still pass user-controlled data into domain or unparsed. This is materially narrower than AC:H alone captures.
  • Two-vuln chain to meaningful impact: Stripping SameSite or HttpOnly is a *precondition*, not a *compromise*. The attacker still needs a CSRF-exploitable endpoint (without secondary tokens) or an XSS on the same origin to extract cookies. Modern frameworks ship anti-CSRF tokens by default.
  • Role multiplier: undici is bundled in every Node.js 18+ runtime, giving it presence on CI/CD runners, SSR servers, API gateways, and internal tooling. However, the affected API (setCookie) is not invoked in any of these high-value roles by default — it requires deliberate, custom cookie-scoping code. On a CI/CD server or build runner, setCookie with tenant domains is essentially non-existent. On an SSR framework or reverse proxy that *does* scope cookies to tenant domains, the blast radius is tenant-level session integrity, not fleet compromise or supply-chain pivot. No high-value-role floor is triggered because the terminal impact (cookie attribute manipulation) does not reach domain takeover, fleet compromise, or supply-chain scale.
  • Browser defaults as backstop: Chrome, Firefox, and Edge enforce SameSite=Lax by default when no SameSite attribute is present. An attacker who *strips* SameSite still gets Lax enforcement, limiting the CSRF window to top-level GET navigations only.
  • Fresh disclosure, zero exploitation signal: Published 2026-07-29 with no PoC, no KEV listing, no campaign reports. The attack prerequisites make automated mass exploitation unlikely.

Why not higher?

The vulnerability cannot reach HIGH because the terminal impact is limited to cookie-attribute manipulation — there is no path to remote code execution, privilege escalation, or direct data access. Exploitation requires a second independent vulnerability (XSS or unprotected CSRF endpoint) to produce meaningful harm. The affected API (setCookie) is a niche helper within a library whose primary use case (HTTP requests via fetch/request) is unaffected. No high-value-role deployment pattern puts setCookie in a position where attribute injection escalates to domain or fleet compromise.

Why not lower?

The vulnerability cannot drop to LOW because the attack vector is network-reachable with no authentication or user interaction required (AV:N/PR:N/UI:N), undici's install base is genuinely enormous (~139M weekly downloads, bundled in all active Node.js lines), and the specific multi-tenant reverse-proxy pattern — while uncommon — is not hypothetical. Cookie security attribute manipulation can enable real CSRF bypass in applications that rely solely on SameSite for CSRF protection, which is an increasingly common (if incomplete) pattern. The coordinated Node.js emergency release treating this as part of a 10-CVE batch also signals the maintainers consider it actionable.

05 · Compensating Control

What to do — in priority order.

  1. Validate domain inputs against RFC 1034 LDH charset before calling setCookie — Reject any domain string containing semicolons, spaces, or non-LDH characters at your application's input boundary. This is the most targeted fix and eliminates the injection vector entirely. Implement within your normal MEDIUM remediation window (365 days per noisgate SLA), but sooner if you know you pass user input to setCookie.
  2. Audit codebase for setCookie usage with user-controlled parameters — Run grep -rn 'setCookie\|set-cookie' --include='*.js' --include='*.ts' across your Node.js services. If no call sites pass user-controlled data to domain or unparsed, your exposure is zero and you can deprioritize. This triage step should take hours, not days.
  3. Upgrade undici or Node.js to patched versions — Update to undici 6.28.0 / 7.29.0 / 8.9.0, or Node.js 22.23.2 / 24.18.1 / 26.5.1. This is the definitive fix. Schedule within the noisgate remediation SLA of 365 days for MEDIUM severity.
  4. Ensure anti-CSRF tokens are in place on all state-changing endpoints — If your application relies solely on SameSite cookies for CSRF protection, add framework-level CSRF tokens (e.g., csurf, Django CSRF middleware, Rails authenticity tokens). This neutralizes the downstream impact even if cookie attributes are manipulated.
What doesn't work
  • WAF rules blocking cookie injection — The injection happens *inside* the application's own setCookie call, not in inbound HTTP headers. A WAF inspecting request headers won't see the manipulated Set-Cookie being emitted in the response unless you have egress header inspection, which most WAFs don't perform.
  • Upgrading Node.js without checking direct undici dependency — If your app has undici in package.json as a direct dependency (not just the bundled version), upgrading Node.js alone won't fix the direct import. You must also npm update undici or pin the fixed version.
  • Content Security Policy (CSP) — CSP controls script execution and resource loading, not cookie attribute parsing. It does not prevent SameSite downgrade or HttpOnly stripping.
06 · Verification

Crowdsourced verification payload.

Run this on any host or CI runner with Node.js installed. It checks both the bundled undici version (via process.versions.undici) and any directly-installed undici in node_modules. No special privileges needed. Example: bash check_cve_2026_16729.sh /path/to/your/project

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_16729.sh — Detect undici versions vulnerable to CVE-2026-16729
# Usage: bash check_cve_2026_16729.sh [project_dir]
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -euo pipefail

PROJECT_DIR="${1:-.}"
VULNERABLE=0

echo "=== CVE-2026-16729 Check ==="
echo "Checking undici for cookie attribute injection via unsanitized setCookie fields"
echo ""

# Function to compare semver (major.minor.patch)
ver_lt() {
  local IFS='.'
  read -ra a <<< "$1"
  read -ra b <<< "$2"
  for i in 0 1 2; do
    local ai="${a[$i]:-0}"
    local bi="${b[$i]:-0}"
    if (( ai < bi )); then return 0; fi
    if (( ai > bi )); then return 1; fi
  done
  return 1  # equal means not less-than
}

# Check 1: Bundled undici in Node.js
echo "[1] Checking bundled undici version in Node.js..."
BUNDLED_VER=$(node -e 'console.log(process.versions.undici || "none")' 2>/dev/null || echo "none")
if [ "$BUNDLED_VER" = "none" ]; then
  echo "    Node.js does not expose bundled undici version (likely Node < 18). Skipping."
else
  echo "    Bundled undici version: $BUNDLED_VER"
  MAJOR=$(echo "$BUNDLED_VER" | cut -d. -f1)
  if [ "$MAJOR" -le 6 ] && ver_lt "$BUNDLED_VER" "6.28.0"; then
    echo "    RESULT: VULNERABLE (needs >= 6.28.0)"
    VULNERABLE=1
  elif [ "$MAJOR" -eq 7 ] && ver_lt "$BUNDLED_VER" "7.29.0"; then
    echo "    RESULT: VULNERABLE (needs >= 7.29.0)"
    VULNERABLE=1
  elif [ "$MAJOR" -eq 8 ] && ver_lt "$BUNDLED_VER" "8.9.0"; then
    echo "    RESULT: VULNERABLE (needs >= 8.9.0)"
    VULNERABLE=1
  else
    echo "    RESULT: PATCHED"
  fi
fi

echo ""

# Check 2: Direct undici dependency in project
echo "[2] Checking direct undici dependency in $PROJECT_DIR ..."
PKG_JSON="$PROJECT_DIR/node_modules/undici/package.json"
if [ -f "$PKG_JSON" ]; then
  DIRECT_VER=$(node -e "console.log(require('$PKG_JSON').version)" 2>/dev/null || echo "unknown")
  if [ "$DIRECT_VER" = "unknown" ]; then
    echo "    Could not parse version from $PKG_JSON"
  else
    echo "    Direct undici version: $DIRECT_VER"
    MAJOR=$(echo "$DIRECT_VER" | cut -d. -f1)
    if [ "$MAJOR" -le 6 ] && ver_lt "$DIRECT_VER" "6.28.0"; then
      echo "    RESULT: VULNERABLE (needs >= 6.28.0)"
      VULNERABLE=1
    elif [ "$MAJOR" -eq 7 ] && ver_lt "$DIRECT_VER" "7.29.0"; then
      echo "    RESULT: VULNERABLE (needs >= 7.29.0)"
      VULNERABLE=1
    elif [ "$MAJOR" -eq 8 ] && ver_lt "$DIRECT_VER" "8.9.0"; then
      echo "    RESULT: VULNERABLE (needs >= 8.9.0)"
      VULNERABLE=1
    else
      echo "    RESULT: PATCHED"
    fi
  fi
else
  echo "    No direct undici dependency found in $PROJECT_DIR/node_modules/"
fi

echo ""

# Check 3: Grep for setCookie usage (exposure check)
echo "[3] Scanning for setCookie usage in $PROJECT_DIR (exposure check)..."
SETCOOKIE_HITS=$(grep -rn 'setCookie\|setCookies' --include='*.js' --include='*.ts' --include='*.mjs' "$PROJECT_DIR/" 2>/dev/null | grep -v node_modules | head -20 || true)
if [ -n "$SETCOOKIE_HITS" ]; then
  echo "    WARNING: setCookie usage found — review for user-controlled domain/unparsed input:"
  echo "$SETCOOKIE_HITS" | while IFS= read -r line; do echo "      $line"; done
else
  echo "    No setCookie calls found outside node_modules. Exposure is likely ZERO."
fi

echo ""
echo "=== Summary ==="
if [ "$VULNERABLE" -eq 1 ]; then
  echo "VULNERABLE — Update undici or Node.js to a patched version."
  exit 1
else
  if [ "$BUNDLED_VER" = "none" ] && [ ! -f "$PKG_JSON" ]; then
    echo "UNKNOWN — Could not determine undici version."
    exit 2
  else
    echo "PATCHED — No vulnerable undici versions detected."
    exit 0
  fi
fi
07 · Bottom Line

If you remember one thing.

TL;DR
This is a MEDIUM-severity library flaw with zero exploitation in the wild and a narrow attack surface. Monday morning action: run npm audit or your SCA scanner across Node.js services to identify undici versions below 6.28.0 / 7.29.0 / 8.9.0. Then grep for setCookie calls with user-controlled input — if you find none, your actual exposure is zero and this becomes a routine dependency bump. There is no noisgate mitigation SLA for MEDIUM — go straight to the noisgate remediation SLA of 365 days and schedule the undici or Node.js upgrade (22.23.2 / 24.18.1 / 26.5.1) in your next planned maintenance window. If you *do* find setCookie calls accepting tenant-supplied domains, add RFC 1034 LDH validation on those inputs this sprint as a targeted fix while you plan the broader upgrade. No emergency patching is warranted.

Sources

  1. GitHub Advisory GHSA-v3r7-h72x-cjcm
  2. CVE-2026-16729 — THREATINT
  3. Node.js July 2026 Security Releases
  4. Node.js Ships 22.23.2, 24.18.1, 26.5.1 Emergency Patch
  5. undici npm package
  6. undici GitHub repository
  7. Related advisory — GHSA-g8m3-5g58-fq7m (SameSite substring matching)
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.