2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-17 19:21:29 +03:00

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 <jasonsaayman@gmail.com>
This commit is contained in:
Nezuko Agent
2026-05-25 00:05:48 +07:00
committed by GitHub
parent 7b3369a9c4
commit 140a17944a
2 changed files with 12 additions and 9 deletions
+1
View File
@@ -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**)
+11 -9
View File
@@ -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)