CVE-2026-93572: Io.netty/netty-codec-redis: netty: redisarrayaggregator nested resp headers multiply patched preallocation limits

Published Sep 18, 2026
·
Updated

A flaw was found in Netty's RedisArrayAggregator component. A remote attacker can exploit this vulnerability by sending specially crafted nested Redis (RESP) array headers. This can cause the RedisArrayAggregator to eagerly preallocate a large amount of heap memory, leading to heap memory exhaustion and a Denial of Service (DoS) for applications using RedisDecoder with RedisArrayAggregator on untrusted traffic.

Other sources

RedisArrayAggregator nested RESP headers multiply patched preallocation limits

A public GitHub Security Advisory (GHSA-r4xx-7fpg-j8xg) describes the following issue:

Summary

RedisArrayAggregator recently added maxElements and maxNestedArrayDepth limits to fix public Redis resource-exhaustion advisories. The limits are independent, but the allocator remains eager: every positive nested RESP array header creates new ArrayList<RedisMessage>(length) before any child element exists.

With the default constructor, an attacker can send nested array headers with length 1,000,000 until the default nesting limit of 1024 is reached. This can reserve up to 1,024,000,000 child slots from roughly 12 KB of RESP input. This is backing capacity, not logical list size: ArrayList(int) constructs an empty list with the specified initial capacity.

Technical Details

Current decodeRedisArrayHeader(...) checks the two limits independently:

java if (header.length() > maxElements) { throw new CodecException("this codec doesn't support longer length than " + maxElements); }

if (depths.size() >= maxNestedArrayDepth) { releaseAndClearDepths(); throw new CodecException("max nested array depth exceeded: " + maxNestedArrayDepth); } depths.push(new AggregateState((int) header.length()));

AggregateState immediately allocates a backing list at the attacker-declared length:

java AggregateState(int length) { this.length = length; this.children = new ArrayList<RedisMessage>(length); }

The missing invariant is a total outstanding aggregate budget across the active nested states. The patch bounds one header and one depth counter, but not their product.

PoC

PoV:

RedisArrayAggregatorNestedPreallocationPovTest.java

Run from the Netty checkout:

fish ./mvnw -pl codec-redis -am -Dtest=RedisArrayAggregatorNestedPreallocationPovTest -Dsurefire.failIfNoSpecifiedTests=false -DskipNativeTests -DskipAutobahnTests test

Focused validation on current 4.2.16.Final-SNAPSHOT:

text Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS

The safe test uses maxElements = 4096 and maxNestedArrayDepth = 4 and proves four small array headers create four active aggregate states with a total declared child-slot budget of 16,384 before any child messages are received. It does not intentionally trigger OutOfMemoryError; it safely proves the state and arithmetic, while the source code and ArrayList(int) constructor semantics establish the corresponding backing-capacity allocation. The default configuration scales the same code path to 1024 1,000,000 declared child slots.

Default trigger shape:

text 1000000\r\n1000000\r\n1000000\r\n ... repeat 1024 times ...

Impact

Availability impact via heap memory exhaustion. Any Netty Redis pipeline that uses RedisDecoder with RedisArrayAggregator on untrusted traffic is in scope. The same multiplier applies to custom configurations when maxElements maxNestedArrayDepth exceeds the intended per-connection memory budget.

Suggested Fix

Do not preallocate the list to the declared RESP array length before children exist. Allocate lazily or with a small bounded initial capacity. Also track and enforce a total outstanding aggregate budget across all active nested states.

Affected Package/Versions

io.netty:netty-codec-redis

Confirmed affected:

- current 4.2 branch head 7bae566a93e69409697fe57fa807910ba5c9720e - netty-4.2.15.Final - netty-4.1.135.Final

Recommended affected range for this incomplete-fix variant:

- >= 4.2.15.Final - >= 4.1.135.Final

CWE and CVSS

Primary CWE: CWE-770.

Secondary CWE: CWE-400.

Provisional CVSS v3.1:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 7.5 High

This follows the same High availability-only scoring used for the adjacent public Netty Redis advisories GHSA-5w86-c3rq-vjj7 and GHSA-3244-j874-rhc2.

Duplicate Boundary

