Описание
jackson-core: UTF8DataInputJsonParser._reportInvalidToken() missing maxErrorTokenLength limit -> unbounded StringBuilder growth (DoS)
Status
FULLY REPRODUCED. A malformed token fed through createParser(DataInput) produced a
20,000,109-character exception message from a 20-million-character attacker payload, while the
identical payload fed through createParser(InputStream) produced a correctly bounded
367-character message.
Affected Component / Version
- Package:
com.fasterxml.jackson.core:jackson-core - Confirmed against:
jackson-core-2.20.2 - Affected file:
src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java(_reportInvalidToken(int, String, String), lines ~2763-2780 in the 2.20.2 tree)
Technical Analysis
UTF8DataInputJsonParser._reportInvalidToken() builds the offending-token description for its
exception message by appending identifier characters one at a time to a bare StringBuilder:
There is no check against ErrorReportConfiguration.getMaxErrorTokenLength() (default 256)
anywhere in this loop. By contrast, the sibling UTF8StreamJsonParser implementation of the
same logic does enforce it:
ReaderBasedJsonParser and NonBlockingUtf8JsonParserBase also correctly enforce the limit —
this is a defect isolated to the DataInput-backed implementation specifically, confirmed by
direct comparison of all four parser implementations in this tree.
This path is additionally left with no fallback control: because of [core#1570]-related
logic in JsonFactory, configuring maxDocumentLength causes DataInput-sourced parser
creation to be rejected outright, so a document-length backstop cannot coexist with this input
source, and the identifier-character accumulation never passes through
ReadConstrainedTextBuffer, so maxStringLength does not apply either. There is no
configuration an application can set to mitigate this specific path.
Reproduction Procedure
Same clone/build steps as jackson-core_1_...md. Then:
Full PoC Source (poc/PoC6_UnboundedErrorTokenStringBuilder.java)
Captured Evidence (actual run output)
The same 20-million-character malformed token, fed to the two parser variants, produces a
367-character message via the correctly-bounded InputStream path and a 20,000,109-character
message via the vulnerable DataInput path — a difference of roughly 54,500x for identical
input, confirming the missing bound is the sole cause of the difference.
Impact
Any application creating parsers via JsonFactory.createParser(DataInput) over
attacker-supplied input (a fully public, documented API) is exposed to unbounded memory growth
from a single malformed token. Scaling the payload from the 20MB demonstrated here to
gigabytes (well within a typical unbounded request body) would drive the accumulated
StringBuilder — which additionally undergoes byte-to-char expansion and internal doubling —
to consume many times the raw payload size, realistically triggering OutOfMemoryError and
denying service to the whole JVM process. Critically, no available configuration mitigates
this: maxDocumentLength cannot be set for DataInput sources at all, and maxStringLength
does not apply to this code path.
Remediation
- Add the
maxErrorTokenLengthcheck to the append loop inUTF8DataInputJsonParser._reportInvalidToken(), appending"..."and breaking when the limit is reached — mirroring the three other parser implementations exactly. - Add a parameterized regression test across all four parser implementations asserting the
exception message length is bounded by
maxErrorTokenLengthplus a small constant. - Consider extracting this bounded-scan logic into a single shared helper on
ParserMinimalBaseto prevent this class of per-implementation drift recurring.
Ссылки
- https://github.com/FasterXML/jackson-core/security/advisories/GHSA-7hhh-6rmp-j9qf
- https://nvd.nist.gov/vuln/detail/CVE-2026-89425
- https://github.com/FasterXML/jackson-core/pull/1698
- https://github.com/FasterXML/jackson-core/commit/211cf2c5d91abbec38067f37efc1363cd4e88ee3
- https://github.com/FasterXML/jackson-core/releases/tag/jackson-core-2.18.11
- https://github.com/FasterXML/jackson-core/releases/tag/jackson-core-3.2.3
Пакеты
com.fasterxml.jackson.core:jackson-core
>= 2.19.0, <= 2.21.6
2.21.7
com.fasterxml.jackson.core:jackson-core
>= 2.22.0, <= 2.22.2
2.22.3
tools.jackson.core:jackson-core
>= 3.0.0, <= 3.1.6
3.1.7
tools.jackson.core:jackson-core
>= 3.2.0, <= 3.2.2
3.2.3
com.fasterxml.jackson.core:jackson-core
>= 2.8.0, <= 2.18.10
2.18.11
Связанные уязвимости
UTF8DataInputJsonParser._reportInvalidToken() in FasterXML jackson-core builds the offending-token text for its error message by appending Java identifier characters to a StringBuilder in a loop that has no upper bound. Unlike the three sibling parser implementations, including UTF8StreamJsonParser, it never consults ErrorReportConfiguration.getMaxErrorTokenLength() (default 256). A malformed token supplied to a parser created through JsonFactory.createParser(DataInput) is therefore accumulated in full. No StreamReadConstraints setting mitigates this: maxDocumentLength cannot be applied to DataInput sources at all, and maxStringLength does not cover this path because the accumulation bypasses ReadConstrainedTextBuffer. The reporter measured a 20,000,109-character exception message from a 20-million-character malformed token on the DataInput path, against 367 characters for identical input on the InputStream path. Scaling the payload drives the StringBuilder, which also incurs byte-t...
UTF8DataInputJsonParser._reportInvalidToken() in FasterXML jackson-core builds the offending-token text for its error message by appending Java identifier characters to a StringBuilder in a loop that has no upper bound. Unlike the three sibling parser implementations, including UTF8StreamJsonParser, it never consults ErrorReportConfiguration.getMaxErrorTokenLength() (default 256). A malformed token supplied to a parser created through JsonFactory.createParser(DataInput) is therefore accumulated in full. No StreamReadConstraints setting mitigates this: maxDocumentLength cannot be applied to DataInput sources at all, and maxStringLength does not cover this path because the accumulation bypasses ReadConstrainedTextBuffer. The reporter measured a 20,000,109-character exception message from a 20-million-character malformed token on the DataInput path, against 367 characters for identical input on the InputStream path. Scaling the payload drives the StringBuilder, which also incurs byte-t...
UTF8DataInputJsonParser._reportInvalidToken() in FasterXML jackson-core builds the offending-token text for its error message by appending Java identifier characters to a StringBuilder in a loop that has no upper bound. Unlike the three sibling parser implementations, including UTF8StreamJsonParser, it never consults ErrorReportConfiguration.getMaxErrorTokenLength() (default 256). A malformed token supplied to a parser created through JsonFactory.createParser(DataInput) is therefore accumulated in full. No StreamReadConstraints setting mitigates this: maxDocumentLength cannot be applied to DataInput sources at all, and maxStringLength does not cover this path because the accumulation bypasses ReadConstrainedTextBuffer. The reporter measured a 20,000,109-character exception message from a 20-million-character malformed token on the DataInput path, against 367 characters for identical input on the InputStream path. Scaling the payload drives the StringBuilder, which also incurs byte-to-c
UTF8DataInputJsonParser._reportInvalidToken() in FasterXML jackson-cor ...
Уязвимость функции UTF8DataInputJsonParser._reportInvalidToken() библиотеки jackson-core проекта FasterXML, позволяющая нарушителю вызвать отказ в обслуживании