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 Orbis AppSec
Published May 31, 2026Reviewed June 3, 2026

Answer Summary

CVE-2026-42036 is a medium-severity Denial of Service vulnerability in axios 1.12.2 (Node.js HTTP client) where using `responseType: 'stream'` allows an attacker to exhaust server memory through unbounded stream consumption, classified under CWE-400 (Uncontrolled Resource Consumption). The fix is a dependency upgrade from axios 1.12.2 to 1.15.1, applied in `pnpm-lock.yaml`, which patches the stream-handling logic to enforce proper resource limits and prevent memory exhaustion.

Vulnerability at a Glance

cweCWE-400
fixUpgrade axios from 1.12.2 to 1.15.1 in pnpm-lock.yaml
riskAttacker can exhaust server memory, causing service unavailability
languageJavaScript / Node.js
root causeaxios 1.12.2 does not bound memory usage when consuming HTTP response streams with `responseType: 'stream'`
vulnerabilityDenial of Service via Unbounded Stream Consumption

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.

Frequently Asked Questions

What is unbounded stream consumption in axios?

It is a condition where axios reads an HTTP response stream without enforcing any size or memory limit, allowing a malicious or misbehaving server to send an arbitrarily large response that fills available memory.

How do you prevent unbounded stream consumption DoS in Node.js?

Use up-to-date HTTP client libraries that enforce stream limits, add explicit `maxContentLength` and `maxBodyLength` options, and apply backpressure or destroy streams when thresholds are exceeded.

What CWE is unbounded stream consumption?

CWE-400 — Uncontrolled Resource Consumption ("Resource Exhaustion"), which covers scenarios where a program does not properly limit the amount of resources it allocates in response to external input.

Is setting `maxContentLength` in axios enough to prevent this DoS?

It helps, but it was not sufficient in axios 1.12.2 because the stream path bypassed that check. The 1.15.1 patch closes the gap; combining the upgrade with explicit limits is the most robust approach.

Can static analysis detect unbounded stream consumption?

Yes — tools like Semgrep can flag uses of `responseType: 'stream'` in combination with outdated axios versions, and dependency scanners (Dependabot, Snyk, Orbis AppSec) can detect the vulnerable version directly in lock files.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #11

Related Articles

high

How Regular Expression Denial of Service happens in Node.js picomatch extglob patterns and how to fix it

A Regular Expression Denial of Service (ReDoS) vulnerability in picomatch versions prior to 2.3.2, 3.0.2, and 4.0.4 allowed attackers to craft malicious extglob patterns that triggered catastrophic backtracking in the regex engine, potentially freezing Node.js applications. The fix, tracked as CVE-2026-33671, involved upgrading picomatch to patched versions and pinning the dependency explicitly in `package.json` to ensure the safe version is resolved across the dependency tree.

high

How Denial of Service happens in Node.js devalue and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-22774) was discovered in the `devalue` package used by the exo-dashboard SvelteKit application. Attackers could craft malicious input to trigger excessive resource consumption in the devalue deserialization library, potentially taking down the web service. The fix upgrades `devalue` from version 5.5.0 to 5.6.2 in both `package.json` and `package-lock.json`.

high

How unbounded input size denial-of-service happens in C lexer functions and how to fix it

A high-severity denial-of-service vulnerability was discovered in the PH7 lexer where the `PH7_TokenizePHP()` function accepted arbitrarily large input sizes without validation. An attacker could submit gigabyte-scale PHP code, causing proportional CPU and memory exhaustion. The fix introduces a configurable input size cap enforced before lexer processing begins.

high

How form limit bypass DoS happens in Python Starlette and how to fix it

CVE-2026-54283 is a high-severity denial-of-service vulnerability in Starlette where size limits set on `request.form()` were silently ignored for `application/x-www-form-urlencoded` content, allowing attackers to submit unbounded form data and exhaust server resources. The fix upgrades Starlette from version 1.2.1 to 1.3.1, which correctly enforces form size limits for all content types. Any Python web application using Starlette (including FastAPI-based services) that accepts form submissions

high

How Denial of Service via crafted URI templates happens in Ruby addressable and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-35611) was discovered in the Ruby `addressable` gem versions prior to 2.9.0, which could allow attackers to crash or hang applications by sending specially crafted URI templates. The fix upgrades the dependency from version 2.8.7 to 2.9.0 across the Gemfile, Gemfile.lock, and gemspec in a Fastlane project, eliminating the vulnerable code path entirely.

high

How Denial of Service in SSH Key Exchange happens in Go golang.org/x/crypto and how to fix it

A high-severity denial of service vulnerability (CVE-2025-22869) was discovered in the SSH key exchange implementation of Go's `golang.org/x/crypto` library. The `cpdaemon` service depended on the vulnerable version v0.32.0, which could allow an attacker to exhaust server resources during the SSH handshake phase. The fix upgrades the dependency to v0.35.0, which includes the upstream patch for this vulnerability.