Back to Blog
medium SEVERITY6 min read

Axios DoS via Unbounded Stream Consumption Fixed in pnpm-lock.yaml

A medium-severity Denial of Service vulnerability (CVE-2026-42036) was discovered in axios 1.12.2, where using `responseType: 'stream'` could allow an attacker to exhaust server memory through unbounded stream consumption. The fix upgrades axios from version 1.12.2 to 1.15.1 in the project's `pnpm-lock.yaml`, closing the attack surface before it could be exploited in production.

O
By orbisai0security
May 31, 2026

Axios DoS via Unbounded Stream Consumption: How responseType: 'stream' Became an Attack Vector

Introduction

The pnpm-lock.yaml file in this project pins axios at version 1.12.2 — a version that contains a quietly dangerous flaw. When HTTP responses are consumed using responseType: 'stream', axios fails to enforce any upper bound on how much data it will accept from the remote server. The result? A malicious or misconfigured server can push an endless stream of bytes into your Node.js process, consuming memory until the application crashes or becomes unresponsive.

This is CVE-2026-42036, a medium-severity Denial of Service vulnerability that affects any application using axios with streaming responses. If your backend proxies external content, fetches large files, or pipes API responses — this vulnerability deserves your full attention.


The Vulnerability Explained

What Goes Wrong with responseType: 'stream'?

When you configure an axios request like this:

const response = await axios.get('https://external-api.example.com/data', {
  responseType: 'stream'
});

response.data.pipe(someWritableStream);

You're telling axios: "Don't buffer this response — give me the raw Node.js readable stream." This is a perfectly legitimate pattern for handling large files, real-time data feeds, or proxying responses.

The problem in axios 1.12.2 is that the stream handed back to the caller has no built-in consumption limit. Axios does not apply a maxContentLength guard when the response type is stream, nor does it enforce a timeout on how long an idle or slow stream can hold a connection open.

The Attack Scenario

Consider a Node.js service that proxies responses from a third-party API:

// A typical proxy handler — looks safe, but isn't with axios 1.12.2
app.get('/proxy', async (req, res) => {
  const upstream = await axios.get(req.query.url, {
    responseType: 'stream'
  });
  upstream.data.pipe(res);
});

An attacker — or a compromised upstream server — can respond to this request with an HTTP response that never ends, or that sends data at a trickle for hours. Because axios 1.12.2 does not cap stream consumption:

  1. The Node.js event loop remains tied to this connection.
  2. Memory allocated for buffering grows without bound.
  3. With enough concurrent requests of this type, the process exhausts available heap memory.
  4. The application crashes or becomes too slow to serve legitimate users.

This is a classic slow-read / infinite-stream DoS attack. The attacker doesn't need to send data fast — they just need to keep the connection alive and growing.

Why maxContentLength Wasn't Enough

Axios does expose a maxContentLength option, but in 1.12.2, this guard was not reliably enforced for streaming responses. The check was designed for buffered responses where axios accumulates the full body before resolving the promise. When responseType: 'stream' bypasses that accumulation step, the guard is effectively skipped — leaving the stream unbounded.


The Fix

What Changed: axios 1.12.21.15.1

The remediation is a direct dependency upgrade captured in pnpm-lock.yaml:

# Before (vulnerable)
axios:
  version: 1.12.2

# After (fixed)
axios:
  version: 1.15.1

Axios 1.15.1 addresses the unbounded stream consumption issue by ensuring that stream responses are subject to the same content-length and timeout enforcement as buffered responses. Specifically, the fix in the axios codebase:

  • Enforces maxContentLength for stream responses — the readable stream now tracks bytes transferred and destroys the stream if the configured limit is exceeded.
  • Applies response timeout to streaming connections — a connection that stalls mid-stream will now be terminated after the configured timeout window, rather than being held open indefinitely.
  • Emits a proper error event on the stream when limits are exceeded, allowing callers to handle the rejection gracefully rather than experiencing a silent memory leak.

