CVE-2021-46877
Description
jackson-databind 2.10.x through 2.12.x before 2.12.6 and 2.13.x before 2.13.1 allows attackers to cause a denial of service (2 GB transient heap usage per read) in uncommon situations involving JsonNode JDK serialization.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2021-46877 is a denial-of-service vulnerability in Jackson Databind caused by unbounded memory allocation during JDK serialization of JsonNode objects.
Vulnerability
Overview
CVE-2021-46877 describes a denial-of-service (DoS) vulnerability in FasterXML jackson-databind affecting versions 2.10.x through 2.12.x before 2.12.6 and 2.13.x before 2.13.1 [2][4]. The root cause lies in the NodeSerialization helper class, which handles JDK serialization of JsonNode objects. During deserialization, the code reads an integer length from the input stream and immediately allocates a byte array of that size without any bounds checking [3]. An attacker can craft a malicious serialized payload specifying an extremely large length (e.g., 2 GB), causing the JVM to allocate a huge transient byte array per read operation, leading to excessive heap usage and potentially service disruption.
Attack
Surface and Prerequisites
The vulnerability is exploitable only in scenarios where untrusted data is deserialized using JDK serialization (ObjectInputStream) on JsonNode objects [4]. This is uncommon, as Jackson's typical usage involves JSON parsing via ObjectMapper. Attackers must have the ability to supply a crafted JDK serialized object to the application, which may be possible in contexts like distributed caching systems, session persistence, or other frameworks that perform Java serialization. No authentication is required for the DoS attack itself, but network access to the deserialization endpoint is necessary. The impact is purely resource exhaustion (CPU/memory) leading to denial of service; there is no data leak or privilege escalation.
Mitigation and
Fix
The fix, introduced in jackson-databind 2.12.6 and 2.13.1, limits eager memory allocation during deserialization by introducing a threshold constant LONGEST_EAGER_ALLOC set to 100,000 bytes [3]. For lengths beyond this threshold, the code uses a ByteArrayBuilder with incremental reading to avoid large pre-allocation. Users are advised to upgrade to the patched versions. Versions 2.10.x and 2.11.x are not backported and remain vulnerable; users should upgrade to a supported branch. The vulnerability does not affect Jackson 2.9.x or earlier, nor versions 2.14 and later [4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
com.fasterxml.jackson.core:jackson-databindMaven | >= 2.10.0, < 2.12.6 | 2.12.6 |
com.fasterxml.jackson.core:jackson-databindMaven | >= 2.13.0, < 2.13.1 | 2.13.1 |
Affected products
13- jackson-databind/jackson-databinddescription
- osv-coords12 versionspkg:apk/chainguard/cassandra-reaperpkg:apk/chainguard/management-api-for-apache-cassandra-4.0pkg:apk/chainguard/management-api-for-apache-cassandra-4.0-compatpkg:apk/chainguard/management-api-for-apache-cassandra-4.1pkg:apk/chainguard/management-api-for-apache-cassandra-5.0pkg:apk/chainguard/management-api-for-apache-cassandra-5.0-compatpkg:apk/chainguard/request-1277pkg:apk/wolfi/cassandra-reaperpkg:apk/wolfi/management-api-for-apache-cassandra-4.1pkg:apk/wolfi/management-api-for-apache-cassandra-5.0pkg:apk/wolfi/management-api-for-apache-cassandra-5.0-compatpkg:maven/com.fasterxml.jackson.core/jackson-databind
< 4.0.1-r1+ 11 more
- (no CPE)range: < 4.0.1-r1
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 0.1.109-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 4.0.1-r1
- (no CPE)range: < 0.1.109-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: < 0.1.89-r0
- (no CPE)range: >= 2.10.0, < 2.12.6
Patches
13ccde7d938feFix #3328 (improvement to handling of JDK serialization of JsonNode)
3 files changed · +76 −6
release-notes/VERSION-2.x+1 −0 modified@@ -9,6 +9,7 @@ Project: jackson-databind #3280: Can not deserialize json to enum value with Object-/Array-valued input, `@JsonCreator` (reported by peteryuanpan@github) +#3328: Possible DoS issue 2.12.5 (27-Aug-2021)
src/main/java/com/fasterxml/jackson/databind/node/NodeSerialization.java+36 −2 modified@@ -4,6 +4,8 @@ import java.io.ObjectInput; import java.io.ObjectOutput; +import com.fasterxml.jackson.core.util.ByteArrayBuilder; + /** * Helper value class only used during JDK serialization: contains JSON as `byte[]` * @@ -12,6 +14,9 @@ class NodeSerialization implements java.io.Serializable, java.io.Externalizable { + // To avoid malicious input only allocate up to 100k + protected final static int LONGEST_EAGER_ALLOC = 100_000; + private static final long serialVersionUID = 1L; public byte[] json; @@ -45,7 +50,36 @@ public void writeExternal(ObjectOutput out) throws IOException { @Override public void readExternal(ObjectInput in) throws IOException { final int len = in.readInt(); - json = new byte[len]; - in.readFully(json, 0, len); + json = _read(in, len); + } + + private byte[] _read(ObjectInput in, int expLen) throws IOException { + // Common case, just read directly + if (expLen <= LONGEST_EAGER_ALLOC) { + byte[] result = new byte[expLen]; + in.readFully(result, 0, expLen); + return result; + } + // but longer content needs more care to avoid DoS by maliciously crafted data + // (this wrt [databind#3328] + try (final ByteArrayBuilder bb = new ByteArrayBuilder(LONGEST_EAGER_ALLOC)) { + byte[] buffer = bb.resetAndGetFirstSegment(); + int outOffset = 0; + while (true) { + int toRead = Math.min(buffer.length - outOffset, expLen); + in.readFully(buffer, 0, toRead); + expLen -= toRead; + outOffset += toRead; + // Did we get everything we needed? If so, we are done + if (expLen == 0) { + return bb.completeAndCoalesce(outOffset); + } + // Or perhaps we filled the current segment? If so, finish, get next + if (outOffset == buffer.length) { + buffer = bb.finishCurrentSegment(); + outOffset = 0; + } + } + } } }
src/test/java/com/fasterxml/jackson/databind/node/NodeJDKSerializationTest.java+39 −4 renamed@@ -1,11 +1,14 @@ -package com.fasterxml.jackson.databind; +package com.fasterxml.jackson.databind.node; import java.io.*; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.core.JsonGenerator; -public class TestNodeJDKSerialization extends BaseMapTest +import com.fasterxml.jackson.databind.BaseMapTest; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class NodeJDKSerializationTest extends BaseMapTest { private final ObjectMapper MAPPER = newJsonMapper(); @@ -40,6 +43,38 @@ public void testArrayNodeSerialization() throws Exception testNodeRoundtrip(root); } + // [databind#3328] + public void testBigArrayNodeSerialization() throws Exception + { + // Try couple of variations just to tease out possible edge cases + _testBigArrayNodeSerialization(NodeSerialization.LONGEST_EAGER_ALLOC - 39); + _testBigArrayNodeSerialization(NodeSerialization.LONGEST_EAGER_ALLOC + 1); + _testBigArrayNodeSerialization(3 * NodeSerialization.LONGEST_EAGER_ALLOC - 1); + _testBigArrayNodeSerialization(9 * NodeSerialization.LONGEST_EAGER_ALLOC); + } + + private void _testBigArrayNodeSerialization(int expSize) throws Exception + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int ix = 0; + try (JsonGenerator g = MAPPER.createGenerator(out)) { + g.writeStartArray(); + + do { + g.writeStartObject(); + g.writeNumberField("index", ix++); + g.writeStringField("extra", "none#"+ix); + g.writeEndObject(); + } while (out.size() < expSize); + + g.writeEndArray(); + } + + JsonNode root = MAPPER.readTree(out.toByteArray()); + + testNodeRoundtrip(root); + } + // and then also some scalar types public void testScalarSerialization() throws Exception {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-3x8x-79m2-3w2wghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2021-46877ghsaADVISORY
- github.com/FasterXML/jackson-databind/commit/3ccde7d938fea547e598fdefe9a82cff37fed5cbghsaWEB
- github.com/FasterXML/jackson-databind/issues/3328ghsaWEB
- groups.google.com/g/jackson-user/c/OsBsirPM_VwghsaWEB
News mentions
0No linked articles in our index yet.