Sep 30, 2026·6 min read·1 visit
An unauthenticated remote attacker can crash Java applications using Jackson-databind by transmitting JSON payloads with high-cardinality, unrecognized polymorphic type IDs, causing unbounded memory retention and JVM heap exhaustion.
CVE-2026-91776 is a high-severity Denial of Service (DoS) vulnerability in the FasterXML jackson-databind library. The vulnerability is caused by uncontrolled resource consumption (CWE-400) where raw, unrecognized polymorphic type IDs are cached indefinitely without boundaries inside TypeDeserializerBase. When name-based polymorphic deserialization is configured with a fallback mechanism (such as a default implementation or custom problem handlers), remote attackers can send crafted payloads containing unique unknown type IDs, causing heap exhaustion, Garbage Collection (GC) overhead limit exhaustion, and an Out-of-Memory (OOM) crash.
The FasterXML jackson-databind library provides powerful polymorphic type resolution mechanisms, allowing developers to dynamically map input fields to Java objects based on a type identifier. A typical implementation involves decorating target classes with @JsonTypeInfo(use = Id.NAME), instructing the deserializer to interpret a specific JSON property (such as type) as the class indicator. To optimize performance and bypass expensive reflection-based class lookups on every request, jackson-databind maintains an internal cache of resolved type deserializers within the TypeDeserializerBase class.
However, a design vulnerability exists in how the library caches unknown type IDs when fallback configurations are active. If the deserializer is configured with a default implementation (via defaultImpl = ...) or utilizes a custom DeserializationProblemHandler to gracefully handle unknown types, the lookup mechanism resolves any unrecognized type string to that fallback deserializer. The vulnerability arises because the library caches this mapping using the raw, attacker-supplied, unknown type string as the unique key within a long-lived, unbounded map.
Because the underlying cache map (_deserializers) is bound to the lifetime of the ObjectMapper instance—which is almost universally registered as an application-wide singleton—any memory retained by the map remains occupied indefinitely. Remote, unauthenticated attackers can exploit this behavior by sending a stream of payloads, each featuring a newly generated, unique, or exceptionally long unrecognized type identifier. This results in direct, monotonic memory consumption on the JVM heap.
The root cause of CVE-2026-91776 lies within the polymorphic type resolution implementation of com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase. When processing name-based polymorphic structures, the library relies on the internal method _findDeserializer(DeserializationContext ctxt, String typeId) to retrieve the appropriate deserializer for the given typeId string. The cache of resolved type-to-deserializer mappings is stored in the local map declared as:
protected final Map<String, JsonDeserializer<Object>> _deserializers;
When a request contains an unrecognized typeId, and a fallback implementation is defined, the lookup logic maps this invalid ID to the fallback deserializer (e.g., NullifyingDeserializer or the user-defined defaultImpl class). In vulnerable versions, the method executes _deserializers.put(typeId, deser); without validating the size of the _deserializers map or checking the length of the typeId key.
Because this cache lacks an entry-count ceiling and has no key-length restriction, the application fails to control resource consumption (CWE-400). A malicious actor can force the storage of an infinite number of unique string keys in the cache, with each key pointing to the same fallback deserializer object. Since the keys are unique strings, they represent newly allocated memory that cannot be reclaimed by garbage collection, guaranteeing eventual exhaustion of the JVM heap space.
The official fix, introduced in commit 2870d1d6dc1b7e1c07ee11dd5b04ab71cddbb577, implements bounds and structural restrictions to neutralize cache-exhaustion techniques.
// Vulnerable logic in TypeDeserializerBase.java directly stored the key:
_deserializers.put(typeId, deser);The patch introduces two defensive constraints (MAX_CACHED_TYPE_IDS and MAX_CACHED_TYPE_ID_LENGTH) to regulate the caching behavior of _deserializers:
// Hard-caps added in patched version:
final static int MAX_CACHED_TYPE_IDS = 1000;
final static int MAX_CACHED_TYPE_ID_LENGTH = 256;In addition to these limits, the patch inserts validation checks before putting new entries into the cache:
// Guard conditions to limit cache expansion
if (typeId.length() > MAX_CACHED_TYPE_ID_LENGTH) {
return deser; // Resolve but do not cache excessively long keys
}
if (_deserializers.size() >= MAX_CACHED_TYPE_IDS) {
_deserializers.clear(); // Flush cache if it exceeds size limits
}
_deserializers.put(typeId, deser);Furthermore, the patch modifies _findDeserializer to prevent caching instances of NullifyingDeserializer.instance and other transient deserialization fallbacks resolved via problem handlers. This ensures that transient, context-specific deserialization results do not corrupt or saturate the common cache. If an attacker tries to flood the system with randomized type IDs, the map will safely purge itself once it reaches 1,000 keys, limiting memory usage.
An attack against CVE-2026-91776 requires three conditions: polymorphic name-based deserialization is active, a default/fallback implementation is declared, and the parsing engine uses a singleton mapper.
The following architectural sequence illustrates how an attacker exploits the unbounded cache inside the JVM heap:
To execute the attack, the adversary transmits HTTP requests containing JSON bodies with randomized string keys. An example attack vector targeting a hypothetical Animal endpoint is structured as follows:
{ "animal": { "type": "exploit_key_9bc4a89d1", "name": "Rover" } }
{ "animal": { "type": "exploit_key_0ef72b4c2", "name": "Rover" } }With each request, the cache is populated with a unique key. Because the heap footprint grows with each request, an automated script sending thousands of requests per second can quickly exhaust the memory allocated to the JVM. Once the heap is full, performance degrades as garbage collection threads consume CPU cycles in vain, leading to an eventual application crash.
The primary impact of CVE-2026-91776 is an unauthenticated, remote denial of service (DoS) on the target host. Because name-based polymorphic parsing is heavily utilized in microservice architectures and RESTful web interfaces, endpoints processing structured JSON inputs are highly exposed.
When exploitation occurs, the physical memory allocated to the JVM is filled with uncollectible references. This forces the JVM Garbage Collector into a loop of aggressive collection sweeps, leading to high CPU usage and thread starvation. Legitimate user requests are delayed, timed out, or dropped.
Once the Garbage Collector cannot reclaim enough space to fulfill new object allocations, the JVM throws a fatal java.lang.OutOfMemoryError: Java heap space and crashes. In containerized environments, such as Kubernetes, this crash triggers container restarts. If the attack continues, it can result in a permanent outage of the target microservice, causing cascading failures across upstream components.
The recommended mitigation is to upgrade jackson-databind to a patched release. For environments where immediate patching is not possible, developers can implement several workarounds to reduce risk.
One workaround is to avoid using catch-all fallback classes or default implementations (defaultImpl) in name-based polymorphic mappings. By omitting default implementations, the parser fails immediately when encountering an invalid type ID, preventing cache allocation.
Another option is to implement a strict, custom TypeIdResolver to validate incoming type ID strings against a static list of allowed classes before resolution. This stops unknown inputs from entering the resolution pipeline. In addition, security teams can configure web application firewalls (WAF) to detect and block JSON payloads where polymorphic type fields exceed standard lengths (e.g., more than 256 characters).
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.0.0, <= 2.18.10 | 2.18.11 |
jackson-databind FasterXML | >= 2.19.0, <= 2.21.6 | 2.21.7 |
jackson-databind FasterXML | >= 2.22.0, <= 2.22.2 | 2.22.3 |
jackson-databind FasterXML | >= 3.0.0, <= 3.1.6 | 3.1.7 |
jackson-databind FasterXML | >= 3.2.0, <= 3.2.2 | 3.2.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Network |
| CVSS Severity | 7.5 (High) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
| Vulnerability Class | Uncontrolled Resource Consumption |
The application does not adequately control the allocation and maintenance of a limited resource, enabling an actor to cause a denial of service.
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.
A security vulnerability in league/commonmark versions 1.3.0 through 2.10.1 allows remote attackers to bypass Stored Cross-Site Scripting (XSS) protections in the DisallowedRawHtml extension. Due to an validation logic flaw in the regular expression parser, specifically handling bare, unclosed HTML blocks ending at the string boundary, raw HTML tags can be passed to the rendered output. When combined with browser-side parsing heuristics, an attacker can execute arbitrary JavaScript in the context of the user session.
A DOM-based Cross-Site Scripting (DOM XSS) vulnerability in DOMPurify allows attackers to bypass sanitization when using the in-place sanitization configuration (IN_PLACE: true) combined with custom hooks. If custom hooks detach elements during post-processing phases, nested malicious payloads can escape sterilization and execute in the browser's context.
A security vulnerability in serialize-javascript v7.1.1 allows Cross-Site Scripting (XSS) due to an overly greedy regular expression (SCRIPT_CLOSE_REGEXP) used during function serialization. Two secondary defects involving a spoofed toString() validation bypass and a stateful native code validator are also addressed in the fixed version v7.1.2.
A Denial of Service (DoS) vulnerability exists in the PyJWT library when parsing unverified token payloads containing deeply nested JSON structures. Because PyJWT fails to catch RecursionError during payload parsing, an unauthenticated remote attacker can crash the application thread or worker by sending a specially crafted token.
An improper output encoding and escaping vulnerability (CWE-116) in Vercel Satori allows unauthenticated remote attackers to perform markup injection in dynamic Open Graph images generated via Next.js's ImageResponse. Unsanitized parameter interpolation into SVG elements breaks XML structural boundaries. This exposes downstream parsing, rasterization, and rendering pipelines to Server-Side Request Forgery (SSRF), Local File Read, and Remote Code Execution (RCE).