Back to Blog
medium SEVERITY6 min read

How Remote Memory Exhaustion happens in Rust QUIC implementations and how to fix it

A high-severity vulnerability (GHSA-4w2j-m93h-cj5j) in quinn-proto 0.11.14 allowed attackers to exhaust server memory through unbounded out-of-order QUIC stream reassembly. The fix upgrades to quinn-proto 0.11.15, which implements proper bounds checking to prevent malicious clients from forcing servers to buffer unlimited out-of-order stream data.

O
By Orbis AppSec
Published August 9, 2026Reviewed August 9, 2026

Answer Summary

GHSA-4w2j-m93h-cj5j is a remote memory exhaustion vulnerability in quinn-proto 0.11.14, a Rust implementation of the QUIC transport protocol (CWE-400: Uncontrolled Resource Consumption). Attackers could send out-of-order QUIC stream frames that forced the server to buffer unlimited data in memory. The fix upgrades to quinn-proto 0.11.15, which implements bounded reassembly buffers to limit memory consumption from untrusted stream data.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade to quinn-proto 0.11.15 with bounded reassembly buffers
riskRemote attackers can exhaust server memory through malicious QUIC stream frames
languageRust
root causequinn-proto 0.11.14 lacks bounds on out-of-order stream data buffering
vulnerabilityRemote Memory Exhaustion via Unbounded Stream Reassembly

Introduction

In a production Rust application using QUIC networking, Trivy scanner identified a high-severity vulnerability (GHSA-4w2j-m93h-cj5j) in the quinn-proto dependency version 0.11.14. This vulnerability in the QUIC protocol implementation's stream reassembly logic could allow remote attackers to exhaust server memory without authentication. The flaw lies in how quinn-proto handles out-of-order stream frames—a fundamental feature of QUIC that enables efficient multiplexed data transfer but, when unbounded, becomes an attack vector for resource exhaustion.

The vulnerability was discovered in Cargo.lock, where the application depended on quinn-proto version 0.11.14. This version lacked proper bounds checking on the amount of out-of-order stream data buffered during reassembly, allowing malicious clients to force the server to allocate unlimited memory.

The Vulnerability Explained

QUIC is a modern transport protocol that allows multiplexed streams over a single connection. Unlike TCP, QUIC streams can arrive out of order, and the implementation must buffer these frames until earlier frames arrive to reassemble the stream in the correct sequence.

The vulnerable pattern in quinn-proto 0.11.14:

[[package]]
name = "quinn-proto"
version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"

In version 0.11.14, the stream reassembly logic did not enforce maximum limits on how much out-of-order data could be buffered per stream or per connection. When a QUIC client sends stream frames with large gaps in sequence numbers, the server must buffer all the later frames until the missing earlier frames arrive.

Attack scenario specific to this vulnerability:

  1. An attacker establishes a QUIC connection to a server using quinn-proto 0.11.14
  2. The attacker opens multiple streams (QUIC allows up to 2^60 concurrent streams)
  3. For each stream, the attacker sends frame 1000, then frame 2000, then frame 3000, etc., deliberately skipping frames 0-999, 1001-1999, 2001-2999
  4. The server buffers all these out-of-order frames, waiting for the missing frames that will never arrive
  5. The attacker repeats this across thousands of streams, each forcing the server to buffer megabytes of out-of-order data
  6. Server memory is exhausted, causing denial of service or crashes

Real-world impact:

For applications using quinn-proto 0.11.14 (like the computer-use-linux remote desktop application in this repository), this vulnerability could allow:

  • Unauthenticated DoS: Any client that can establish a QUIC connection can exhaust server memory
  • Service disruption: Memory exhaustion crashes the server or triggers OOM killer
  • Resource monopolization: A single malicious connection can consume resources intended for thousands of legitimate users
  • No large payload required: The attack uses protocol-level manipulation, not bandwidth flooding

The severity is rated HIGH because exploitation requires no authentication, minimal bandwidth, and can completely disable the service.

The Fix

The fix upgrades quinn-proto from version 0.11.14 to 0.11.15, which implements bounded reassembly buffers:

Before (vulnerable version):

[[package]]
name = "quinn-proto"
version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"

After (patched version):

[[package]]
name = "quinn-proto"
version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"

How this specific change solves the problem:

Quinn-proto 0.11.15 introduces bounded buffers for stream reassembly. The patched version:

  1. Enforces per-stream limits: Each stream can only buffer a maximum amount of out-of-order data before rejecting additional frames
  2. Implements per-connection limits: The total buffered out-of-order data across all streams in a connection is capped
  3. Returns flow control errors: When limits are exceeded, the server sends STOP_SENDING frames to the client instead of buffering unlimited data
  4. Preserves legitimate use cases: Normal out-of-order delivery (which happens naturally in networks) still works within the bounds

