
Dieses Repository bietet eine umfassende Behebung der Sicherheitslücken Denial-of-Service und Ressourcenzuweisung ohne Grenzen oder Drosselung, die in CVE-2025-52999, GHSA-2m67-wjpj-xhg9 und sonatype-2022-6438 gemeldet wurden, bei vollständiger Kompatibilität mit jackson‑core 2.13.5.
Dieser Branch (2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9) enthält eine umfassende Sicherheitsbehebung für Sicherheitslücken im Zusammenhang mit Denial of Service (DoS) und der Zuweisung von Ressourcen ohne Grenzen oder Drosselung, die jackson-core 2.13.5 betreffen. Er führt die StreamReadConstraints-API ein —
abgestimmt auf die in jackson-core 2.15.0 eingeführte API, jedoch erweitert um eine breitere Parser-Abdeckung
und zusätzliche Schutzmaßnahmen gegen Angriffsvektoren — und behebt damit einen Erschöpfungsangriff über die Verschachtelungstiefe
(CVE-2025-52999), die Zuweisung von Ressourcen ohne Grenzen oder Drosselung (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924), eine Umgehung der Begrenzung der Dokumentlänge (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9) sowie einen Erschöpfungsangriff über die Länge numerischer Tokens (Sonatype-2022-6438), während die Kompatibilität mit der öffentlichen API-Oberfläche von jackson-core Version 2.13.5 erhalten bleibt.
| Branch | Behobene Sicherheitslücken |
|---|---|
2.13.5-CVE-2025-52999-sonatype-2022-6438 | CVE-2025-52999, Sonatype-2022-6438, SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 |
2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 | Alle oben genannten + GHSA-2m67-wjpj-xhg9 (Umgehung der Begrenzung der Dokumentlänge) |
Der ursprüngliche Branch (2.13.5-CVE-2025-52999-sonatype-2022-6438) behebt drei Sicherheitslücken
und ist auf dem Remote sasso erhalten. Dieser Branch erweitert ihn um die zusätzliche Behebung von
GHSA-2m67-wjpj-xhg9,
die maxDocumentLength über alle Parser-Pfade hinweg durchsetzt.
| ID | Typ | Schweregrad | CVSS | Upstream-Fix |
|---|---|---|---|---|
| CVE-2025-52999 | Denial of Service — unbegrenzte Verschachtelungstiefe | High | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.15.0 |
| Sonatype-2022-6438 / SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538 | Denial of Service — unbegrenzte Länge numerischer Tokens | High | 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.15.0 |
| SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 | Zuweisung von Ressourcen ohne Grenzen oder Drosselung | High | 8.7 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.18.6, 2.21.1 oder höher. |
| SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 | Zuweisung von Ressourcen ohne Grenzen oder Drosselung — Umgehung der Begrenzung der Dokumentlänge | High | 8.7 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) | jackson-core 2.18.7, 2.21.2 oder höher. |
| Version | CVE-2025-52999 | Sonatype-2022-6438 / SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 |
|---|---|---|---|---|
| 2.13.5 | Verwundbar | Verwundbar | Verwundbar | Verwundbar |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438 | Behoben | Behoben | Behoben | Verwundbar |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 | Behoben | Behoben | Behoben | Behoben |
| 2.14.x | Verwundbar | Verwundbar | Verwundbar | Verwundbar |
| 2.15.x | Behoben | Behoben | Verwundbar | Verwundbar |
| 2.16.x | Behoben | Behoben | Verwundbar | Verwundbar |
| 2.17.x | Behoben | Behoben | Verwundbar | Verwundbar |
| 2.18.6+ | Behoben | Behoben | Behoben | Verwundbar |
| 2.18.7+ | Behoben | Behoben | Behoben | Behoben |
| 2.21.1+ | Behoben | Behoben | Behoben | Verwundbar |
| 2.21.2+ | Behoben | Behoben | Behoben | Behoben |
NVD-Eintrag
| Feld | Wert |
|---|---|
| CVE-ID | CVE-2025-52999 |
| Veröffentlicht | 2025-06-25 |
| Zuletzt geändert | 2025-06-26 |
| Quelle (CNA) | GitHub, Inc. |
| CVSS-v4.0-Score | 8.7 HIGH — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N |
| CWE | CWE-121 — Stack-based Buffer Overflow |
| GitHub-Advisory | GHSA-h46c-h94j-95f3 |
| Upstream-Fix-PR | jackson-core#943 |
Offizielle NVD-Beschreibung
jackson-core enthält die zentralen Low-Level-Abstraktionen für den inkrementellen („Streaming“-)Parser und -Generator, die vom Jackson Data Processor verwendet werden. In Versionen vor 2.15.0 konnte Jackson, wenn ein Benutzer eine Eingabedatei parst, die besonders tief verschachtelte Daten enthält, einen
StackOverflowErrorauslösen, falls die Tiefe besonders groß ist. jackson-core 2.15.0 enthält ein konfigurierbares Limit dafür, wie tief Jackson ein Eingabedokument durchläuft; standardmäßig ist eine zulässige Tiefe von 1.000 festgelegt. jackson-core löst eineStreamConstraintsExceptionaus, wenn das Limit erreicht wird. jackson-databind profitiert ebenfalls von dieser Änderung, da es jackson-core zum Parsen von JSON-Eingaben verwendet. Als Workaround sollten Benutzer das Parsen von Eingabedateien aus nicht vertrauenswürdigen Quellen vermeiden.
Workaround: Vermeiden Sie das Parsen von JSON-Eingaben aus nicht vertrauenswürdigen Quellen, bis die behobene Version bereitgestellt ist.
Grundursache: Vor 2.15.0 legte JsonParser kein Limit dafür fest, wie tief ein JSON-Dokument
verschachtelt sein durfte. Jedes Token für ein Array [ oder ein Objekt { veranlasste JsonReadContext.createChildArrayContext() /
createChildObjectContext() dazu, einen neuen Kontextknoten auf dem Heap zu allokieren und eine Referenz-
kette zu verlängern. Ein Angreifer kann ein Dokument mit Zehntausenden von Verschachtelungsebenen erstellen, wodurch die Java Virtual Machine
ihren Thread-Stack oder Heap-Speicher erschöpft.
Verwundbarer Codepfad:
Dieselbe fehlende Prüfung wird über jede der vier Parser-Implementierungen erreicht:``` JsonParser.nextToken() // common entry point │ ├─ ReaderBasedJsonParser → _parsePunctuationMark() ├─ UTF8StreamJsonParser → _parsePunctuationMark() ├─ UTF8DataInputJsonParser → _parsePunctuationMark() └─ NonBlockingJsonParserBase → _startArrayScope() / _startObjectScope() │ ▼ _parsingContext.createChildArrayContext() // '[' encountered _parsingContext.createChildObjectContext() // '{' encountered ⚠ no depth check — context chain grows without bound
Alle vier `JsonParser`-Implementierungen weisen diesen Fehler auf. Der Angriff lässt sich durch
jede von ihnen gleichermaßen ausnutzen – egal ob die Eingabe über `InputStream`, `Reader`, `DataInput` oder die asynchrone
nicht-blockierende Feeder-API erfolgt.
**Angriffsvektoren:**
| # | Strategie | Beispiel-Payload | Tiefenzuwachs | Betroffene Parser |
|---|----------|----------------|-----------------|------------------|
| 1 | Array-Verschachtelung | `[[[…]]]` — 1.001 aufeinanderfolgende `[`-Tokens | +1 pro `[` | Alle vier |
| 2 | Objekt-Verschachtelung | `{"k":{"k":{…}}}` — 1.001 aufeinanderfolgende `{`-Tokens | +1 pro `{` | Alle vier |
| 3 | Abwechselnde Verschachtelung | `[{"k":[{"k":…}]}]` — 1.001 gemischte `[`/`{`-Tokens | +1 pro `[` oder `{` | Alle vier |
Wichtige Beobachtungen:
- **Array-Verschachtelung – minimaler Overhead:** Es werden nur `[`- und `]`-Tokens benötigt; keine Schlüssel, Werte oder Leerzeichen. Eine 2.002-Byte-Payload mit 1.001 Klammerpaaren reicht aus, um das Standardlimit von 1.000 zu überschreiten.
- **Objekt-Verschachtelung – verstärkter Heap-Druck:** Jedes `{` allokiert zusätzlich einen `JsonReadContext`-Schlüsselslot zum Knoten der Tiefenkette, was den Speicherverbrauch bei extremen Tiefen weiter erhöht.
- **Abwechselnde Verschachtelung – Umgehung von Web Application Firewalls (WAF):** Musterbasierte Abwehrmaßnahmen, die wiederholte `[[[`- oder `{{{`-Sequenzen erkennen, sind gegenüber abwechselnder Token-Verschachtelung blind; der Tiefenzähler des Parsers erhöht sich unabhängig vom Tokentyp identisch.
- **Nicht-blockierender Feeder – gleiche Payload, andere Angriffsfläche:** Alle drei Verschachtelungsstrategien sind gleichermaßen über `NonBlockingJsonParser` und die `ByteArrayFeeder`-API ausnutzbar. Das Dokument kann in beliebig kleinen Teilen geliefert werden; `NonBlockingJsonParserBase._startArrayScope()` / `_startObjectScope()` erhöhen den Tiefenzähler bei jedem kontextöffnenden Token, unabhängig davon, wie die Bytes ankommen, und akkumulieren die Tiefe über mehrere `feedInput()`-Aufrufe hinweg.
Alle drei Verschachtelungsstrategien sind über jede der vier `JsonParser`-Implementierungen erreichbar.
Mit 2.13.5 gelingt das Parsen stillschweigend; mit dieser Behebung werfen alle drei Vektoren
`StreamConstraintsException: Depth (1001) exceeds the maximum allowed nesting depth (1000)`.
---
### Sonatype-2022-6438 — Unbegrenzte numerische Token-Länge
**Sicherheitsdetails**
| Feld | Wert |
|-------|-------|
| Sonatype-ID | [sonatype-2022-6438](https://guide.sonatype.com/vulnerability/sonatype-2022-6438/security-details) |
| Beschreibung | jackson-core — Denial of Service (DoS) |
| Veröffentlicht | 2022-12-07 |
| Quelle | Sonatype |
| CVSS-v3.1-Score | **7.5 HIGH** — `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` |
| CWE | [CWE-770](https://cwe.mitre.org/data/definitions/770.html) — Zuweisung von Ressourcen ohne Begrenzung oder Drosselung |
| EPSS-Score | 0% |
| Upstream-Fix-PRs | [jackson-core#827](https://github.com/FasterXML/jackson-core/pull/827), [jackson-core#846](https://github.com/FasterXML/jackson-core/pull/846) |
**Verwundbare Methoden (wie von Sonatype identifiziert)**
| Methode | Anmerkungen |
|--------|-------|
| `com.fasterxml.jackson.core.base.ParserBase._parseSlowInt(I)V` | Verwundbarer Parameter: Index 0 |
| `com.fasterxml.jackson.core.base.ParserBase.convertNumberToBigDecimal()V` | |
| `com.fasterxml.jackson.core.base.ParserMinimalBase.getValueAsDouble(D)D` | Verwundbarer Parameter: Index 0 |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDecimal()` | Gibt `BigDecimal` zurück |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDouble(Z)D` | |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsFloat(Z)F` | |
Jede dieser Methoden verarbeitet den rohen Ziffernpuffer, ohne vorher dessen Länge zu validieren. Die Übergabe eines
ausreichend langen numerischen Tokens führt zu unbegrenzter Heap-Allokation und CPU-Erschöpfung, wenn die JVM
versucht, aus den unbeschränkten Pufferinhalten einen `BigInteger` oder `BigDecimal` zu instanziieren.
---
**Grundursache:** Vor 2.15.0 legte `JsonParser` keine Begrenzung für die Bytelänge von Integer-Tokens, Tokens in wissenschaftlicher Notation, einfachen Gleitkomma-Tokens oder zusammengesetzten Gleitkomma-Tokens fest. Wenn ein Parser seinen internen `_textBuffer` zum Sammeln von Ziffern allokiert, kann ein Angreifer eine Zahl mit Millionen von Ziffern bereitstellen, wodurch der Puffer unbegrenzt wächst und schließlich den Heap-Speicher erschöpft.
**Verwundbare Codepfade:**
Es gibt zwei strukturell unterschiedliche verwundbare Pfade – einen, der den drei synchronen Parsern gemeinsam ist,
und einen zweiten unabhängigen Pfad durch den asynchronen Parser.
**Pfad A – synchrone Parser** (drei Implementierungen, eine gemeinsame Senke):```
JsonParser.nextToken() // common entry point
│
├─ ReaderBasedJsonParser ─┐
├─ UTF8StreamJsonParser ├─→ ParserBase.resetInt() / resetFloat()
└─ UTF8DataInputJsonParser ─┘ │
▼
_textBuffer.contentsAsString()
⚠ no length check — buffer grows without bound
Pfad B — asynchroner Parser (unabhängiger Codepfad, separat ungeschützt):``` NonBlockingJsonParser.nextToken() │ ├─ _startPositiveNumber() / _startNegativeNumber() // integer paths ├─ _finishNumberIntegralPart() ├─ _startFloat() // floating-point paths ├─ _finishFloatFraction() └─ _finishFloatExponent() │ ▼ writes _intLength / _fractLength / _expLength directly ⚠ never calls ParserBase.resetInt() / resetFloat() ⚠ constraint validation bypassed entirely
The non-blocking (async) parser is a particularly notable attack surface: it contains its own
digit-accumulation loops in `_startPositiveNumber`, `_startNegativeNumber`,
`_finishNumberIntegralPart`, `_startFloat`, `_finishFloatFraction`, and `_finishFloatExponent`
that set `_intLength` / `_fractLength` / `_expLength` directly without ever going through
`ParserBase.resetInt()` or `resetFloat()`. This means the upstream PR #827 fix (which added
validation only to `ParserBase`) **left `NonBlockingJsonParser` completely unprotected**.
This was discovered during extended attack-surface analysis and remediated in this branch.
**Angriffsvektoren:**
| # | Token-Form | Beispiel-Payload | `intLen` | `fractLen` | `expLen` | Gesamt | Beschränkung |
|---|------------|----------------|----------|------------|----------|-------|------------|
| 1 | Ganzzahl | `999…` — 199.999 aufeinanderfolgende Ziffern | 199.999 | 0 | 0 | 199.999 | `validateIntegerLength` |
| 2 | Dezimalbruch | `0.999…` — einstellige Ganzzahl, 1.001-stelliger Bruchteil | 1 | 1.001 | 0 | 1.002 | `validateFPLength` |
| 3 | Wissenschaftliche Notation | `1e999…` — einstellige Mantisse, 1.001-stelliger Exponent | 1 | 0 | 1.001 | 1.002 | `validateFPLength` |
| 4 | Zusammengesetzte Gleitkommazahl | `0.999…e999…` — 500-stelliger Bruchteil, 500-stelliger Exponent | 1 | 500 | 500 | 1.001 | `validateFPLength` |
Wichtige Beobachtungen:
- **Ganzzahl — Vorzeichenzeichen ist keine Ziffer:** Das führende `-` ist von der Ziffern-Akkumulation ausgeschlossen; `-999…` und `999…` erzeugen identische `intLen`-Werte und lösen die Beschränkung bei derselben Schwelle aus.
- **Dezimalbruch — kurze Ganzzahl, unbegrenzter Bruchteil:** Der ganzzahlige Teil kann eine einzelne Ziffer (0) sein, während der Bruchteil unbegrenzt wächst; der Dezimalpunkt selbst ist von der Zählung ausgeschlossen.
- **Wissenschaftliche Notation — kompakt und dennoch katastrophal:** Bei ~1.004 Byte ist dies das kleinste wirksame Payload; es erzwingt die Instanziierung eines `BigDecimal` mit Skala ±10^1001, was eine unbegrenzte Zwischen-Heap-Allokation erfordert, ungeachtet der geringen Größe des Tokens.
- **Zusammengesetzte Gleitkommazahl — Umgehung durch geteilte Grenzwerte:** Bei `fractLen = 500` und `expLen = 500` erreicht keine Komponente für sich genommen die 1.000-Ziffern-Schwelle. Die vereinheitlichte Prüfung `validateFPLength(intLen + fractLen + expLen)` ist die einzige Verteidigung, die diese Lücke schließt.
- **Nicht-blockierender Parser — unabhängiger Bypass:** Alle vier oben genannten Token-Formen sind unabhängig über `NonBlockingJsonParser` mittels `ByteArrayFeeder` ausnutzbar. Im Gegensatz zu den synchronen Parsern akkumuliert `NonBlockingJsonParser` Ziffern in privaten Schleifen (`_startPositiveNumber`, `_finishNumberIntegralPart`, `_startFloat`, `_finishFloatFraction`, `_finishFloatExponent`), die `_intLength` / `_fractLength` / `_expLength` direkt schreiben und `ParserBase.resetInt()` sowie `resetFloat()` vollständig umgehen. Der Upstream-PR #827 — der nur `ParserBase` modifizierte — ließ diesen Parser daher vollständig ungeschützt, was sechs unabhängige Patches an den Aufrufstellen in dieser Behebung erforderte.
Alle vier Token-Formen und der nicht-blockierende Bypass werden zum Zeitpunkt der Tokenisierung abgewiesen — bevor ein `BigDecimal` oder `BigInteger`
konstruiert wird — durch `validateIntegerLength` und `validateFPLength` in `ParserBase` (synchronen
Paser) und an sechs dedizierten Aufrufstellen in `NonBlockingJsonParser` (asynchroner Parser). Mit 2.13.5 werden alle vier Token-Formen stillschweigend akzeptiert; mit dieser Behebung wirft jeder
Parser `StreamConstraintsException: Number length (N) exceeds the maximum length (1000)`.
> **Hinweis zu `UTF8DataInputJsonParser` mit großen Payloads:** Der DataInput-Parser hat eine
> bereits bestehende interne Puffergrenze von 65 536 Byte ([jackson-core#493](https://github.com/FasterXML/jackson-core/issues/493)).
> Dokumente, die diese Größe überschreiten (z. B. 199.999-stellige PoC-Payloads ≈ 200 KB), lösen eine
> `ArrayIndexOutOfBoundsException` aus, bevor die Längenbeschränkung greifen kann. Der Schutz der Zahlenlänge
> für `UTF8DataInputJsonParser` wird daher mit kürzeren Payloads
> (≤ 1.001 Ziffern) verifiziert, bei denen der Fehler weiterhin reproduzierbar ist.
---
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 — Umgehung der Dokumentlängen-Beschränkung
**Sicherheitsdetails**
| Feld | Wert |
|-------|-------|
| Snyk ID | [SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551](https://security.snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551) |
| GitHub Advisory | [GHSA-2m67-wjpj-xhg9](https://github.com/FasterXML/jackson-core/security/advisories/GHSA-2m67-wjpj-xhg9) |
| Beschreibung | Zuweisung von Ressourcen ohne Grenzen oder Drosselung |
| Offengelegt | 2026-04-04 |
| CVSS v4.0-Score | **8.7 HOCH** |
| CWE | [CWE-770](https://cwe.mitre.org/data/definitions/770.html) — Zuweisung von Ressourcen ohne Grenzen oder Drosselung |
| Betroffene Versionen | [2.8.0, 2.21.2) |
| Upstream-Fix | jackson-core 2.18.7, 2.21.2 oder höher |
| Fix-Commits | [74c9ee25](https://github.com/FasterXML/jackson-core/commit/74c9ee25) (3.x), [7ce3622f](https://github.com/FasterXML/jackson-core/commit/7ce3622f) (2.18.x) |
**Grundursache:** Selbst wenn `StreamReadConstraints.maxDocumentLength` konfiguriert ist, erzwingen Versionen vor
2.18.7 / 2.21.2 das Dokumentlängenlimit in keinem Parser-Pfad. Die blockierenden Parser
(`UTF8StreamJsonParser`, `ReaderBasedJsonParser`) validieren niemals die kumulativ gelesenen Bytes gegen das
konfigurierte Limit. Der asynchrone Parser (`NonBlockingJsonParser`) besitzt in `feedInput()` ebenfalls keine Validierung.
Der `UTF8DataInputJsonParser` hat keinen Mechanismus, um die insgesamt verbrauchten Bytes zu verfolgen.
In jackson-core 2.13.5 gab es `maxDocumentLength` überhaupt nicht, was bedeutet, dass es keine Möglichkeit gab, die Dokumentgröße zu begrenzen. Diese Behebung führt das Feld `maxDocumentLength` in `StreamReadConstraints` ein und setzt es in allen Parser-Pfaden durch.
**Verwundbare Parser-Pfade:**
| Parser | Pfad | Durchsetzungspunkt |
|--------|------|-------------------|
| `UTF8StreamJsonParser` | `InputStream` → `_loadMore()` | Validiert `_currInputProcessed + count` nach jedem Puffer-Nachladen und bei EOF |
| `ReaderBasedJsonParser` | `Reader` → `_loadMore()` | Gleiches Muster wie `UTF8StreamJsonParser` |
| `NonBlockingJsonParser` | `feedInput()` | Validiert `_currInputProcessed + _origBufferLen` nach jedem Eingabeblock |
| `UTF8DataInputJsonParser` | `DataInput` | Fail-fast: wirft `StreamConstraintsException`, falls `maxDocumentLength` konfiguriert ist |
**Angriffsszenario:** Ein Angreifer sendet ein gültiges, aber übermäßig großes JSON-Dokument (z. B. eine tief verschachtelte
oder stark repetitive Struktur über Gigabytes) an einen Dienst, der `maxDocumentLength` konfiguriert hat, um
Ressourcenerschöpfung zu verhindern. Ohne Durchsetzung verarbeitet der Parser das gesamte Dokument ungeachtet des
konfigurierten Limits und verbraucht unbegrenzten Speicher und CPU.
---
## Sicherheitsauswirkung
Alle vier Schwachstellen sind remote ausnutzbar, ohne dass eine Authentifizierung erforderlich ist:
- Jeder Dienst, der angreiferkontrolliertes JSON über einen `JsonParser` parst (direkt oder über
Jackson Databind, das `jackson-core` kapselt), ist gefährdet.
- Der Angriff ist trivial konstruierbar — wenige hundert Byte JSON genügen, um unbegrenzten
Ressourcenverbrauch auszulösen.
- Es gibt keine Auswirkungen auf Vertraulichkeit oder Integrität; Verfügbarkeit (DoS) ist die einzige Auswirkungsklasse.
---
## Details zur Behebung
### Offizielles Upgrade (Empfohlen)
Führen Sie ein Upgrade auf **jackson-core 2.15.4** oder eine beliebige spätere stabile Version durch. Alle 2.15.x- und 2.16+ Versionen enthalten die `StreamReadConstraints`-API mit sicheren Standardwerten.```xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.4</version>
</dependency>
Falls ein Upgrade auf eine neuere Version nicht sofort möglich ist, wendet dieser Branch einen umfassenden
Fix auf die 2.13.5-Codebasis an. Er führt StreamReadConstraints und StreamConstraintsException
mit einer zu 2.15.x kompatiblen API ein, bindet die Constraints in alle vier JsonParser-Implementierungen
ein — einschließlich des nicht-blockierenden Parsers, der vom Upstream-Fix nicht abgedeckt war — und erzwingt
die folgenden Standardlimits:
| Einschränkung | Standardlimit |
|---|---|
| Maximale Verschachtelungstiefe | 1.000 |
| Maximale Länge numerischer Tokens | 1.000 Ziffern |
| Maximale Länge von String-Tokens | 1.000.000 Zeichen |
Maximale Skalengröße von BigDecimal | 100.000 |
StreamReadConstraints (356 Zeilen)Unveränderliches Wertobjekt, das die Stream-Read-Limits pro Parser enthält, erstellt über einen Builder:```java // Default constraints (used by all parsers unless overridden) StreamReadConstraints defaults = StreamReadConstraints.defaults();
// Custom constraints StreamReadConstraints custom = StreamReadConstraints.builder() .maxNestingDepth(500) .maxNumberLength(2000) .maxStringLength(5000000) .build();
Validierungsmethoden (von Parsern bei jedem neuen Token aufgerufen):```java
void validateNestingDepth(int depth) throws StreamConstraintsException;
void validateIntegerLength(int length) throws StreamConstraintsException;
void validateFPLength(int length) throws StreamConstraintsException;
void validateStringLength(int length) throws StreamConstraintsException;
void validateBigIntegerScale(int scale) throws StreamConstraintsException;
Exception message format:
"Depth (%d) exceeds the maximum allowed nesting depth (%d)""Number length (%d) exceeds the maximum length (%d)""String length (%d) exceeds the maximum length (%d)""BigDecimal scale (%d) magnitude exceeds maximum allowed (%d)"StreamConstraintsException (52 Zeilen)Erweitert StreamReadException (selbst eine JsonProcessingException). Wird ausschließlich von
StreamReadConstraints-Validierungsmethoden ausgelöst.
base/ParserBase.javaFeld _streamReadConstraints hinzugefügt (Standardwert: StreamReadConstraints.defaults()).
resetInt() und resetFloat() validieren jetzt die Länge des numerischen Tokens unmittelbar nachdem das Token
akkumuliert wurde:```java
protected void resetInt(boolean negative, int intLen) throws IOException {
_streamReadConstraints.validateIntegerLength(intLen);
// … existing reset logic …
}
protected void resetFloat(boolean negative, int intLen, int decLen, int expLen) throws IOException { int totalLen = intLen + decLen + expLen; _streamReadConstraints.validateFPLength(totalLen); // … existing reset logic … }
Neue Hilfsmethoden `_createChildArrayContext()` und `_createChildObjectContext()` kapseln die Kontexterstellung mit einer Tiefenprüfung:```java
protected JsonReadContext _createChildArrayContext(int line, int col) throws IOException {
_streamReadConstraints.validateNestingDepth(_parsingContext.getNestingDepth() + 1);
return _parsingContext.createChildArrayContext(line, col);
}
Alle vier Parser rufen jetzt die neuen Hilfsmethoden zur Tiefenprüfung auf, anstatt direkt auf
_parsingContext.createChild*() zuzugreifen:
json/ReaderBasedJsonParser.javajson/UTF8StreamJsonParser.javajson/UTF8DataInputJsonParser.javajson/async/NonBlockingJsonParserBase.javaJsonStreamContext.javagetNestingDepth() hinzugefügt, das die Elternkette durchläuft, um die absolute Tiefe zu berechnen:```java
public int getNestingDepth() {
int depth = 0;
JsonStreamContext curr = this;
while ((curr = curr.getParent()) != null) {
depth++;
}
return depth;
}
#### `json/JsonReadContext.java`
Die Signaturen von `createChildArrayContext()` und `createChildObjectContext()` wurden aktualisiert, um
`throws IOException` weiterzugeben.
#### `json/async/NonBlockingJsonParser.java` (nur Sonatype-2022-6438)
Dies ist der wesentliche zusätzliche Fix, der über den Umfang des Upstream-PR #827 hinaus entdeckt wurde. Sechs
Stellen zum Abschluss von Zahlen, die `ParserBase.resetInt()` umgingen, wurden einzeln behoben:
| Methode | Hinzugefügte Validierung |
|--------|------------------|
| `_startPositiveNumber()` — Fast-Path-Rückgabe | `validateIntegerLength(_intLength)` |
| `_startNegativeNumber()` — Fast-Path-Rückgabe | `validateIntegerLength(_intLength)` |
| `_finishNumberIntegralPart()` — endgültige Rückgabe | `validateIntegerLength(_intLength)` |
| `_finishToken()` Fall `MINOR_NUMBER_INTEGER_DIGITS` | `validateIntegerLength(_intLength)` |
| `_startFloat()` / `_finishFloatFraction()` / `_finishFloatExponent()` endgültige Rückgaben | `validateFPLength(_intLength + _fractLength + _expLength)` |
| `_finishToken()` Fälle `MINOR_NUMBER_FRACTION_DIGITS` / `MINOR_NUMBER_EXPONENT_DIGITS` | `validateFPLength(...)` |
Alle Stellen sind erreichbar: Die Fast-Path-Methoden behandeln den Fall, dass die vollständige Zahl in
einem einzigen `feedInput()`-Aufruf verfügbar ist; die `MINOR_*`-Resume-State-Fälle behandeln den Chunk-Fall,
bei dem Zahlziffern über mehrere Aufrufe eintreffen. Beide Pfade müssen abgesichert werden.
---
## Testabdeckung
### CVE-2025-52999 — Tests zur Verschachtelungstiefe
| Testdatei | Testmethode | Parser-Modi | Abdeckung |
|-----------|-------------|-------------|--------|
| `read/ArrayParsingTest.java` | `testCVE_2025_52999` | stream | Rekursive Traversierung, die reale App-Nutzung simuliert; bestätigt `StreamConstraintsException` bei Tiefe 1001 (behoben) und `StackOverflowError` bei Tiefe 20.000 (2.13.5) |
| `read/ArrayParsingTest.java` | `testCustomNestingDepthConstraint` | direkte API | `StreamReadConstraints.builder().maxNestingDepth(5)` — Accessor, am Limit bestanden, über Limit wirft Exception |
| `read/ArrayParsingTest.java` | `testObjectNestingDepthLimit` | stream | Objekte genau am Limit 1000 (bestanden), Objekte mit 1001 Ebenen werfen Exception |
| `read/ArrayParsingTest.java` | `testDataInputParserDepthLimit` | `UTF8DataInputJsonParser` | `UTF8DataInputJsonParser` erzwingt das 1001-Ebenen-Tiefenlimit |
| `read/ArrayParsingTest.java` | `testNonBlockingParserDepthLimit` | non-blocking | `NonBlockingJsonParser` erzwingt das 1001-Ebenen-Tiefenlimit |
### Sonatype-2022-6438 — Tests zur Zahlenlänge
| Testdatei | Testmethode | Parser-Modi | Abdeckung |
|-----------|-------------|-------------|--------|
| `read/NumberOverflowTest.java` | `testSonatype_2022_6438` | `ALL_MODES` | Ganzzahl am Limit (bestanden), Ganzzahl über Limit (fehlgeschlagen), Gleitkommazahl am Limit (bestanden), Gleitkommazahl über Limit (fehlgeschlagen), Exponent in wissenschaftlicher Notation am Limit (bestanden), Exponent über Limit (fehlgeschlagen) — alle vier Parser |
| `read/NumberOverflowTest.java` | `testNonBlockingParserNumericLengthLimit` | non-blocking | `NonBlockingJsonParser` erzwingt die Zahlenlänge |
| `read/NumberOverflowTest.java` | `testNonBlockingParserExponentLengthLimit` | non-blocking | `NonBlockingJsonParser` erzwingt die Länge des Exponenten in wissenschaftlicher Notation über `validateFPLength` |
| `read/NumberOverflowTest.java` | `testCustomMaxNumberLengthConstraint` | direkte API | `StreamReadConstraints.builder().maxNumberLength(5)` — Accessor, am Limit bestanden, über Limit wirft Exception für `validateIntegerLength()` und `validateFPLength()`, Format der Fehlermeldung |
> **Legende der Parser-Modi:**
> - `ALL_STREAMING_MODES` = `UTF8StreamJsonParser` (stream), `UTF8StreamJsonParser` (gedrosselt), `ReaderBasedJsonParser`
> - `ALL_MODES` = die obigen drei + `UTF8DataInputJsonParser`
> - `non-blocking` = `NonBlockingJsonParser` über `ByteArrayFeeder`
> - `stream` = `UTF8StreamJsonParser` (Standard `JsonFactory.createParser`)
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 — Tests zur Dokumentlänge
| Testdatei | Testmethode | Parser-Modi | Abdeckung |
|-----------|-------------|-------------|--------|
| `constraints/LargeDocReadTest.java` | `testInputStreamExceedsLimit` | `UTF8StreamJsonParser` | InputStream-Parser erzwingt `maxDocumentLength` — 20K-Dokument mit 10K-Limit abgelehnt |
| `constraints/LargeDocReadTest.java` | `testInputStreamUnderLimitSucceeds` | `UTF8StreamJsonParser` | InputStream-Parser akzeptiert Dokument innerhalb des Limits |
| `constraints/LargeDocReadTest.java` | `testReaderExceedsLimit` | `ReaderBasedJsonParser` | Reader-Parser erzwingt `maxDocumentLength` — 20K-Dokument mit 10K-Limit abgelehnt |
| `constraints/LargeDocReadTest.java` | `testReaderUnderLimitSucceeds` | `ReaderBasedJsonParser` | Reader-Parser akzeptiert Dokument innerhalb des Limits |
| `constraints/LargeDocReadTest.java` | `testAsyncExceedsLimit` | `NonBlockingJsonParser` | Async-Parser erzwingt `maxDocumentLength` — 20K-Dokument in `feedInput()` abgelehnt |
| `constraints/LargeDocReadTest.java` | `testAsyncUnderLimitSucceeds` | `NonBlockingJsonParser` | Async-Parser akzeptiert Dokument innerhalb des Limits |
| `constraints/LargeDocReadTest.java` | `testDataInputWithDocLengthLimitFails` | `UTF8DataInputJsonParser` | DataInput-Parser schlägt schnell fehl, wenn `maxDocumentLength` konfiguriert ist |
| `constraints/LargeDocReadTest.java` | `testDataInputWithoutDocLengthLimitWorks` | `UTF8DataInputJsonParser` | DataInput-Parser funktioniert normal ohne konfiguriertes `maxDocumentLength` |
| `constraints/LargeDocReadTest.java` | `testDefaultFactoryNoLimit` | `UTF8StreamJsonParser` | Standard-Factory (ohne Limit) akzeptiert große Dokumente |
---
## Ergebnisse der vollständigen Testsuite```
Tests run: 957, Failures: 0, Errors: 0, Skipped: 0
Alle 957 Tests bestehen auf dem behobenen Build. Aufschlüsselung der neu hinzugefügten Sicherheitstests:
| Test Datei | Neue / Erweiterte Methoden |
|---|---|
read/ArrayParsingTest.java | testCVE_2025_52999, testCustomNestingDepthConstraint, testObjectNestingDepthLimit, testDataInputParserDepthLimit, testNonBlockingParserDepthLimit |
read/NumberOverflowTest.java | testSonatype_2022_6438 (erweitert um Exponentenfälle), testNonBlockingParserNumericLengthLimit, testCustomMaxNumberLengthConstraint, testNonBlockingParserExponentLengthLimit |
constraints/LargeDocReadTest.java | testInputStreamExceedsLimit, testInputStreamUnderLimitSucceeds, testReaderExceedsLimit, testReaderUnderLimitSucceeds, testAsyncExceedsLimit, testAsyncUnderLimitSucceeds, testDataInputWithDocLengthLimitFails, testDataInputWithoutDocLengthLimitWorks, testDefaultFactoryNoLimit |
Build-Befehl:```bash ./mvnw test
---
## Validierungsergebnisse
### Regressionstest gegen jackson-core 2.13.5
Die CVE-Testmethoden wurden so entworfen, dass sie auf der 2.13.5-Codebasis **fehlschlagen** und im behobenen Build **bestehen**.
**`NumberOverflowTest#testSonatype_2022_6438`** gegen 2.13.5:```
FAIL — Sonatype-2022-6438 VULNERABILITY PRESENT: parser returned VALUE_NUMBER_INT
for a 1001-digit integer — number length limit is not enforced
ArrayParsingTest#testCVE_2025_52999 gegen 2.13.5:```
FAIL — CVE-2025-52999 VULNERABILITY PRESENT: StackOverflowError after 20000 nesting
levels — parser enforces no depth limit (2.13.5)
**Beide Tests am behobenen Build: PASS.**
---
## Proof of Concept
### CVE-2025-52999 — Verschachtelungstiefe DoS```java
// Build a 1001-level nested array document (just over the limit)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1001; i++) sb.append('[');
for (int i = 0; i < 1001; i++) sb.append(']');
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(sb.toString());
try {
while (parser.nextToken() != null) { } // ← throws on 1001st '['
System.err.println("VULNERABLE: no exception thrown");
} catch (StreamConstraintsException e) {
System.out.println("REMEDIATED: " + e.getMessage());
// Depth (1001) exceeds the maximum allowed nesting depth (1000)
} finally {
parser.close();
}
Alle vier Token-Formen lösen validateFPLength / validateIntegerLength aus, bevor eine
BigDecimal- / BigInteger-Konvertierung versucht wird.```java
JsonFactory factory = new JsonFactory();
// ── 1. Long integer ────────────────────────────────────────────────────────── String longInt = "9".repeat(1001); // 1001-digit integer // Negative form works identically: "-" + "9".repeat(1001)
// ── 2. Long fractional part (floating-point) ───────────────────────────────── // intLen=1, fractLen=1001, total=1002 String longFloat = "0." + "9".repeat(1001);
// ── 3. Long exponent / scientific notation ─────────────────────────────────── // intLen=1, fractLen=0, expLen=1001, total=1002 — only 1,004 bytes on the wire String longExp = "1e" + "9".repeat(1001);
// ── 4. Combined fractional + exponent ──────────────────────────────────────── // intLen=1, fractLen=500, expLen=500, total=1001 — neither part alone is over the limit String combined = "0." + "9".repeat(500) + "e" + "9".repeat(500);
for (String payload : new String[]{ longInt, longFloat, longExp, combined }) { JsonParser parser = factory.createParser("[" + payload + "]"); try { parser.nextToken(); // START_ARRAY parser.nextToken(); // ← throws on the number token System.err.println("VULNERABLE: " + payload.substring(0, 20) + "…"); } catch (StreamConstraintsException e) { System.out.println("REMEDIATED: " + e.getMessage()); // Number length (N) exceeds the maximum length (1000) } finally { parser.close(); } }
---
## Migrationsanleitung
### Option 1: Upgrade auf jackson-core 2.15.4+ (Empfohlen)```xml
<!-- Maven -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.4</version>
</dependency>
<!-- Or with Jackson BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.15.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Mit 2.15+ kannst du die Grenzwerte auch zur Laufzeit anpassen, wenn deine Anwendung legitimerweise tiefere Verschachtelung oder längere Zahlen benötigt:```java JsonFactory factory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(2000) .maxNumberLength(10000) .maxDocumentLength(50_000_000L) .build()) .build();
### Option 2: Diese Sicherheitsbehebung anwenden```bash
git clone https://github.com/sassoftware/jackson-core.git
cd jackson-core
git checkout 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9
./mvnw install -DskipTests
Aktualisieren Sie dann die Abhängigkeit Ihres Projekts, um das lokal installierte Artefakt 2.13.5-SNAPSHOT zu verwenden, oder stellen Sie es in Ihrem internen Artefakt-Repository bereit.
| Datei | Änderungsart | Geänderte Zeilen | Beschreibung |
|---|---|---|---|
src/main/java/.../StreamReadConstraints.java | Neu | +356 | Constraint-Konfiguration + 5 Validierungsmethoden |
src/main/java/.../exc/StreamConstraintsException.java | Neu | +52 | Ausnahmetyp für Constraint-Verstöße |
src/main/java/.../base/ParserBase.java | Geändert | +44 | Tiefen-/Längen-Hooks in Reset- und Kontext-Hilfsmethoden |
src/main/java/.../json/JsonReadContext.java | Geändert | +6 | Weitergabe von throws IOException |
src/main/java/.../json/ReaderBasedJsonParser.java | Geändert | +30 | Tiefenprüfende _createChild*-Hilfsmethoden verwenden |
src/main/java/.../json/UTF8StreamJsonParser.java | Geändert | +26 | Tiefenprüfende _createChild*-Hilfsmethoden verwenden |
src/main/java/.../json/UTF8DataInputJsonParser.java | Geändert | +26 | Tiefenprüfende _createChild*-Hilfsmethoden verwenden |
src/main/java/.../json/async/NonBlockingJsonParserBase.java | Geändert | +4 | Tiefenprüfende _createChild*-Hilfsmethoden verwenden |
src/main/java/.../json/async/NonBlockingJsonParser.java | Geändert | +9 | NEU — validateIntegerLength / validateFPLength an 6 Stellen zum Abschluss von Zahlen; validateDocumentLength in feedInput() |
src/main/java/.../JsonStreamContext.java | Geändert | +20 | getNestingDepth() hinzugefügt |
src/main/java/.../TSFBuilder.java | Geändert | +15 | Feld _streamReadConstraints und Setter streamReadConstraints() hinzugefügt |
Gesamt: 16 Dateien geändert, 1.606 Einfügungen (laut git diff jackson-core-2.13.5 --stat).
StreamReadConstraints-API (2.15-Javadoc): https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.15.4/com/fasterxml/jackson/core/StreamReadConstraints.htmlJede Anwendung, die:
jackson-databind)ist anfällig für beide Angriffe.
Auch nach der Behebung sollten Sie Folgendes berücksichtigen:
maxRequestSize in Servlet-Containern),
um extrem große Anforderungstexte abzulehnen, bevor der Parser aufgerufen wird.StreamReadConstraints, wenn Ihre Anwendung legitimerweise größere oder tiefere
Dokumente benötigt – passen Sie die Grenzwerte an das für Ihren Anwendungsfall erforderliche Minimum an.| Dimension | Anforderung |
|---|---|
| Build-JDK | Java 8 (JDK 1.8) oder höher – dieser Zweig erfordert Java 8+ für Build und Tests |
| Minimale Laufzeit-JRE | Java 8 oder höher |
| Maven | 3.6.3 oder höher (der gebündelte Wrapper ./mvnw erfüllt dies automatisch) |
Hinweis: Die ursprüngliche jackson-core 2.13.5-Version zielte auf Java 6 (
-source 1.6 -target 1.6). In diesem Sicherheitszweig ist Java 8 oder höher sowohl für Build als auch Laufzeit erforderlich. Es wird keine öffentliche API-Oberfläche von Jackson 2.13 geändert; nur JDK-6/7-Laufzeiten verlieren die Kompatibilität aufgrund der Maven- und JDK-Anforderungen.
| Komponente | Version |
|---|---|
| Basis-Tag | jackson-core-2.13.5 |
| Branch | 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 |
| Build-Tool | Maven (Wrapper: ./mvnw) |
| Test-Framework | JUnit 3 / TestCase-Stil |
| Testanzahl | 957 |
./mvnw test
./mvnw install -DskipTests
---
## Lizenz
Lizenziert unter der [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).```
Copyright 2024–2025 The Jackson Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Autor für Sicherheitslückenforschung und -behebung : Jinwoo Hwang (https://JinwooHwang.com)
src/main/java/.../JsonFactory.java | Geändert | +12 | Builder-Constraints in Konstruktoren verdrahten; DataInput-Fail-Fast für maxDocumentLength |
src/test/java/.../read/NumberOverflowTest.java | Geändert | +241 | testSonatype_2022_6438 (inkl. Exponent-Fälle), testNonBlockingParserNumericLengthLimit, testNonBlockingParserExponentLengthLimit, testCustomMaxNumberLengthConstraint |
src/test/java/.../read/NumberParsingTest.java | Geändert | +39 | 3 verifyException-Aufrufstellen aktualisiert |
src/test/java/.../read/ArrayParsingTest.java | Geändert | +143 | testCVE_2025_52999, testCustomNestingDepthConstraint |
src/test/java/.../constraints/LargeDocReadTest.java | Neu | +200 | 9 Tests für die Durchsetzung von maxDocumentLength über alle Parser-Pfade hinweg |