Before vs. After Behavior

Before (axios 1.12.2):

// maxContentLength is set, but ignored for streams
const response = await axios.get(url, {
  responseType: 'stream',
  maxContentLength: 10 * 1024 * 1024 // 10MB — NOT enforced in 1.12.2
});
// Stream can grow past 10MB with no error thrown
response.data.pipe(destination);

After (axios 1.15.1):

// maxContentLength is now enforced even for streams
const response = await axios.get(url, {
  responseType: 'stream',
  maxContentLength: 10 * 1024 * 1024 // 10MB — ENFORCED in 1.15.1
});
// Stream is destroyed and an error is emitted if 10MB is exceeded
response.data.on('error', (err) => {
  console.error('Stream limit exceeded:', err.message);
});
response.data.pipe(destination);

This is a non-breaking change for well-behaved applications — if you weren't hitting content limits before, you won't notice a difference. But it closes the door on the unbounded consumption attack.


Prevention & Best Practices

1. Always Configure maxContentLength and timeout for Stream Requests

Even with the fix in place, defense-in-depth means you should explicitly configure limits:

const response = await axios.get(url, {
  responseType: 'stream',
  maxContentLength: 50 * 1024 * 1024, // 50MB hard limit
  timeout: 30000,                       // 30 second connection timeout
  maxBodyLength: 50 * 1024 * 1024
});

2. Never Proxy Arbitrary User-Supplied URLs Without Validation

The attack scenario above becomes dramatically more dangerous when users control the upstream URL. Validate and allowlist upstream hosts before making proxied requests:

const ALLOWED_HOSTS = new Set(['api.trusted.com', 'cdn.trusted.com']);

function isSafeUrl(rawUrl) {
  try {
    const parsed = new URL(rawUrl);
    return ALLOWED_HOSTS.has(parsed.hostname);
  } catch {
    return false;
  }
}

3. Audit pnpm-lock.yaml (and package-lock.json) Regularly

Lock files pin transitive dependencies that your direct package.json entries may not explicitly reference. A vulnerability in a nested dependency can be invisible until you scan the lock file directly.

Tools to integrate into your CI pipeline:
- pnpm audit — scans your pnpm lock file against the npm advisory database
- Orbis AppSec — automated PR-based fixes like the one that generated this post
- Dependabot / Renovate — automated dependency update PRs
- Snyk — deep dependency graph scanning with fix suggestions

4. Apply Backpressure When Piping Streams

Even with axios fixed, always handle backpressure and error events when piping:

const source = response.data;
const dest = fs.createWriteStream('/tmp/output');

source.on('error', (err) => {
  dest.destroy();
  // handle error
});

dest.on('error', (err) => {
  source.destroy();
  // handle error
});

source.pipe(dest);

5. Reference Standards

  • CWE-400: Uncontrolled Resource Consumption — the root CWE for this vulnerability class
  • OWASP A05:2021 – Security Misconfiguration (includes missing resource limits)
  • OWASP A06:2021 – Vulnerable and Outdated Components (the direct category for this fix)

Key Takeaways

  • responseType: 'stream' bypassed axios's maxContentLength guard in versions before 1.15.1 — a guard that developers reasonably expected to protect them.
  • The pnpm-lock.yaml file is a security artifact, not just a reproducibility tool. Pinning axios at 1.12.2 locked in this vulnerability until an explicit upgrade was applied.
  • Upgrading from 1.12.2 to 1.15.1 is the minimum safe version for any project that uses axios with streaming responses — partial version bumps within 1.12.x do not contain this fix.
  • Slow-stream DoS attacks are low-bandwidth and hard to detect with traditional rate limiting — they require application-level resource caps to mitigate effectively.
  • Explicit timeout and content-length configuration in axios is now a best practice, not optional hardening, especially for any service that fetches data from external or user-controlled URLs.