The security improvement is concrete: an attacker who previously could force the server to buffer gigabytes of data across thousands of streams is now limited to a few megabytes total. When the attacker exceeds these limits, the server actively terminates the offending streams rather than consuming more memory.

Changes made:

The fix modified two files:
- Cargo.toml: Updated the quinn-proto dependency constraint to require version 0.11.15 or later
- Cargo.lock: Locked the specific version to 0.11.15 with the patched checksum

This ensures that both direct and transitive dependencies use the secure version, preventing accidental downgrades during dependency resolution.

Prevention & Best Practices

To avoid similar memory exhaustion vulnerabilities in QUIC and other streaming protocol implementations:

1. Always Bound Buffers for Untrusted Input

Any buffer that holds data from untrusted sources (network clients, file uploads, etc.) must have explicit maximum size limits. In streaming protocols, this includes:
- Per-stream reassembly buffers
- Per-connection aggregate buffers
- Fragment reassembly queues

2. Implement Flow Control at Multiple Layers

QUIC provides flow control mechanisms—use them:

// Example of proper flow control configuration
let mut config = quinn::ServerConfig::default();
config.transport
    .stream_receive_window(1024 * 1024)?  // 1MB per stream
    .receive_window(8 * 1024 * 1024)?;    // 8MB per connection

3. Monitor Dependency Vulnerabilities

Use automated tools to track security advisories:
- Trivy: Scans Cargo.lock for known vulnerabilities
- cargo-audit: Checks dependencies against RustSec advisory database
- Dependabot: Automatically opens PRs for vulnerable dependencies
- Orbis AppSec: Detects and fixes vulnerabilities with context-aware patches

4. Test Resource Limits

Include DoS testing in your security test suite:

#[test]
fn test_out_of_order_memory_limit() {
    let server = start_test_server();
    let client = malicious_client();

    // Send many out-of-order frames
    for stream_id in 0..1000 {
        client.send_frame(stream_id, offset: 1000000, data: vec![0; 1000]);
    }

    // Server should not consume unbounded memory
    assert!(server.memory_usage() < MAX_EXPECTED_MEMORY);
}

5. Apply Defense in Depth

Layer multiple protections:
- Network layer: Rate limit connections per IP
- Protocol layer: Enforce QUIC flow control limits (as in the fix)
- Application layer: Implement timeouts for incomplete streams
- Infrastructure layer: Use memory cgroups to limit container memory

6. Keep Dependencies Updated

Security patches often fix subtle protocol-level issues that are hard to detect in application code. Establish a process for:
- Weekly dependency vulnerability scans
- Monthly dependency updates for non-breaking changes
- Immediate updates for high-severity vulnerabilities like GHSA-4w2j-m93h-cj5j

Security Standards References

  • CWE-400: Uncontrolled Resource Consumption ('Resource Exhaustion')
  • OWASP: Denial of Service prevention cheat sheet
  • RFC 9000: QUIC specification, Section 4.1 on flow control

Key Takeaways

  • Quinn-proto 0.11.14's unbounded stream reassembly allowed attackers to exhaust server memory by sending out-of-order QUIC frames across multiple streams
  • Version 0.11.15 fixes this by enforcing per-stream and per-connection limits on buffered out-of-order data
  • Dependency vulnerabilities are infrastructure risks: Even if your application code is secure, vulnerable dependencies can expose critical attack vectors
  • Protocol-level DoS attacks are subtle: This vulnerability didn't require large payloads or bandwidth—just clever manipulation of QUIC's out-of-order delivery mechanism
  • Automated scanning is essential: Tools like Trivy and Orbis AppSec can detect dependency vulnerabilities that manual code review would miss

How Orbis AppSec Detected This

  • Source: Untrusted QUIC stream frames from remote clients
  • Sink: Unbounded memory allocation in quinn-proto 0.11.14's stream reassembly buffers
  • Missing control: No maximum limit on buffered out-of-order data per stream or per connection
  • CWE: CWE-400 (Uncontrolled Resource Consumption)
  • Fix: Upgraded quinn-proto to 0.11.15, which implements bounded reassembly buffers with configurable limits

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

