CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2022-42004
CVSS 7.5|EPSS 0.14%

CVE-2022-42004: Death by a Thousand Brackets in Jackson-databind

Amit Schendel
Amit Schendel
Senior Security Researcher•January 2, 2026•5 min read
PoC Available

Executive Summary (TL;DR)

If you use Jackson to deserialize JSON and have `UNWRAP_SINGLE_VALUE_ARRAYS` enabled, a payload like `[[[[...]]]]` will crash your application via stack exhaustion. Update to 2.13.4 or disable the feature.

A high-severity Denial of Service vulnerability in the ubiquitous FasterXML jackson-databind library. By exploiting the UNWRAP_SINGLE_VALUE_ARRAYS feature with deeply nested JSON arrays, attackers can trigger a StackOverflowError, crashing JVMs with trivial payloads.

The Hook: Java's JSON Juggernaut

If you write Java, you use Jackson. It is the dark matter of the Java ecosystem—invisible, pervasive, and holding everything together. Whether you are building a Spring Boot microservice or a legacy enterprise monolith, jackson-databind is almost certainly the engine parsing your JSON.

But great power comes with great configuration complexity. Jackson has a feature called DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS. It is a quality-of-life setting designed for dealing with quirky APIs that wrap objects in arrays unnecessarily. If enabled, it tells Jackson: "Hey, if you see [{"id":1}], just treat it as {"id":1}."

It sounds helpful, right? A lenient parser is a developer's best friend. But in the security world, leniency is just another word for "attack surface." It turns out that this helpful unwrapping logic was a bit too willing to dive down the rabbit hole, and it forgot to check how deep the hole went.

The Flaw: Recursion Without Brakes

The vulnerability is a classic case of CWE-674: Uncontrolled Recursion. When UNWRAP_SINGLE_VALUE_ARRAYS is enabled, the BeanDeserializer attempts to handle an incoming array by peeking inside to find the actual object.

Here is the logic flaw: When the deserializer encounters a START_ARRAY token ([), it calls a function to handle the unwrapping. If the very next token is another START_ARRAY, the code recursively calls the deserialization method again. It assumes that eventually, it will hit a JSON object (the "meat" of the data).

The problem is that the computer's stack memory is finite. Each recursive call pushes a new frame onto the stack. If an attacker sends a JSON payload consisting of thousands of opening brackets—[[[[[[...—the parser dutifully creates thousands of stack frames. Eventually, the JVM runs out of stack space and throws a StackOverflowError.

Unlike a regular Exception, a StackOverflowError is an Error type in Java. It is often fatal to the thread processing the request, and in many web server configurations, valid requests can get caught in the crossfire or the entire application container can become unstable.

The Code: The Smoking Gun

Let's look at the fix in BeanDeserializer.java. The patch is deceptively simple, proving that the most dangerous bugs often hide in plain sight.

The Vulnerable Logic (Conceptual): Before the patch, the code essentially said: "If unwrapping is enabled and I see an array, call deserialize again to unpack it."

The Fix (Commit 063183589218fec19a9293ed2f17ec53ea80ba88): The maintainers added a check to ensure that we only unwrap once. If the parser peels back the first layer of the array and immediately sees another array, it realizes it's being tricked and bails out.

// BeanDeserializer.java patch logic
if (_unwrapSingle == Boolean.TRUE ||
        ((_unwrapSingle == null) && _beanProperties.findFormatFeature(ctxt, _beanType, JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY).asBoolean())) {
    JsonToken t = p.nextToken();
    
    // THE FIX: Check if the next token is ALSO an array start
    if (t == JsonToken.START_ARRAY) {
        return (Object) ctxt.handleUnexpectedToken(_beanType, p);
    }
    
    // Proceed with deserialization...
    final Object value = deserialize(p, ctxt);
}

The key change is the check if (t == JsonToken.START_ARRAY). It explicitly forbids nested arrays when unwrapping is active. It says, "I will unwrap one layer for you, but I am not unwrapping a Russian nesting doll of arrays."

The Exploit: Crashing the JVM

Exploiting this is embarrassingly easy. You don't need shellcode, you don't need memory addresses, and you don't need to bypass ASLR. You just need a text editor and the [ key.

If you identify an endpoint that accepts JSON and has this feature enabled (often done globally in ObjectMapper configuration), you just send this:

[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[...]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]

The Attack Chain:

  1. Recon: Identify a Java backend (headers like X-Powered-By: Spring or typical stack traces are a giveaway).
  2. Probe: Send valid JSON wrapped in a single array [{"test":1}]. If the server accepts it and treats it as {"test":1}, the vulnerable feature is likely enabled.
  3. Weaponize: Generate a payload with ~10,000 opening brackets.
  4. Fire: POST the payload. The server thread handling your request consumes its stack space recursively calling deserialize().
  5. Impact: java.lang.StackOverflowError. If you send enough of these concurrently, you can exhaust the thread pool or crash the JVM entirely.

The Fix: Remediation

This isn't a complex architectural change. It's a patch update.

Option 1: Update (Preferred) Upgrade jackson-databind to version 2.13.4, 2.14.0, or later. If you are stuck on the 2.12.x branch, a patch was backported to 2.12.7.1.

Option 2: Configuration Change If you can't update, verify if you actually need DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS. It is disabled by default. If you turned it on, try turning it off:

objectMapper.disable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);

Option 3: Stream Constraints (Modern) In versions 2.15+, Jackson introduced StreamReadConstraints. This allows you to set a hard limit on nesting depth globally, which kills this entire class of vulnerability regardless of specific feature flags:

factory.setStreamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(1000).build());

Official Patches

FasterXMLIssue Tracker #3590
DebianDebian Security Tracker

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.14%
Top 35% most exploited

Affected Systems

Java applications using jackson-databind < 2.13.4Spring Boot applications (depend on Jackson)Microservices with UNWRAP_SINGLE_VALUE_ARRAYS enabled

Affected Versions Detail

ProductAffected VersionsFixed Version
jackson-databind
FasterXML
< 2.13.42.13.4
jackson-databind
FasterXML
2.12.0 - 2.12.72.12.7.1
AttributeDetail
CWECWE-674 (Uncontrolled Recursion)
CVSS7.5 (High)
Attack VectorNetwork
Availability ImpactHigh (Stack Exhaustion)
Exploit ComplexityLow
AuthenticationNone

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application Exhaustion
Impact
CWE-674
Uncontrolled Recursion

Uncontrolled Recursion

Exploit Resources

Known Exploits & Detection

GitHubOriginal issue report with reproduction steps

Vulnerability Timeline

Vulnerability Timeline

Issue Reported & Fixed in Codebase
2022-09-14
Release 2.13.4 published
2022-10-02
CVE-2022-42004 assigned
2022-10-06

References & Sources

  • [1]Jackson-databind Issue 3590
  • [2]NVD - CVE-2022-42004
Related Vulnerabilities
CVE-2022-42003

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.