JDK deserialization of a `JsonNode` with a negative length prefix throws `NegativeArraySizeException` instead of an `IOException`
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
Research direction
The bug is in NodeSerialization.readExternal() and _read() in NodeSerialization.java, where a negative length from in.readInt() reaches new byte[expLen] on the eager path. Start by reading _read() around line 62 and add a check that throws a StreamCorruptedException when expLen is negative. Done when the reproduction in the issue throws an IOException and the existing test suite still passes.
Written by the indexing model from the issue text.
Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
JsonNode is JDK-serialized through NodeSerialization, which writes a 4-byte length followed by the JSON bytes. On reading, a negative length makes readObject() throw an unchecked NegativeArraySizeException. A length that is too large is reported as an EOFException, and other malformed streams give IOExceptions:
java.lang.NegativeArraySizeException: -1
at tools.jackson.databind.node.NodeSerialization._read(NodeSerialization.java:63)
at tools.jackson.databind.node.NodeSerialization.readExternal(NodeSerialization.java:57)
at java.base/java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:2333)
...
Cause: readExternal() passes the length read by in.readInt() to _read() (NodeSerialization.java:56-57). _read() takes the eager path for every expLen <= LONGEST_EAGER_ALLOC (:62), including negative values, and calls new byte[expLen] (:63). 2.x has the same code (NodeSerialization.java:52-59). The #3328 hardening only covers large lengths.
The effect is limited to the exception type: the stream is rejected either way, so this is not a security issue. Callers that catch IOException around readObject() do get an unexpected runtime exception, though.
Version Information
3.x (3.3.0-SNAPSHOT, 043e38d), 3.2.4, 2.x (2.23.0-SNAPSHOT, 425299b), 2.22.4.
Reproduction
JsonNode node = new JsonMapper().createObjectNode().put("a", 1);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
out.writeObject(node);
}
byte[] b = bytes.toByteArray();
// overwrite the 4-byte length that precedes the JSON payload {"a":1} with -1
int idx = indexOf(b, "{\"a\":1}".getBytes(StandardCharsets.UTF_8));
b[idx - 4] = b[idx - 3] = b[idx - 2] = b[idx - 1] = (byte) 0xFF;
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(b))) {
in.readObject(); // NegativeArraySizeException
}
Expected behavior
An IOException, for example StreamCorruptedException("Invalid JsonNode content length: -1") thrown from _read() when expLen < 0. With that change, the full 3.x test suite passes.
Additional context
This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually.
- Dominant language
- Java
- Stars
- 3.8k
- Forks
- 1.6k
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 59
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from FasterXML/jackson-databind
-
to-evaluate
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
FasterXML/jackson-databind#6340 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 12/100
FasterXML/jackson-databind#6442 ·
Maintainers usually reply within 1 day
-
`@JsonUnwrapped` value with `EXTERNAL_PROPERTY` type id silently deserialized as `null` (or misleading unknown-property error)Possibly taken @wn1331 claimed this 2 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 55/100
FasterXML/jackson-databind#6421 ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 1-2 days Newbie friendliness 35/100
FasterXML/jackson-databind#6418 · 2 comments ·
Maintainers usually reply within 1 day
-
`StdConvertingSerializer` looks up and contextualizes delegate serializer for every value when converter output type is dynamicPossibly taken @wn1331 claimed this 2 days ago. Open3.x
Difficulty 4/5 3-5 days Newbie friendliness 25/100
FasterXML/jackson-databind#6395 ·
Maintainers usually reply within 1 day
All issues in FasterXML/jackson-databind
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
johanhaleby/occurrent#1505 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
finos/fluxnova-bpm-platform#387 ·
Maintainers usually reply within 4 days
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
-
Difficulty 2/5 Under an hour Newbie friendliness 84/100
cpp-best-practices/project_validator#251 ·
Maintainers usually reply within 1 day