GHSA-4w2j-m93h-cj5j demonstrates how protocol-level vulnerabilities in dependencies can create serious security risks even when application code is well-written. The unbounded stream reassembly in quinn-proto 0.11.14 allowed remote memory exhaustion attacks that could completely disable services. Upgrading to version 0.11.15 fixes this by implementing proper bounds checking, but the broader lesson is the importance of continuous dependency monitoring and automated security scanning. As QUIC adoption grows, understanding these protocol-level attack vectors becomes essential for building resilient network services.

References

Frequently Asked Questions

What is remote memory exhaustion in QUIC implementations?

Remote memory exhaustion occurs when a QUIC server unboundedly buffers out-of-order stream data sent by malicious clients, allowing attackers to consume all available memory without authentication or sending large amounts of data themselves.

How do you prevent memory exhaustion in Rust QUIC servers?

Implement bounded buffers for stream reassembly, set maximum limits on out-of-order data per stream and per connection, and upgrade to patched versions of QUIC libraries like quinn-proto 0.11.15 that enforce these limits automatically.

What CWE is unbounded stream reassembly?

CWE-400: Uncontrolled Resource Consumption ('Resource Exhaustion'). This occurs when an application doesn't properly limit the resources consumed when processing untrusted input, allowing attackers to exhaust memory, CPU, or other system resources.

Is rate limiting enough to prevent QUIC memory exhaustion?

No. While rate limiting helps, it doesn't prevent the core issue: a single connection can send many small out-of-order frames that each consume memory. The fix requires bounded buffers per stream and per connection, not just limiting connection rates.

Can static analysis detect unbounded stream reassembly?

Partially. Static analysis can identify missing bounds checks on buffer operations, but detecting the specific QUIC protocol logic that allows memory exhaustion requires specialized security scanners that understand protocol-level vulnerabilities and dependency vulnerabilities like Trivy or Orbis AppSec.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1272

Related Articles

medium

How Uninitialized Memory Vulnerabilities Happen in Rust and How to Fix Them

The fuser crate (versions prior to 0.16.0) contained a critical vulnerability that allowed uninitialized memory to be read and leaked through FUSE operations. This security issue was fixed by upgrading fuser from 0.15.1 to 0.16.0, which tightens memory handling and prevents potential information disclosure in applications that interact with the filesystem via FUSE.

critical

How Denial of Service Vulnerabilities Happen in QUIC Protocol Implementations and How to Fix Them

The quinn-proto library, a critical component for QUIC protocol implementations, contained a denial of service vulnerability (CVE-2026-31812) that could be triggered by specially crafted QUIC Initial packets. A security update from version 0.11.13 to 0.11.14 tightens the handling of untrusted network input, preventing attackers from exhausting server resources through malformed packets.

high

How Remote Memory Exhaustion Happens in Rust QUIC Implementations and How to Fix It

A high-severity vulnerability in `quinn-proto` allowed remote attackers to exhaust server memory by sending carefully crafted out-of-order QUIC stream data, triggering unbounded buffer growth during reassembly. The fix upgrades `rustls-webpki` from `0.103.10` to `0.103.13` in `Cargo.lock`, closing a related denial-of-service primitive that could be chained with the stream reassembly weakness. Together, these changes harden the QUIC stack against memory exhaustion attacks that require no authenti

high

How cryptographic binding vulnerabilities happen in Rust OpenSSL and how to fix it

CVE-2026-41676 is a high-severity vulnerability in the rust-openssl crate that could allow attackers to exploit cryptographic operations. The fix involves upgrading from version 0.10.63 to 0.10.81, removing unsafe dependency chains, and ensuring proper OpenSSL binding integrity. This vulnerability demonstrates why keeping cryptographic libraries current is critical for production Rust applications.

high

How a named pipe I/O race condition happens in Rust mio and how to fix it

CVE-2024-27308 is a high-severity vulnerability in the Rust `mio` crate (versions prior to 0.8.11) that exposes a race condition in named pipe I/O event handling on Windows. The fix upgrades `mio` from version 0.8.10 to 0.8.11, closing the window for potential exploitation in applications like `rpm-ostree` that depend on async I/O. Because `mio` sits at the foundation of the Tokio async runtime, this flaw has wide blast radius across the Rust ecosystem.

medium

How GitHub Actions Mutable Action Tags Enable Supply-Chain Attacks and How to Fix Them

A GitHub Actions workflow was using `actions/checkout@v1`, a mutable tag reference that could be silently repointed by the action owner to inject malicious code. This supply-chain vulnerability was fixed by pinning the action to a specific commit SHA (`11bd71901bbe5b1630ceea73d27597364c9af683`), ensuring the workflow always executes verified, immutable code.