VYPR
High severityNVD Advisory· Published Mar 18, 2023· Updated Feb 26, 2025

CVE-2021-46877

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.

PackageAffected versionsPatched versions
com.fasterxml.jackson.core:jackson-databindMaven
>= 2.10.0, < 2.12.62.12.6
com.fasterxml.jackson.core:jackson-databindMaven
>= 2.13.0, < 2.13.12.13.1

Affected products

13

Patches

1
3ccde7d938fe

Fix #3328 (improvement to handling of JDK serialization of JsonNode)

https://github.com/FasterXML/jackson-databindTatu SalorantaDec 4, 2021via ghsa
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

News mentions

0

No linked articles in our index yet.