From 140a17944a6ff175611597c874e218ad6c2afd1c Mon Sep 17 00:00:00 2001 From: Nezuko Agent Date: Mon, 25 May 2026 00:05:48 +0700 Subject: [PATCH] fix: guard socketPath with own() to prevent prototype pollution SSRF (#10901) * fix: guard socketPath with own() to prevent prototype pollution SSRF CVE-2026-42264 fix introduced the own() helper to guard config reads, but socketPath and allowedSocketPaths were missed. An attacker who can pollute Object.prototype.socketPath (via another dependency) can redirect all axios requests to a Unix socket (e.g. Docker daemon), enabling SSRF and container escape. Fix: use own('socketPath') and own('allowedSocketPaths') instead of direct config property access. Ref: GHSA-72mg-mc2j-cwf6 Fixes: CVE-2026-42264 (complete) * docs: add socketPath security release note --------- Co-authored-by: Jay --- PRE_RELEASE_CHANGELOG.md | 1 + lib/adapters/http.js | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/PRE_RELEASE_CHANGELOG.md b/PRE_RELEASE_CHANGELOG.md index 9abc1394..837d32b8 100644 --- a/PRE_RELEASE_CHANGELOG.md +++ b/PRE_RELEASE_CHANGELOG.md @@ -9,6 +9,7 @@ ## Bug Fixes - **AxiosHeaders:** Silently skip empty response header names emitted by some React Native Android responses instead of throwing. (**#6959**, **#10875**) +- **HTTP Adapter - Socket Path:** Ignore inherited `socketPath` and `allowedSocketPaths` config values when building Node.js requests, preventing prototype-pollution SSRF via Unix sockets. (**#10901**) - **React Native FormData:** Clear the default `Content-Type` header for React Native `FormData` requests so Android can build multipart bodies with the correct boundary. (**#10898**) - **Request Data:** Preserve enumerable symbol keys when merging plain request data before `transformRequest`. (**#6392**) diff --git a/lib/adapters/http.js b/lib/adapters/http.js index c27cbeaa..f8f3d7d4 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -790,19 +790,21 @@ export default isHttpAdapterSupported && // cacheable-lookup integration hotfix !utils.isUndefined(lookup) && (options.lookup = lookup); - if (config.socketPath) { - if (typeof config.socketPath !== 'string') { + const socketPath = own('socketPath'); + if (socketPath) { + if (typeof socketPath !== 'string') { return reject( new AxiosError('socketPath must be a string', AxiosError.ERR_BAD_OPTION_VALUE, config) ); } - if (config.allowedSocketPaths != null) { - const allowed = Array.isArray(config.allowedSocketPaths) - ? config.allowedSocketPaths - : [config.allowedSocketPaths]; + const allowedSocketPaths = own('allowedSocketPaths'); + if (allowedSocketPaths != null) { + const allowed = Array.isArray(allowedSocketPaths) + ? allowedSocketPaths + : [allowedSocketPaths]; - const resolvedSocket = resolvePath(config.socketPath); + const resolvedSocket = resolvePath(socketPath); const isAllowed = allowed.some( (entry) => typeof entry === 'string' && resolvePath(entry) === resolvedSocket ); @@ -810,7 +812,7 @@ export default isHttpAdapterSupported && if (!isAllowed) { return reject( new AxiosError( - `socketPath "${config.socketPath}" is not permitted by allowedSocketPaths`, + `socketPath "${socketPath}" is not permitted by allowedSocketPaths`, AxiosError.ERR_BAD_OPTION_VALUE, config ) @@ -818,7 +820,7 @@ export default isHttpAdapterSupported && } } - options.socketPath = config.socketPath; + options.socketPath = socketPath; } else { options.hostname = parsed.hostname.startsWith('[') ? parsed.hostname.slice(1, -1)