GHSA-mghh-pgcx-3jjj: Npm/axios vulnerability

Published Sep 30, 2026
·
Updated

Summary

Axios shouldBypassProxy() normalizes hostnames with hostname.replace(/\.+$/, ''). For a hostname shaped as many dots followed by a non-dot, the anchored regex can perform quadratic backtracking. Because axios re-evaluates proxy bypass rules for redirected requests, a malicious server can trigger this synchronous work through a crafted redirect Location.

The issue affects Node.js applications that use environment proxy variables with NOPROXY and allow redirects.

Impact

An attacker-controlled server can return a redirect whose hostname causes 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.

Affected Functionality

Affected:

- Node.js HTTP adapter. - Environment proxy handling through HTTPPROXY or HTTPSPROXY. - NOPROXY or noproxy set to a non-empty value. - Redirects followed by axios or follow-redirects.

Not affected:

- Browser adapters. - Requests with proxy: false. - Requests with no NOPROXY value. - Requests with maxRedirects: 0, unless application code manually follows the malicious redirect and re-enters axios.

Technical Details

lib/helpers/shouldBypassProxy.js contains:

js return unmapIPv4MappedIPv6(hostname.replace(/\.+$/, ''));

When the hostname is "." n + "a", the $ anchor causes the regex engine to retry the dot run from many positions before it fails. setProxy() invokes shouldBypassProxy(location) after getProxyForUrl(location) returns a proxy, including on redirect hops via beforeRedirects.proxy.

Local timing on axios 1.18.1 showed increasing cost for crafted hostnames: about 1 ms at 1000 dots, 6.9 ms at 3000 dots, and 34.5 ms at 6000 dots. The growth is consistent with the submitted quadratic claim while avoiding long-running payloads.

Proof of Concept of Attack

Constrained helper-level demonstration:

js import shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js';

process.env.NOPROXY = 'example.com'; shouldBypassProxy('http://' + '.'.repeat(6000) + 'a/');

In the full adapter path, a malicious server can return that hostname in a 302 Location header while the client has proxy environment variables and NOPROXY configured.

Workarounds

Disable automatic redirects for requests to untrusted servers, or avoid environment proxy handling for those requests with proxy: false when appropriate. Operators can also avoid broad untrusted redirect-following in services where event-loop availability is critical.

<details> <summary><h3>Original report</h3></summary> Summary

shouldBypassProxy normalizes a host with hostname.replace(/\.+$/, ''). On a host of the shape <many dots><non-dot> (e.g. "." × 40000 + "a"), this anchored regex backtracks quadratically (O(N²)), synchronously starving the Node.js event loop. Because axios re-evaluates the proxy on every redirect using the new Location host, a malicious server can return a crafted 302 Location and freeze the client's event loop for seconds per redirect — a denial of service.

Details

- Affected code: lib/helpers/shouldBypassProxy.js → normalizeNoProxyHost: hostname.replace(/\.+$/, '') (one pass in 1.18.1). The open PR #11029 adds a second /\.+$/ pass in normalizeIPAddress, doubling the cost (not the origin). - Root cause: /\.+$/ is O(N²) on a long run of dots that is not at the end of the string — the $ anchor forces the engine to backtrack the entire dot-run from every start position. - Trust boundary (per THREATMODEL): the redirect Location is untrusted (T-2: "axios to network … redirect Location … untrusted"). The caller requests a benign URL; the malicious host arrives via the server's 302. This is not the T-1 caller-supplied-URL non-goal. - Call chain: setProxy(options, configProxy, location, isRedirect, …) (lib/adapters/http.js) → env-proxy branch → getProxyForUrl(location) returns a proxy → if (!shouldBypassProxy(location)) → normalizeNoProxyHost(parsed.hostname.toLowerCase()) runs /\.+$/. setProxy is re-invoked on the redirect hop with the untrusted Location; new URL() retains the long dot-run in .hostname. - Preconditions: proxy configured via environment (HTTPPROXY/HTTPSPROXY, trusted per THREATMODEL T-3, common in CI/containers/enterprise) + NOPROXY set + redirects followed (default maxRedirects: 5).

PoC

Self-contained, no network — imports axios's own helper: // node poc.mjs (run next to an axios install) import sbp from './nodemodules/axios/lib/helpers/shouldBypassProxy.js'; process.env.NOPROXY = 'example.com'; for (const n of [5000, 10000, 20000, 40000]) { const url = 'http://' + '.'.repeat(n) + 'a/'; // arrives as an untrusted 302 Location host const t0 = process.hrtime.bigint(); sbp(url); // returns false (correct no-bypass) — but O(N^2) slow console.log(N=${n}: ${(Number(process.hrtime.bigint()-t0)/1e6)|0} ms); } // Measured on 1.18.1: N=5000 ~43ms, 10000 ~160ms, 20000 ~618ms, 40000 ~2499ms; benign host ~0.05ms. Driven through the real http-adapter setProxy on the redirect path (setProxy(…, isRedirect=true)), a 10 ms timer fires 0 times during the ~2.4 s block at N=40000 — full event-loop starvation.

Impact

Denial of service (event-loop starvation) on any axios client that uses an environment proxy with NOPROXY set and follows redirects, when a server it contacts returns a crafted redirect Location. No data exposure or RCE. Same impact class as the accepted DoS advisories GHSA-62hf-57xw-28j9 (toFormData recursion) and the maxContentLength response-size DoS.

Suggested fix

Replace the regex trailing-dot strip with a linear trim: let end = hostname.length; while (end > 0 && hostname.charCodeAt(end - 1) === 46 / '.' /) end--; hostname = hostname.slice(0, end); Also drop the redundant second /\.+$/ pass in PR #11029's normalizeIPAddress. </details>

---

Affected Software

1 affected componentFixes available
npm/axios>=1.15.0<1.20.0
1.20.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/axios to a version that resolves this vulnerability.

    Fixed in 1.20.0
  2. Configuration

    Disable automatic redirects for requests to untrusted servers.

    Axios maxRedirects = 0
  3. Configuration

    Avoid environment proxy handling for requests to untrusted servers when appropriate.

    Axios proxy = false
  4. Compensating control

    In axios/lib/helpers/shouldBypassProxy.js, replace hostname.replace(/\.+$/, '') with a linear trailing-dot trim; also drop the redundant second /\.+$/ pass in PR #11029's normalizeIPAddress.

Event History

Sep 30, 2026
Advisory Published
via GitHub·03:03 PM
Data Sourced
via GitHub·03:03 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

Which deployments are exposed to this issue?

Exposure requires the Node.js HTTP adapter, environment proxy handling through HTTP_PROXY or HTTPS_PROXY, a non-empty NO_PROXY or no_proxy value, and redirects that axios or follow-redirects will follow. Browser adapters are not affected.

2

What does an attacker need to do to trigger the CPU consumption?

The attacker needs to control a server that the application requests and have it return a redirect with a crafted Location hostname. Axios re-evaluates proxy bypass rules during redirected requests, allowing the crafted hostname to trigger synchronous processing.

3

What temporary configuration changes avoid the affected path?

Requests configured with proxy: false are not affected. Requests with no NO_PROXY value are also not affected; any such change should be evaluated for its effect on required proxy routing.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203