Sep 30, 2026·6 min read·245 visits
A quadratic-time algorithmic complexity flaw in Jackson's forward-reference resolution mechanism allows unauthenticated remote attackers to trigger severe CPU thread starvation by submitting specialized JSON payloads containing out-of-order references.
An uncontrolled resource consumption vulnerability in FasterXML jackson-databind allows remote unauthenticated attackers to cause a Denial of Service (DoS) via crafted JSON payloads containing out-of-order forward references in identity-enabled collections or maps.
The security vulnerability CVE-2026-91777 (tracked as GHSA-cxp5-3px4-pw24) is a critical resource consumption defect residing within the FasterXML jackson-databind core deserialization pipeline. It specifically targets endpoints that handle incoming object graphs with cyclical, duplicate, or out-of-order identity-enabled relationships. When an application implements the @JsonIdentityInfo annotation on standard collection or map structures, Jackson generates internal structures to resolve forward-referencing Object IDs during deserialization.
An unauthenticated remote attacker can exploit this mechanism by preparing a specifically crafted JSON body that forces the deserializer's internal accumulator into a worst-case lookup loop. Because the affected parser iterates through arrays in sequential execution order, out-of-order definitions of referenced identifiers cause the processing engine to repeatedly traverse the unresolved queue. This behavior increases processing overhead significantly.
This vulnerability belongs to the algorithmic complexity class (CWE-400), which yields computational denial of service. Traditional defensive parameters, such as restricting nesting depth, fail to prevent this exploitation method because the attack does not rely on deep hierarchy loops or invalid schema configurations. The impact is restricted to the execution context of the JVM, though complete CPU starvation can affect adjacent application threads.
The root cause of the vulnerability lies in the structural choice of a flat list for tracking pending identity references during collection and map parsing. In legacy versions of jackson-databind, the CollectionReferringAccumulator and MapReferringAccumulator components utilize a standard java.util.ArrayList structure, named _accumulator, to cache pending CollectionReferring objects.
When Jackson parses an array with elements that refer to Object IDs before their explicit definition, it constructs placeholder CollectionReferring nodes and appends them to this array list. When the actual definition of an Object ID is encountered, the deserializer calls resolveForwardReference. This trigger prompts a linear iteration from the beginning of the _accumulator array list via an Iterator structure to locate the target ID node.
If the payload organizes these object definitions in reverse order relative to their initial referencing declarations, the iterator executes a worst-case linear scan of the outstanding list size for each resolution step. Compounding this, the accumulator executes a manual buffer-merging loop using previous.addAll(ref.next) to preserve chronological order for elements parsed after the unresolved ID. The cumulative cost of both operations scales exponentially to O(N^2) time complexity for N forward references.
To understand the technical issue, analyze the legacy implementation of resolveForwardReference within CollectionDeserializer.java. In this code path, the resolver performs a linear traversal on every invocation to find the matching unresolved ID:
// LEGACY VULNERABLE CODE
public void resolveForwardReference(Object id, Object value) throws IOException {
Iterator<CollectionReferring> iterator = _accumulator.iterator();
Collection<Object> previous = _result;
while (iterator.hasNext()) {
CollectionReferring ref = iterator.next();
if (ref.hasId(id)) {
iterator.remove();
previous.add(value);
previous.addAll(ref.next); // Merge buffers (quadratic step)
return;
}
previous = ref.next;
}
throw new IllegalArgumentException("Unresolved forward reference id not seen.");
}The official fix, introduced in commit 37ad9b81712cbb9fb62c2d2c1813593252a24b67, replaces the flat accumulator list with a composite data structure. It utilizes a HashMap named _unresolvedById that maps keys directly to a Deque of CollectionReferring references, yielding O(1) lookup performance. Additionally, it preserves ordering through a flat linear queue structure named _pending coupled with an index pointer, _pendingStart.
// PATCHED SECURE CODE
public void resolveForwardReference(Object id, Object value) throws IOException {
Deque<CollectionReferring> refs = _unresolvedById.get(id);
if (refs == null) {
throw new IllegalArgumentException("Unknown forward reference id.");
}
CollectionReferring ref = refs.removeFirst();
if (refs.isEmpty()) {
_unresolvedById.remove(id);
}
ref.resolve(value);
// Linear sliding-window evaluation
final int end = _pending.size();
int i = _pendingStart;
for (; i < end; ++i) {
Object pending = _pending.get(i);
if (pending instanceof CollectionReferring) {
CollectionReferring pendingRef = (CollectionReferring) pending;
if (!pendingRef.isResolved()) {
break; // Halted by the next unresolved reference
}
pending = pendingRef.resolvedValue();
}
_result.add(pending);
_pending.set(i, null);
}
_pendingStart = (i == end) ? 0 : i;
if (i == end) _pending.clear();
}By using this queue sliding window, every parsed and pending object is evaluated and shifted to the destination _result collection exactly once. This shifts the runtime profile from a quadratic O(N^2) scale down to a stable linear O(N) scale.
Exploitation of CVE-2026-91777 is highly reliable and requires no specialized prerequisites other than a network path to a vulnerable Jackson deserialization endpoint. The target class must utilize the @JsonIdentityInfo annotation to track references. The attacker constructs a payload consisting of two distinct sections: the list of forward references and the reverse-order declaration definitions.
For a Collection-based exploit, the input array starts with a sequence of string keys matching the generated Object IDs. The parser is forced to cache each reference inside the accumulator as it reads the array from left to right. Immediately following the keys, the attacker provides the full object definitions in reverse numeric order:
[
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
{"id": "19", "name": "node19"},
{"id": "18", "name": "node18"},
{"id": "17", "name": "node17"},
{"id": "0", "name": "node0"}
]Because each definition from 19 to 0 triggers a linear scan from the beginning of the legacy list, the JVM executes thousands of comparisons for small datasets. For larger payloads of several thousand elements, the calculation yields millions of comparison loops. This process consumes the entire CPU execution slice of the handling thread, triggering rapid denial of service.
The vulnerability carries a CVSS Base Score of 7.5, indicating a high-impact availability threat. Successful exploitation leads directly to CPU resource exhaustion on the target application node, blocking all standard requests and potentially causing orchestrators to restart the container under load-balancer stress.
Remediation consists of upgrading to the patched Jackson-databind versions. However, the fix itself introduces minor structural constraints. Since unresolved references block the sliding window, a single un-resolved reference at the beginning of an array will hold all subsequent items in heap memory within _pending. This behavior poses a minor risk of memory exhaustion if request payloads are sufficiently large.
Below is a conceptual logical comparison of the legacy vs. patched behavior inside Jackson:
While the patch is functionally complete and eliminates the quadratic lookup vector, administrators must configure maximum packet-size limits. This prevents attackers from bypassing the CPU check by abusing the residual memory retention mechanism in the sliding window buffer.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
jackson-databind FasterXML | >= 2.5.0, < 2.18.11 | 2.18.11 |
jackson-databind FasterXML | >= 2.19.0, < 2.21.7 | 2.21.7 |
jackson-databind FasterXML | >= 2.22.0, < 2.22.3 | 2.22.3 |
jackson-databind FasterXML | >= 3.0.0, < 3.1.7 | 3.1.7 |
jackson-databind FasterXML | >= 3.2.0, < 3.2.3 | 3.2.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Network |
| CVSS Score | 7.5 (High) |
| EPSS Score | 0.0045 |
| Impact | Denial of Service (CPU Exhaustion) |
| Exploit Status | Proof of Concept available |
| KEV Status | Not currently listed |
The product does not properly control the allocation and maintenance of a limited resource, enabling an actor to cause resource exhaustion.
CVE-2026-128087 (GHSA-9264-jvgf-6w2f) is an incorrect behavior order (CWE-696) and improper authorization (CWE-863) vulnerability in the russh Rust SSH library, affecting versions 0.55.0 through 0.65.0. During the initial SSH key exchange (KEX) handshake, the client state machine invokes the client::Handler::kex_done() callback—providing the negotiated raw shared secret bytes—prior to validating the remote server's host key or certificate via check_server_key(). Consequently, an untrusted or rogue SSH server can complete cryptographic key agreement and force a connecting client to execute side-effecting application logic inside kex_done() before the server's identity is checked and rejected.
CVE-2026-128082 (GHSA-6vhm-j9h7-f9gh) is an uncontrolled recursion vulnerability (CWE-674) in AutoMapper, a convention-based object-object mapper for .NET. When mapping nested or self-referential types into destination models that rely on parameterized constructors, C# positional records, or recursive ConstructUsing expressions, AutoMapper evaluates child constructor arguments prior to incrementing the parent's recursion depth counter. This ordering flaw bypasses both explicit MaxDepth limits and the default depth limit of 64. An unauthenticated remote attacker can supply deeply nested input payloads to affected endpoints, exhausting the thread call stack and triggering an uncatchable System.StackOverflowException that terminates the hosting .NET process.
An information exposure vulnerability in the @opentelemetry/instrumentation-http package for OpenTelemetry JavaScript versions 0.204.0 prior to 0.222.0 causes incoming HTTP server spans to record raw, unredacted query string parameters under the url.query attribute. While outgoing client spans applied built-in and user-configured query parameter redaction, incoming server spans bypassed this sanitization completely, resulting in the transmission of sensitive credentials such as pre-signed cloud URLs and API tokens to external observability backends.
CVE-2026-128089 is an uncontrolled resource consumption vulnerability in the dnspython toolkit for Python, affecting all versions prior to 2.9.2. When parsing Well-Known Service (WKS) records from text via dns.rdtypes.IN.WKS.WKS.from_text(), the parser fails to validate that numeric service port identifiers fall within the RFC 1035 valid range of 0 through 65535. An attacker capable of supplying untrusted zone files or RDATA text strings containing an arbitrarily large service port integer can force the parser to allocate an unbounded bitmap array using an inefficient linear append loop, resulting in severe CPU exhaustion, application hangs, or Out-Of-Memory (OOM) process termination.
CVE-2026-126347 (GHSA-5cjw-f85j-cv6r) is an open redirect vulnerability (CWE-601) in Tornado, an asynchronous Python networking library and web framework. The flaw resides in tornado.web.RedirectHandler when dynamic URL redirection templates incorporate unvalidated user input. Due to a parser differential between RFC 3986 (used by Python's urllib.parse.urlsplit) and the WHATWG URL Standard (used by modern web browsers), inputs containing three or more leading slashes bypass Tornado 6.6.0's validation logic, allowing unauthenticated attackers to redirect users to arbitrary external domains.
A Denial of Service (DoS) vulnerability exists in @sveltejs/adapter-node versions 5.5.7 and 6.0.0-next.0 through 6.0.0. When a SvelteKit server route returns a direct response from a fetch() call with a Content-Type of text/event-stream, the Node.js adapter attempts to mutate the response headers to disable proxy buffering. Because headers returned directly by the WHATWG Fetch API carry an immutable guard, this mutation throws an unhandled TypeError, terminating the underlying Node.js process and denying service to all active and subsequent clients.