Conclusion

CVE-2026-42036 is a reminder that even well-trusted libraries like axios can harbor subtle resource management flaws. The combination of a widely-used responseType: 'stream' pattern and a missing enforcement boundary in versions up to 1.12.2 created a genuine Denial of Service risk for any Node.js application that fetches external data. The upgrade to 1.15.1 — a single line change in pnpm-lock.yaml — closes that gap by bringing stream responses under the same resource controls that buffered responses have always had.

Keep your lock files audited, configure explicit resource limits on all HTTP clients, and treat dependency upgrades as security patches — not just feature updates.


This vulnerability was automatically detected and remediated by Orbis AppSec. Automated security fixes help teams stay ahead of dependency vulnerabilities without waiting for manual review cycles.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #11

Related Articles

high

CVE-2025-14874: Nodemailer DoS via Crafted Email Address Headers

A high-severity denial-of-service vulnerability (CVE-2025-14874) was discovered in Nodemailer 6.10.1, where an attacker could craft a malicious email address header to crash or hang the mail-sending process. The fix involved a direct major version upgrade from 6.10.1 to 7.0.7 in the project's `package-lock.json`, closing the attack vector entirely. Applications relying on Nodemailer for transactional or user-triggered email are at risk until this upgrade is applied.

high

CVE-2025-14874: Nodemailer DoS via Crafted Email Address Header

A high-severity denial-of-service vulnerability (CVE-2025-14874) was discovered in Nodemailer versions prior to 7.0.0, where a specially crafted email address header could cause the application to hang or crash. The fix involved upgrading Nodemailer from version 6.10.1 to 7.0.7 in the `Dise-ador-experto-master` project's `package-lock.json`. This major version upgrade closes the attack surface and ensures email processing remains stable under adversarial input.

high

CVE-2025-14874: Nodemailer DoS via Crafted Email Address Header Parsing

A high-severity Denial of Service vulnerability (CVE-2025-14874) was discovered in Nodemailer versions prior to 7.0.11, where a specially crafted email address header could cause the application to hang or crash. The fix involved a major version bump from Nodemailer 6.10.1 to 7.0.11 in the `Dise-ador-experto-master/package-lock.json` dependency file. Left unpatched, this vulnerability could allow any unauthenticated attacker to disrupt email-sending functionality and potentially take down the en

high

CVE-2025-14874: Nodemailer DoS via Crafted Email Address Header

CVE-2025-14874 is a high-severity Denial of Service vulnerability in Nodemailer that allows an attacker to crash an application by sending a specially crafted email address header. The vulnerability existed in Nodemailer versions prior to 7.0.11 and was present in the `Dise-ador-experto-master` project's `package-lock.json` dependency on version 6.10.1. Upgrading to Nodemailer 7.0.11 resolves the issue by fixing the underlying header parsing logic that could be exploited to cause unbounded resou

high

CVE-2026-40073: How a BODY_SIZE_LIMIT Bypass in @sveltejs/adapter-node Put Your App at Risk

CVE-2026-40073 is a high-severity vulnerability in `@sveltejs/adapter-node` that allows attackers to bypass the `BODY_SIZE_LIMIT` configuration, potentially enabling denial-of-service attacks and resource exhaustion against SvelteKit applications. The vulnerability was silently present in versions prior to `@sveltejs/kit` 2.57.1, and has now been patched by upgrading the dependency across all affected project examples. If your application relies on body size limits to protect against oversized p

medium

Mass Assignment Vulnerability: Why Your Rails Models Need attr_accessible

A medium-severity mass assignment vulnerability was identified in a Ruby on Rails model that lacked proper attribute whitelisting via `attr_accessible` or strong parameters. Without this protection, attackers can manipulate any model attribute through crafted HTTP requests, potentially escalating privileges or corrupting data. The fix enforces explicit attribute allowlisting, closing the door on unauthorized mass assignment exploitation.