# axios's shouldBypassProxy does not recognize IPv4-mapped IPv6 addresses, allowing NO_PROXY bypass (incomplete fix for CVE-2025-62718)

axios shouldBypassProxy fails to normalize IPv4-mapped IPv6 addresses, so NO_PROXY exclusions for 127.0.0.1 or 169.254.169.254 are bypassed via ::ffff:7f00:1, routing internal requests through an attacker proxy.

- Payout: Research
- Severity: high
- Program: axios
- Found by: HamdaanAliQuatil, jasonsaayman
- Disclosed: 2026-05-29
- CVE: CVE-2026-44492
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-pjwm-pj3p-43mv
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-pjwm-pj3p-43mv
- Tags: area:oss domain:oss impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:nodejs technique:incomplete-fix technique:parser-differential vuln:auth-bypass vuln:ssrf

**Target:** axios shouldBypassProxy / proxy-from-env host matching
**Root cause:** normalizeNoProxyHost strips brackets and trailing dots but does not canonicalize IPv4-mapped IPv6 forms (::ffff:7f00:1, ::ffff:a9fe:a9fe) to their dotted IPv4 equivalents, so they never match NO_PROXY entries or the loopback set.
**Steps:**
1. Set `NO_PROXY=127.0.0.1,localhost,::1` and `HTTP_PROXY=http://attacker:8080`.
2. Call `shouldBypassProxy('http://127.0.0.1/')` -> true; `shouldBypassProxy('http://[::1]/')` -> true.
3. Call `shouldBypassProxy('http://[::ffff:127.0.0.1]/')` or `http://[::ffff:7f00:1]/` -> false, so the proxy is used.
4. Node.js resolves `::ffff:7f00:1` to 127.0.0.1, so the request reaches the internal service through the proxy.
5. For IMDS: with `NO_PROXY=169.254.169.254`, request `http://[::ffff:a9fe:a9fe]/latest/meta-data/` to bypass the exclusion.
**How found:** Reviewing the v1.15.0 fix for CVE-2025-62718 in shouldBypassProxy.js, noticing normalizeNoProxyHost only strips brackets/trailing dots, then testing WHATWG URL canonicalization of `http://[::ffff:127.0.0.1]/` to `[::ffff:7f00:1]` and confirming it fails both the NO_PROXY match and the LOOPBACK_ADDRESSES set; also noted proxy-from-env has the same gap.
**Exploitation:** Attacker controls the request URL; by supplying the IPv4-mapped IPv6 form of an excluded internal/metadata host, the request is sent to the configured HTTP proxy instead of bypassing it, reaching internal services or the cloud IMDS for credential exfiltration.
**Escalation:** Chaining with cloud IMDS access (::ffff:a9fe:a9fe = 169.254.169.254) to exfiltrate instance credentials.
**Insight:** When auditing proxy-bypass/allowlist logic, test alternate textual encodings of the same host (IPv4-mapped IPv6 hex and dotted forms, bracket canonicalization) against every layer in the chain — here both axios and proxy-from-env missed it, so a fix in one layer alone is insufficient.

## Proof of concept (copied exactly from the original report)

**shouldBypassProxy IPv4-mapped IPv6 bypass test**

```
// NO_PROXY=127.0.0.1,localhost,::1  HTTP_PROXY=http://attacker:8080
import shouldBypassProxy from 'axios/lib/helpers/shouldBypassProxy.js';                                                                                                       
                                                                                                                                                                              
// All three should return true (bypass proxy). Only the first two do.                                                                                                        
console.log(shouldBypassProxy('http://127.0.0.1/'));          // true  [OK]                                                                                                     
console.log(shouldBypassProxy('http://[::1]/'));               // true  [OK]                                                                                                     
console.log(shouldBypassProxy('http://[::ffff:127.0.0.1]/')); // false <- bypass                                                                                             
console.log(shouldBypassProxy('http://[::ffff:7f00:1]/'));     // false <- bypass
```

