{"schema_version":"1.9.0","id":"GHSA-pjwm-pj3p-43mv","published":"2026-05-29T15:59:30Z","modified":"2026-09-10T03:51:06.693575938Z","aliases":["CVE-2026-44492"],"summary":"axios's shouldBypassProxy does not recognize IPv4-mapped IPv6 addresses, allowing NO_PROXY bypass (incomplete fix for CVE-2025-62718)","details":"### Summary\nshouldBypassProxy, introduced in v1.15.0 to fix CVE-2025-62718, does not normalise IPv4-mapped IPv6 addresses. When NO_PROXY lists an IPv4 address such as `127.0.0.1` or `169.254.169.254`, a request URL using the IPv4-mapped IPv6 form (`::ffff:7f00:1`, `::ffff:a9fe:a9fe`) still routes through the configured proxy. Node.js resolves these addresses to the underlying IPv4 host, so the request reaches the internal service via the proxy rather than being blocked.\n\n### Details\nlib/helpers/shouldBypassProxy.js (v1.15.0):                                                                                                                                   \n\n```javascript                                                                                                                                                                              \n  const LOOPBACK_ADDRESSES = new Set(['localhost', '127.0.0.1', '::1']);                                                                                                      \n  const isLoopback = (host) => LOOPBACK_ADDRESSES.has(host);                                                                                                                    \n                                                                                                                                                                                \n  // normalizeNoProxyHost strips brackets and trailing dots, but not ::ffff: prefix                                                                                             \n  return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost));                                                                                             \n```\n                                                                                                                                                                                \nThe WHATWG URL parser canonicalises `http://[::ffff:127.0.0.1]/` to hostname `[::ffff:7f00:1]`. After bracket-stripping: `::ffff:7f00:1`. This string does not match 127.0.0.1 in NO_PROXY and is not in LOOPBACK_ADDRESSES, so shouldBypassProxy returns false and the proxy is used.  proxy-from-env (called before shouldBypassProxy) has the same gap - it does not equate ::ffff:7f00:1 with 127.0.0.1 - so neither layer catches the bypass.\n\n### PoC\n```javascript\n\n// NO_PROXY=127.0.0.1,localhost,::1  HTTP_PROXY=http://attacker:8080\nimport shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js';                                                                                                       \n                                                                                                                                                                              \n// All three should return true (bypass proxy). Only the first two do.                                                                                                        \nconsole.log(shouldBypassProxy('http://127.0.0.1/'));          // true  [OK]                                                                                                     \nconsole.log(shouldBypassProxy('http://[::1]/'));               // true  [OK]                                                                                                     \nconsole.log(shouldBypassProxy('http://[::ffff:127.0.0.1]/')); // false <- bypass                                                                                             \nconsole.log(shouldBypassProxy('http://[::ffff:7f00:1]/'));     // false <- bypass\n\n```                                                                                              \n                                                                                                                                                                              \nNode.js routes ::ffff:7f00:1 to 127.0.0.1:                                                                                                                                    \n\n```                                                                                                                                                                              \n// net.connect({ host: '::ffff:7f00:1', port: 80 }) reaches a service                                                                                                       \n// bound to 127.0.0.1:80 — confirmed on Node.js v24, Linux and macOS.                                                                                                         \n```                                                                                                                                                                              \nCloud metadata SSRF: ::ffff:a9fe:a9fe = ::ffff:169.254.169.254. If NO_PROXY=169.254.169.254 is set to block IMDS access, a request to http://[::ffff:a9fe:a9fe]/latest/meta-data/ bypasses it.                                                                                                                      \n                                                                                                                                                                            \n#### Fix                                                                                                                                                                           \n                                                                                                                                                                            \nCanonicalise IPv4-mapped IPv6 in normalizeNoProxyHost before any comparison:                                                                                                  \n \n ```javascript                                                                                                                                                                           \nconst ipv4MappedDotted = /^::ffff:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})$/i;                                                                                                    \nconst ipv4MappedHex    = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;                                                                                                         \n                                                                                                                                                                              \nfunction hexToIPv4(a, b) {                                                                                                                                                    \n  const hi = parseInt(a, 16), lo = parseInt(b, 16);                                                                                                                           \n  return `${hi >> 8}.${hi & 0xff}.${lo >> 8}.${lo & 0xff}`;                                                                                                                   \n}                                                                                                                                                                             \n                                                                                                                                                                              \nconst normalizeNoProxyHost = (hostname) => {                                                                                                                                  \n  if (!hostname) return hostname;                                                                                                                                           \n  if (hostname[0] === '[' && hostname.at(-1) === ']')\n    hostname = hostname.slice(1, -1);                                                                                                                                         \n  hostname = hostname.replace(/\\.+$/, '').toLowerCase();\n                                                                                                                                                                              \n  let m;                                                                                                                                                                    \n  if ((m = hostname.match(ipv4MappedDotted))) return m[1];                                                                                                                    \n  if ((m = hostname.match(ipv4MappedHex)))    return hexToIPv4(m[1], m[2]);                                                                                                   \n  return hostname;                                                                                                                                                            \n};\n\n```\n\n### Impact\nAny application that sets NO_PROXY to exclude internal or metadata endpoints and uses an HTTP/HTTPS proxy can have those exclusions bypassed by a URL using IPv4-mapped IPv6 notation. The attacker must control the request URL. In cloud environments with instance metadata services, this can lead to credential exfiltration.","affected":[{"package":{"name":"axios","ecosystem":"npm","purl":"pkg:npm/axios"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.15.0"},{"fixed":"1.16.0"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-pjwm-pj3p-43mv/GHSA-pjwm-pj3p-43mv.json"}},{"package":{"name":"axios","ecosystem":"npm","purl":"pkg:npm/axios"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.32.0"}]}],"database_specific":{"last_known_affected_version_range":"<= 0.31.1","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-pjwm-pj3p-43mv/GHSA-pjwm-pj3p-43mv.json"}}],"references":[{"type":"WEB","url":"https://github.com/axios/axios/security/advisories/GHSA-pjwm-pj3p-43mv"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44492"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-62718"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36611"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36754"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36820"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36882"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36883"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:40119"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:40138"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:40262"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:41031"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:41055"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:41064"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:41066"},{"type":"WEB","url":"https://access.redhat.com/security/cve/CVE-2026-44492"},{"type":"WEB","url":"https://bugzilla.redhat.com/show_bug.cgi?id=2487938"},{"type":"PACKAGE","url":"https://github.com/axios/axios"},{"type":"WEB","url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-44492.json"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:20889"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:20938"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:26234"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:27044"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:27063"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:28964"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:29082"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:29197"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:30650"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:30651"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33005"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33155"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33160"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33163"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33173"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33183"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:33574"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:34766"},{"type":"WEB","url":"https://access.redhat.com/errata/RHSA-2026:36108"}],"database_specific":{"cwe_ids":["CWE-289","CWE-918"],"github_reviewed":true,"github_reviewed_at":"2026-05-29T15:59:30Z","nvd_published_at":"2026-06-11T17:16:33Z","severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N"}]}