Security
Mar 12, 2026

CVE-2025-52999: Denial of Service via Stack Overflow in Jackson Core

Deeply nested JSON can crash your application — and if you're on Spring Boot 2.7, the upgrade path is more complicated than it looks.

Give me the TL;DR
CVE-2025-52999: Denial of Service via Stack Overflow in Jackson Core
For Qualys admins, NES for .NET directly resolves the EOL/Obsolete Software:   Microsoft .NET Version 6 Detected vulnerability, ensuring your systems remain secure and compliant. Fill out the form to get pricing details and learn more.

Jackson is the backbone of JSON processing in the Java ecosystem. If your application accepts JSON input (and in 2026, it almost certainly does), there is a good chance jackson-core is somewhere in your dependency tree. That ubiquity is exactly what makes CVE-2025-52999 worth your attention: it is a high-severity Denial of Service vulnerability that affects every version of jackson-core prior to 2.15.0.

And it is not alone. A second vulnerability, GHSA-72hv-8253-57qq, targets the async parser path and bypasses the very constraints that were introduced to prevent this class of attack. Together, these two issues paint a clear picture: if you are running an older version of Jackson, your application's availability is at risk.

What is CVE-2025-52999?

CVE-2025-52999 is a Denial of Service (DoS) vulnerability in jackson-core caused by unbounded recursion when parsing deeply nested JSON structures. It carries a CVSS v4.0 score of 8.7 (HIGH).