This should be treated as an incomplete-fix variant of the public Redis resource-exhaustion fixes, not as a duplicate of the original vulnerable versions:

- GHSA-5w86-c3rq-vjj7 / CVE-2026-50011: unbounded per-header preallocation, fixed in 4.2.15.Final and 4.1.135.Final. - GHSA-3244-j874-rhc2 / CVE-2026-44250: unbounded nested depth, fixed in 4.2.15.Final and 4.1.135.Final.

This finding reproduces on those patched tags and on current 4.2.

NVD and Netty release notes currently map the preallocation advisory to CVE-2026-50011; the GitHub advisory page may lag with "No known CVE". The duplicate argument here is based on affected/patched ranges and root cause, not on that metadata discrepancy.

This is also distinct from pov-test, which covered a retained-buffer cleanup gap after a max-elements exception, not nested preallocation.

Why This Is Not Intended Behavior

The Netty 4.2 API docs document maxElements as the maximum elements to aggregate in a single message and maxNestedArrayDepth as the maximum nested array depth. They do not document a multiplicative eager-allocation budget where each allowed nesting level can reserve the full per-array element cap before any elements exist.

The trigger uses valid RESP array headers and nested aggregate structure. It does not rely on malformed line endings or invalid numeric syntax.

The public preallocation advisory (GHSA-5w86-c3rq-vjj7) identified eager ArrayList allocation from an untrusted RESP length as the vulnerable pattern. The public nested-array advisory (GHSA-3244-j874-rhc2) identified per-nesting aggregate state/list allocation as the vulnerable pattern. This report is the patched-line interaction of those two patterns.

Affected: - maven:io.netty:netty-codec-redis affected >= 4.2.15.Final; fixed unknown - maven:io.netty:netty-codec-redis affected >= 4.1.135.Final; fixed unknown

Fixed versions: see advisory

Advisory: https://github.com/netty/netty/security/advisories/GHSA-r4xx-7fpg-j8xg

— Red Hat

Affected Software

1 affected component
Netty netty-codec-redis>=

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade netty-4.1.135.Final to a version that resolves this vulnerability.

    Fixed in 4.1.135.FinalPatch GHSA-3244-j874-rhc2
  2. Upgrade

    Upgrade netty-4.2.15.Final to a version that resolves this vulnerability.

    Fixed in 4.2.15.FinalPatch GHSA-3244-j874-rhc2
  3. Upgrade

    Upgrade netty-4.1.135.Final to a version that resolves this vulnerability.

    Fixed in 4.1.135.FinalPatch GHSA-5w86-c3rq-vjj7
  4. Upgrade

    Upgrade netty-4.2.15.Final to a version that resolves this vulnerability.

    Fixed in 4.2.15.FinalPatch GHSA-5w86-c3rq-vjj7
  5. Compensating control

    For any Netty Redis pipeline that uses RedisDecoder with RedisArrayAggregator on untrusted traffic, apply compensating DoS protections (e.g., network/request isolation and rate limiting) so attackers cannot send specially crafted nested Redis (RESP) array headers that cause heap memory exhaustion.

Event History

Sep 18, 2026
Data Sourced
via Red Hat·10:29 AM
DescriptionSeverityAffected Software
CVE Published
via MITRE·10:53 AM
Data Sourced
via MITRE·10:53 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·11:17 AM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Is the default configuration affected?

Yes. With the default constructor, nested RESP array headers can be accepted up to the default nesting limit of 1,024, and each positive-length header can eagerly allocate backing capacity.

2

What does an attacker need to send to trigger excessive allocation?

An attacker can send nested RESP array headers with a declared length of 1,000,000. The headers do not need child elements to cause allocation, because each positive nested header creates an ArrayList with the declared initial capacity.

3

How large can the allocation be relative to the request size?

Up to 1,024 nested headers with a length of 1,000,000 can reserve up to 1,024,000,000 child slots. The described input needed to reach this condition is roughly 12 KB of RESP data.

4

Do the existing element-count and nesting-depth limits prevent this behavior?

No. The limits are checked independently, so an array length that is within maxElements can still be used at every permitted nesting level, causing repeated eager preallocation.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203