CVE-2026-101906: Axios Denial of Service Vulnerability

HIGH
Advisory Identifier: GHSA-mghh-pgcx-3jjj
CWE-400 CWE-1333
Published
Advisory Summary

CVE-2026-101906 is a HIGH denial of service vulnerability (CWE-400: Uncontrolled Resource Consumption) affecting Axios libraries in the npm ecosystem. The issue involves redos (o(n²)) in shouldbypassproxy host normalization, reachable via untrusted redirect location. Remediation is available by upgrading affected packages to version 1.20.0.

CVE-2026-101906 at a Glance

CVE Identifier CVE-2026-101906
GHSA Identifier GHSA-mghh-pgcx-3jjj
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-400: Uncontrolled Resource Consumption
Affected Product Axios
Package Ecosystem npm
Published Date
Last Updated

How to Fix CVE-2026-101906

To remediate this vulnerability, upgrade all affected Axios dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

axios fixed: 1.20.0
npm install axios@1.20.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls axios

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-101906, inspect your project dependencies using npm:

npm ls axios

Analyze the terminal output to locate any version of Axios in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.20.0), your application is affected.

Note: The npm ls axios command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-400: Uncontrolled Resource Consumption, where the product does not properly control the allocation and maintenance of a limited resource. In Axios, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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 `NO_PROXY` 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 `HTTP_PROXY` or `HTTPS_PROXY`. - `NO_PROXY` or `no_proxy` set to a non-empty value. - Redirects followed by axios or `follow-redirects`. Not affected: - Browser adapters. - Requests with `proxy: false`. - Requests with no `NO_PROXY` 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.NO_PROXY = '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 `NO_PROXY` 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 (HTTP_PROXY/HTTPS_PROXY, trusted per THREATMODEL T-3, common in CI/containers/enterprise) + NO_PROXY 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 './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/'; // 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 NO_PROXY 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> ---

CVE-2026-101906 Affected Axios Versions

1 component(s)
Fixed Versions:
1.20.0
Product / Package Ecosystem Affected Versions Fixed Version
axios
npm
≥ 1.15.0
< 1.20.0
1.20.0

References

Frequently Asked Questions

What is CVE-2026-101906?
CVE-2026-101906 is a security vulnerability in Axios involving ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location under CWE-400: Uncontrolled Resource Consumption.
Which Axios versions are affected?
Affected versions include releases prior to 1.20.0 across affected packages: axios.
What version fixes CVE-2026-101906?
Upgrading to 1.20.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is axios affected?
Yes, axios is affected in releases prior to 1.20.0. Upgrade your dependency to 1.20.0 or later.
What CWE is associated with CVE-2026-101906?
CVE-2026-101906 is classified under CWE-400: Uncontrolled Resource Consumption (The product does not properly control the allocation and maintenance of a limited resource.).
How can I check npm dependencies for CVE-2026-101906?
Run the dependency tree command: 'npm ls axios'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-mghh-pgcx-3jjj",
  "modified" : "2026-09-30T15:03:02Z",
  "published" : "2026-09-30T15:03:02Z",
  "aliases" : [ "CVE-2026-101906" ],
  "summary" : "Axios: ReDoS (O(N²)) in shouldBypassProxy host normalization, reachable via untrusted redirect Location",
  "details" : "## Summary\n\nAxios `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`.\n\nThe issue affects Node.js applications that use environment proxy variables with `NO_PROXY` and allow redirects.\n\n## Impact\n\nAn 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.\n\nThis is an availability-only issue. It does not disclose request data or modify requests.\n\n## Affected Functionality\n\nAffected:\n\n- Node.js HTTP adapter.\n- Environment proxy handling through `HTTP_PROXY` or `HTTPS_PROXY`.\n- `NO_PROXY` or `no_proxy` set to a non-empty value.\n- Redirects followed by axios or `follow-redirects`.\n\nNot affected:\n\n- Browser adapters.\n- Requests with `proxy: false`.\n- Requests with no `NO_PROXY` value.\n- Requests with `maxRedirects: 0`, unless application code manually follows the malicious redirect and re-enters axios.\n\n## Technical Details\n\n`lib/helpers/shouldBypassProxy.js` contains:\n\n```js\nreturn unmapIPv4MappedIPv6(hostname.replace(/\\.+$/, ''));\n```\n\nWhen 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`.\n\nLocal 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.\n\n## Proof of Concept of Attack\n\nConstrained helper-level demonstration:\n\n```js\nimport shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js';\n\nprocess.env.NO_PROXY = 'example.com';\nshouldBypassProxy('http://' + '.'.repeat(6000) + 'a/');\n```\n\nIn the full adapter path, a malicious server can return that hostname in a `302 Location` header while the client has proxy environment variables and `NO_PROXY` configured.\n\n## Workarounds\n\nDisable 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.\n\n<details>\n  <summary><h3>Original report</h3></summary>\n  \n### Summary\n\nshouldBypassProxy 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.\n\n### Details\n\n- 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).\n- 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.\n- 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.\n- 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.\n- Preconditions: proxy configured via environment (HTTP_PROXY/HTTPS_PROXY, trusted per THREATMODEL T-3, common in CI/containers/enterprise) + NO_PROXY set + redirects followed (default maxRedirects: 5).\n\n### PoC\n\nSelf-contained, no network — imports axios's own helper:\n// node poc.mjs   (run next to an axios install)\nimport sbp from './node_modules/axios/lib/helpers/shouldBypassProxy.js';\nprocess.env.NO_PROXY = 'example.com';\nfor (const n of [5000, 10000, 20000, 40000]) {\n  const url = 'http://' + '.'.repeat(n) + 'a/';   // arrives as an untrusted 302 Location host\n  const t0 = process.hrtime.bigint();\n  sbp(url);                                         // returns false (correct no-bypass) — but O(N^2) slow\n  console.log(`N=${n}: ${(Number(process.hrtime.bigint()-t0)/1e6)|0} ms`);\n}\n// Measured on 1.18.1: N=5000 ~43ms, 10000 ~160ms, 20000 ~618ms, 40000 ~2499ms; benign host ~0.05ms.\nDriven 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.\n\n### Impact\n\nDenial 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 or RCE. Same impact class as the accepted DoS advisories GHSA-62hf-57xw-28j9 (toFormData recursion) and the maxContentLength response-size DoS.\n\n### Suggested fix\n\nReplace the regex trailing-dot strip with a linear trim:\nlet end = hostname.length;\nwhile (end > 0 && hostname.charCodeAt(end - 1) === 46 /* '.' */) end--;\nhostname = hostname.slice(0, end);\nAlso drop the redundant second /\\.+$/ pass in PR #11029's normalizeIPAddress.\n</details>\n\n---",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "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"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "axios"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "1.15.0"
      }, {
        "fixed" : "1.20.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/security/advisories/GHSA-mghh-pgcx-3jjj"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-101906"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/pull/11141"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/commit/d19040bda7a8be2f82c3c6e1a5bc03917daee39a"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/axios/axios"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/axios/axios/releases/tag/v1.20.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-1333", "CWE-400" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-30T15:03:02Z",
    "nvd_published_at" : "2026-09-28T18:17:19Z"
  }
}