Fedora Account System
Red Hat Associate
Red Hat Customer
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\n*1000000\r\n*1000000\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