AXIOS · CVE-2026-101898 · Package
FIX → 1.20.0 · >=1.20.0
When a request sets httpVersion to 2, Axios ignores the caller's lookup function and proxy settings and connects directly to the destination. An application that relies on those controls to block internal or metadata addresses can have a user-supplied URL reach them anyway.
first public Sep 16, 2026 · 3 sources
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Only Node.js servers that call axios with httpVersion 2, let users influence request URLs, and rely on axios lookup or proxy settings to block destinations. Browser use and HTTP/1 requests are not affected, and applications that validate destination hosts before calling axios are not affected by the bypass.
Not affected if browser-adapter, http1-only, independent-host-validation
Who cares axios, http2, node, nodejs, ssrf
httpVersion: 2 or httpVersion:2 in calls to axios.lookup or proxy to axios for SSRF or egress control.npm ls axios; affected versions are >= 1.13.0, < 1.20.0.Axios for Node.js does not apply configured DNS lookup or proxy controls when a request uses httpVersion: 2. The HTTP/1 adapter path wraps and forwards config.lookup, builds normal request options, and applies proxy routing through setProxy(). The HTTP/2 path builds a session with http2.connect() using only options.http2Options, which drops the top-level lookup, agent, and proxy state.
Applications are affected when they allow a user to influence request destinations, enable axios HTTP/2, and rely on axios lookup or proxy routing to prevent SSRF or enforce outbound network policy.
In affected server-side deployments, an attacker can cause axios to connect directly to destinations that the configured resolver or proxy would have rejected. Depending on reachable services, this can expose cloud metadata, internal service responses, or allow state-changing requests to internal systems.
This is not an unconditional SSRF in every axios deployment. It requires httpVersion: 2 and an application-level trust boundary where user-influenced URLs are constrained by or proxy policy.
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 1.20.0 · >=1.20.0
1.20.0 or later (fixed in 1.20.0; the product ranges list >=1.20.0 as fixed).lookupAffected:
httpVersion: 2.config.lookup supplied as a DNS policy.config.proxy and environment-derived proxy settings for HTTPS HTTP/2 requests.Not affected:
lookup to the transport and apply proxy handling.In lib/adapters/http.js, the adapter reads lookup, wraps it, stores it on the request options, and applies setProxy() before selecting a transport. For HTTP/2, http2Transport.request() builds an authority from options.protocol, options.hostname, and options.port, then calls:
const { http2Options, headers } = options;
const session = http2Sessions.getSession(authority, http2Options);
lib/helpers/Http2Sessions.js ultimately calls http2.connect(authority, options) with only the http2Options object. The configured DNS lookup and the proxy or tunneling agent installed on the top-level request options are not forwarded into that call.
Local verification on axios 1.18.1 showed lookupCalls: 0 while an HTTP/2 request to a local h2 origin succeeded. A second local HTTPS h2 verification with an explicit rejecting HTTP proxy showed the origin received the request and the proxy observed no traffic.
Local constrained demonstration:
axios.get("http://localhost:<port>/internal", { httpVersion: 2, lookup }) where lookup throws EPOLICY.0.For proxy routing:
httpVersion: 2, http2Options: { rejectUnauthorized: false }, and explicit proxy.Expected safe behavior is that either the lookup policy blocks the request or the proxy observes and rejects the request.
Use the HTTP/1 adapter path for requests that depend on axios lookup or proxy controls. Alternatively, enforce destination allow/deny policy before calling axios, outside the adapter transport path.
I found that Axios does not apply the configured lookup function or proxy when a request uses httpVersion: 2. The HTTP/1 adapter applies both controls, but the HTTP/2 path connects straight to the URL's hostname using http2.connect().
This matters for server applications that accept a user-influenced URL and use a custom DNS lookup or mandatory outbound proxy to prevent SSRF. Switching the Axios instance to HTTP/2 silently removes those controls, allowing the request to reach an address the application intended to block.
I reproduced this on the current npm release, Axios 1.18.1.
The HTTP adapter reads and wraps the caller's lookup function, builds the normal request options, and calls setProxy():
lib/adapters/http.js, around lines 530-578: reads and wraps lookuplib/adapters/http.js, around lines 895-954: adds lookup to options and applies setProxy()For HTTP/2, however, the adapter selects http2Transport. That transport creates an authority from the destination and only passes options.http2Options to the session pool:
const { http2Options, headers } = options;
const session = http2Sessions.getSession(authority, http2Options);
lib/helpers/Http2Sessions.js then calls:
const session = http2.connect(authority, options);
At this point options is only the http2Options object. The top-level lookup, the proxy tunnelling agent created by setProxy(), and the selected httpAgent/httpsAgent are not forwarded. The request therefore uses the system resolver and opens a direct connection to the origin.
The same root cause affects both explicit proxy configuration and environment-derived proxy configuration. I kept the PoC local and used an explicit proxy so the result does not depend on shell environment variables.
I attached axios_http2_transport_controls_poc.mjs. The PoC is entirely local and sets up three pieces:
REACHED_BLOCKED_ORIGIN.502 Bad Gateway.lookup callback that rejects every DNS lookup with an EPOLICY error.The first request is an HTTP/1 control request. It uses the blocking lookup callback and has proxying disabled. Axios calls the callback, receives EPOLICY, and does not reach the origin. This confirms that the callback works and that the hostname is blocked through the normal adapter path.
The second request targets the same URL with httpVersion: 2. It is given both security controls: the same blocking lookup callback and the rejecting proxy. If Axios honors either one, this request cannot reach the origin. It should fail with EPOLICY, or it should reach the proxy and receive its 502 response.
Instead, the request returns HTTP 200 with REACHED_BLOCKED_ORIGIN. The lookup counter does not increase, and the proxy records no request or CONNECT attempt. The origin is the only server that records traffic. This shows that the HTTP/2 path skipped both controls and connected directly using the system resolver.
To reproduce, run the attachment from the root of an Axios checkout:
Run it from the root of an Axios checkout:
git checkout v1.18.1
npm install --ignore-scripts
node /path/to/axios_http2_transport_controls_poc.mjs
Relevant output from my run:
{
"axiosVersion": "1.18.1",
"configuredControls": {
"lookup": "reject every DNS lookup with EPOLICY",
"proxy": "http://127.0.0.1:<port> (reject every request)"
},
"http1Control": "EPOLICY: blocked by application DNS policy",
"http2Result": {
"status": 200,
"data": "REACHED_BLOCKED_ORIGIN"
},
"lookupCalls": 1,
"proxyObservedTraffic": false,
"events": [
{
"server": "origin",
"protocol": "h2",
"path": "/internal"
}
]
}
The important parts of the output are:
http1Control contains EPOLICY, proving the DNS policy blocks the destination under HTTP/1.lookupCalls is still 1 after both requests, proving HTTP/2 never called the configured resolver.proxyObservedTraffic is false, provThis page as .md · .json · CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
GitHub Advisory Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.