The root cause is straightforward. When jackson-core encounters a nested JSON object ({) or array ([), the parser creates a new JsonReadContext on the call stack for each level of nesting. In versions prior to 2.15.0, there is no limit on how deep this nesting can go. An attacker can craft a JSON payload consisting of thousands of nested arrays or objects, something like:

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

When the parser processes this input, each nesting level adds a new frame to the JVM's call stack. Eventually, the stack space is exhausted and the JVM throws a StackOverflowError. The application crashes.

The fix in jackson-core 2.15.0 introduces a configurable maximum nesting depth (defaulting to 1000) via the StreamReadConstraints API. When the limit is reached, the parser throws a StreamConstraintsException instead of allowing the stack to overflow. Because jackson-databind relies on jackson-core for parsing, it also benefits from this fix.

Why is a StackOverflowError even a vulnerability?

Developers sometimes dismiss StackOverflowError as an inconvenience rather than a security issue. The reasoning goes: "It just crashes the thread, not the whole system." That reasoning is wrong in most real-world deployments, and here is why.

A StackOverflowError is an Error, not an Exception. In Java's exception hierarchy, Error signals a condition that a reasonable application should not try to catch or recover from. Most application code does not (and should not) have catch (Error e) blocks. When a StackOverflowError propagates uncaught, it can terminate the thread, corrupt shared state, or destabilize the entire JVM process.

In servlet containers and application servers, a single poisoned request can take down the worker thread. If an attacker sends multiple malicious payloads concurrently, they can exhaust the thread pool and render the entire service unresponsive. This is a classic amplification pattern: a small, cheap-to-send payload causes disproportionate damage on the server side.

The attack requires zero authentication and zero knowledge of the application's internals. Any endpoint that accepts JSON input is a potential target. The attacker does not need to know your data model, your ORM configuration, or your business logic. They just need to send deeply nested brackets.

This is why NVD and CVSS both classify CVE-2025-52999 as high severity with an availability impact of HIGH: it is remotely exploitable, requires no privileges, and can render services completely unavailable.

GHSA-72hv-8253-57qq: The async parser bypasses the fix

Even if you have upgraded to a version of jackson-core that includes StreamReadConstraints (2.15.0+), you may still be vulnerable. GHSA-72hv-8253-57qq, published on February 26, 2026, reveals that the non-blocking (async) JSON parser in jackson-core bypasses the maxNumberLength constraint defined in StreamReadConstraints.

The maxNumberLength setting (default: 1000 characters) is supposed to prevent an attacker from submitting JSON with absurdly long numeric values that consume excessive memory and CPU. The synchronous parser enforces this limit correctly. The async parser does not.

The root cause is in NonBlockingUtf8JsonParserBase and related classes. The async parsing path accumulates digits into the TextBuffer without ever calling the validation methods (validateIntegerLength(), validateFPLength()) that enforce the constraint. After parsing, _valueComplete() finalizes the token but skips the resetInt() and resetFloat() methods where those checks live.

This matters because the async parser is not a niche feature. It is the parser used by reactive frameworks: Spring WebFlux, Vert.x, Micronaut, and any application that uses non-blocking I/O for JSON processing. Apache Kafka has already tracked this issue as affecting its own releases.

Affected versions: jackson-core 2.0.0 through 2.18.5, and 2.19.0 through 2.21.0.

Fixed versions: 2.18.6, 2.21.1, and 3.1.0.

As of this writing, GHSA-72hv-8253-57qq does not yet have a CVE ID assigned. That matters for tooling: many enterprise SCA pipelines and compliance gates still key off CVE IDs exclusively. If your scanner has not flagged this, it does not mean you are safe. Treat this as a first-class vulnerability regardless of the identifier format.

Why upgrading jackson-core is harder than it sounds

The natural response to both of these vulnerabilities is "just upgrade." But for a huge number of Java applications, that is far easier said than done.

Jackson 2.13 is the version that Spring Boot 2.7 manages. Spring Boot 2.7 pins its entire Jackson dependency tree (core, databind, annotations, dataformat modules, and more) to the 2.13.x line. If your application is built on Spring Boot 2.7, you are running a version of jackson-core that is vulnerable to CVE-2025-52999 and cannot be patched to fix GHSA-72hv-8253-57qq without a major version jump.

Jackson 2.13 has been a closed branch since November 2023. According to the Jackson Releases wiki, the 2.13 branch was closed when Jackson 2.16.0 was released. No new patch releases are planned. The Jackson community's currently supported open branches are 2.18 (LTS), 2.21 (LTS), and 3.1 (LTS). Everything between 2.13 and 2.18 is also closed.

Upgrading Jackson means upgrading Spring Boot (or accepting risk). You can attempt to override the jackson.version property in your Maven or Gradle build to pull in a newer Jackson version. But jumping from 2.13.x to 2.15.x+ introduces internal API changes, new constraint behaviors (like the default 1000-depth limit), and potential compatibility issues with other Spring Boot-managed dependencies that expect the 2.13 API surface. The Spring team explicitly discourages mixing Spring Boot dependency management versions with manually overridden library versions for this reason.

Spring Boot 2.7 itself reached end of life in November 2023. So you are in a situation where both the framework and its transitive dependency are unsupported. The community fix for CVE-2025-52999 requires jackson-core 2.15.0+, and the fix for GHSA-72hv-8253-57qq requires 2.18.6+ or 2.21.1+. Neither of those versions is a clean drop-in replacement for a Spring Boot 2.7 application.

This is the classic EOL dependency trap. The vulnerability exists. The fix exists. But the upgrade path requires a significant migration effort that many teams cannot justify or schedule in the short term.

What options do affected users have?

If your application depends on jackson-core < 2.15.0 (whether through Spring Boot 2.7 or another path), you have several options, each with tradeoffs.

1. Upgrade to a supported Spring Boot and Jackson version

This is the "correct" long-term answer. Migrate to Spring Boot 3.x (which uses Jackson 2.15+), and then ensure you are on a Jackson LTS branch (2.18 or 2.21). This resolves both CVE-2025-52999 and GHSA-72hv-8253-57qq, and puts you back on a supported dependency chain.

The tradeoff: Spring Boot 3.x requires Java 17+, Jakarta EE 9+ (the javax.* to jakarta.* namespace migration), and potentially significant refactoring depending on your codebase. For large enterprise applications, this is a multi-quarter effort.

2. Override the Jackson version in your build

You can set jackson-bom.version or jackson.version in your Maven properties to pull in jackson-core 2.18.6+ while staying on Spring Boot 2.7. This is a pragmatic middle ground, but it comes with risk: you are running a Jackson version that Spring Boot 2.7 was never tested against. Integration issues may surface in serialization behavior, auto-configuration, or downstream libraries.

3. Implement input validation at the gateway layer

As a short-term mitigation, you can add request payload validation at your API gateway or load balancer to reject JSON payloads that exceed a reasonable nesting depth or total size. This does not fix the underlying vulnerability, but it can reduce your attack surface while you plan a proper upgrade.

4. Use HeroDevs NES for Jackson

HeroDevs' Never-Ending Support (NES) for Jackson provides security patches for end-of-life Jackson versions, including the 2.13.x line used by Spring Boot 2.7. NES delivers the fix as a drop-in replacement: same group IDs, same artifact IDs, same API surface. You get the security patch without the migration risk.

This is particularly relevant for organizations that need to remediate CVE-2025-52999 for compliance (SOC 2, PCI DSS, EU CRA) but cannot execute a full Spring Boot migration on the timeline their security policy demands. NES bridges the gap between "we need to fix this now" and "we will migrate when we can."

Taking Action

CVE-2025-52999 and GHSA-72hv-8253-57qq are both Denial of Service vulnerabilities that target the parsing layer of one of Java's most widely used libraries. They are remotely exploitable, require no authentication, and can crash applications that accept untrusted JSON input.

If you are running jackson-core < 2.15.0, you are vulnerable to CVE-2025-52999. If you are running any version before 2.18.6 or 2.21.1, you may be vulnerable to GHSA-72hv-8253-57qq in async/reactive contexts. And if you are on Spring Boot 2.7, upgrading is not a one-line fix.

Audit your dependency tree. Know which version of jackson-core you are actually running. And choose a remediation path that matches your timeline and risk tolerance, whether that is a full migration, a version override, or commercial long-term support through HeroDevs NES.

FAQs

What is CVE-2025-52999, in one sentence?

A high-severity Denial of Service issue in jackson-core where deeply nested JSON triggers unbounded recursion during parsing, leading to a JVM StackOverflowError and potential service outage.

Which versions of jackson-core are affected by CVE-2025-52999?

All versions of jackson-core prior to 2.15.0 are affected (per this article’s definition).

What’s the underlying technical root cause?

When parsing nested { and [ tokens, Jackson creates a new parsing context for each nesting level; without a depth limit (pre-2.15.0), sufficiently deep nesting can exhaust the call stack.

What changed in jackson-core 2.15.0 to address this?

2.15.0 introduced StreamReadConstraints with a configurable maximum nesting depth (default 1000), causing parsing to fail with a StreamConstraintsException instead of crashing via stack overflow.

Why is StackOverflowError considered a security vulnerability and not “just a bug”?

Because it’s an Error (not an Exception), often uncaught, and can kill request threads in servers. Repeated malicious requests can exhaust thread pools and effectively take the service down (availability impact).

What is GHSA-72hv-8253-57qq?

A vulnerability in the non-blocking/async Jackson parser path where it bypasses StreamReadConstraints number-length checks, allowing extremely long numeric tokens to consume CPU/memory (DoS risk), especially in reactive stacks.

Does GHSA-72hv-8253-57qq have a CVE ID?

Not yet (as of February 26, 2026 per the article). That can matter because some SCA/compliance gates only track CVE identifiers, so you may need to treat the GHSA as first-class even if tooling misses it.

Which jackson-core versions are affected by GHSA-72hv-8253-57qq?

Affected: 2.0.0 through 2.18.5, and 2.19.0 through 2.21.0
Fixed: 2.18.6, 2.21.1, and 3.1.0

Why does this GHSA matter more for reactive applications?

Because the async/non-blocking parser is commonly used by reactive frameworks (for example, Spring WebFlux, Vert.x, Micronaut) where JSON is parsed in a non-blocking fashion—so the bypassed constraints are more likely to be in play.

If I upgrade to jackson-core 2.15.0+, am I fully protected?

You’re protected against the nesting-depth stack overflow class (CVE-2025-52999) in the paths that enforce StreamReadConstraints, but the async parser has a separate constraint-bypass issue (GHSA-72hv-8253-57qq) that requires newer fixed versions.

What’s the minimum “safe” jackson-core version recommended by this article?

To address CVE-2025-52999: 2.15.0+
To address GHSA-72hv-8253-57qq (async contexts): 2.18.6+ or 2.21.1+ (or 3.1.0)

Why can’t Spring Boot 2.7 users just patch this easily?

Spring Boot 2.7 manages Jackson around the 2.13.x line, and Jackson 2.13 is closed/EOL (no new patches planned). Moving to patched Jackson lines often implies moving Spring Boot major versions, which can be substantial.

What makes upgrading from Spring Boot 2.7 to 3.x “big”?

Spring Boot 3.x typically requires Java 17+, Jakarta EE 9+ namespace migration (javax. to jakarta.), and potential refactors in frameworks/libraries depending on your stack.

What are the remediation options described here?

  1. Upgrade to supported Spring Boot + Jackson LTS (best long-term)
  2. Override Jackson versions in your build while staying on Boot 2.7 (pragmatic, but riskier)
  3. Gateway validation (limit nesting depth / payload size) as a short-term mitigation
  4. HeroDevs NES for Jackson for drop-in security patches on EOL Jackson lines (like 2.13.x)

If I’m stuck on Boot 2.7, what’s the lowest-risk “fix now” approach mentioned?

HeroDevs NES for Jackson provides a drop-in patched artifact approach for EOL Jackson versions, minimizing migration risk while remediating security findings.

What should teams do first before choosing a fix?

Audit your dependency tree and confirm the actual runtime jackson-core version, since it’s often transitive.

What kinds of endpoints are exposed?

Any endpoint that accepts untrusted JSON—the attacker only needs to send deeply nested braces/brackets or extremely long number tokens (async parser case).

Table of Contents
Author
Greg Allen
Chief Technology Officer
Open Source Insights Delivered Monthly