
Questo repository fornisce una correzione completa di sicurezza per le vulnerabilità di negazione del servizio e allocazione di risorse senza limiti o limitazione di velocità segnalate in CVE-2025-52999, GHSA-2m67-wjpj-xhg9 e sonatype-2022-6438, mantenendo la piena compatibilità con jackson‑core 2.13.5.
Questo branch (2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9) contiene una remediazione completa delle vulnerabilità di denial-of-service (DoS) e allocazione di risorse senza limiti o limitazione che colpiscono jackson-core 2.13.5. Introduce l'API StreamReadConstraints —
allineata con l'API introdotta in jackson-core 2.15.0 ma estesa con una copertura parser più ampia
e ulteriori protezioni contro vettori di attacco — affrontando un attacco di esaurimento della profondità di annidamento
(CVE-2025-52999), allocazione di risorse senza limiti o limitazione (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924), un bypass del vincolo di lunghezza del documento (SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9), e un attacco di esaurimento della lunghezza dei token numerici (Sonatype-2022-6438) rimanendo compatibile con la superficie API pubblica di jackson-core versione 2.13.5.
| Branch | Vulnerabilità Affrontate |
|---|---|
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 | Tutte le precedenti + GHSA-2m67-wjpj-xhg9 (bypass vincolo lunghezza documento) |
Il branch originale (2.13.5-CVE-2025-52999-sonatype-2022-6438) rimuove tre vulnerabilità
ed è preservato sul remote sasso. Questo branch lo estende con la remediazione aggiuntiva di
GHSA-2m67-wjpj-xhg9,
che impone maxDocumentLength in tutti i percorsi del parser.
Voce NVD
Descrizione NVD Ufficiale
jackson-core contiene astrazioni di base del parser e generatore incrementale di basso livello ("streaming") utilizzate da Jackson Data Processor. Nelle versioni precedenti alla 2.15.0, se un utente analizza un file di input e questo contiene dati profondamente annidati, Jackson potrebbe lanciare una
StackOverflowErrorse la profondità è particolarmente grande. jackson-core 2.15.0 contiene un limite configurabile per quanto in profondità Jackson attraverserà in un documento di input, con un valore predefinito di profondità consentita di 1.000. jackson-core lancerà unaStreamConstraintsExceptionse il limite viene raggiunto. jackson-databind beneficia anche di questa modifica poiché utilizza jackson-core per analizzare input JSON. Come workaround, gli utenti dovrebbero evitare di analizzare file di input da fonti non attendibili.
Workaround: evitare di analizzare input JSON da fonti non attendibili fino a quando la versione remediata non viene distribuita.
Causa principale: Prima della 2.15.0, JsonParser non imponeva alcun limite a quanto profondamente annidato potesse essere un documento JSON.
Ogni token di array [ o oggetto { causava la allocazione di un nuovo nodo di contesto sull'heap e l'incremento di una catena di riferimenti tramite JsonReadContext.createChildArrayContext() / createChildObjectContext(). Un attaccante può creare un documento con decine di migliaia di livelli annidati, causando l'esaurimento dello stack del thread o della memoria heap della Java Virtual Machine.
Percorso di codice vulnerabile:
La stessa mancanza di controllo viene raggiunta attraverso ciascuna delle quattro implementazioni del parser:``` 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
Tutte e quattro le implementazioni di `JsonParser` condividono questa falla. L'attacco è ugualmente sfruttabile attraverso ciascuna di esse — che l'input arrivi tramite `InputStream`, `Reader`, `DataInput` o l'API asincrona non bloccante feeder.
**Vettori d'attacco:**
| # | Strategia | Payload esempio | Incremento profondità | Parser interessati |
|---|-----------|----------------|-----------------------|-------------------|
| 1 | Annidamento array | `[[[…]]]` — 1.001 token `[` consecutivi | +1 per `[` | Tutti e quattro |
| 2 | Annidamento oggetto | `{"k":{"k":{…}}}` — 1.001 token `{` consecutivi | +1 per `{` | Tutti e quattro |
| 3 | Annidamento alternato | `[{"k":[{"k":…}]}]` — 1.001 token misti `[`/`{` | +1 per `[` o `{` | Tutti e quattro |
Osservazioni chiave:
- **Annidamento array — overhead minimo:** sono richiesti solo i token `[` e `]`; niente chiavi, valori o spazi bianchi. Un payload di 2.002 byte con 1.001 coppie di parentesi è sufficiente per superare il limite predefinito di 1.000.
- **Annidamento oggetto — pressione heap amplificata:** ogni `{` alloca ulteriormente uno slot chiave `JsonReadContext` oltre al nodo della catena di profondità, aggravando il consumo di memoria a profondità estreme.
- **Annidamento alternato — evasione del Web Application Firewall (WAF):** le difese di pattern-matching che rilevano sequenze ripetute di `[[[` o `{{{` sono cieche all'annidamento a token alternati; il contatore di profondità del parser incrementa allo stesso modo indipendentemente dal tipo di token.
- **Feeder non bloccante — stesso payload, superficie di consegna distinta:** tutte e tre le strategie di annidamento sono ugualmente sfruttabili tramite `NonBlockingJsonParser` e l'API `ByteArrayFeeder`. Il documento può essere consegnato in blocchi arbitrariamente piccoli; `NonBlockingJsonParserBase._startArrayScope()` / `_startObjectScope()` incrementano il contatore di profondità ad ogni token di apertura contesto indipendentemente da come arrivano i byte, accumulando profondità attraverso più chiamate `feedInput()`.
Tutte e tre le strategie di annidamento sono raggiungibili attraverso ciascuna delle quattro implementazioni di `JsonParser`. Con la 2.13.5, il parsing ha successo silenziosamente; con questa correzione, tutti e tre i vettori lanciano `StreamConstraintsException: Depth (1001) exceeds the maximum allowed nesting depth (1000)`.
---
### Sonatype-2022-6438 — Lunghezza Token Numerico Illimitata
**Dettagli di sicurezza**
| Campo | Valore |
|-------|--------|
| Sonatype ID | [sonatype-2022-6438](https://guide.sonatype.com/vulnerability/sonatype-2022-6438/security-details) |
| Descrizione | jackson-core — Negazione del Servizio (DoS) |
| Pubblicato | 2022-12-07 |
| Fonte | Sonatype |
| Punteggio CVSS v3.1 | **7.5 ALTA** — `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) — Assegnazione di Risorse Senza Limiti o Limitazione |
| Punteggio EPSS | 0% |
| PR di correzione upstream | [jackson-core#827](https://github.com/FasterXML/jackson-core/pull/827), [jackson-core#846](https://github.com/FasterXML/jackson-core/pull/846) |
**Metodi vulnerabili (come identificati da Sonatype)**
| Metodo | Note |
|--------|------|
| `com.fasterxml.jackson.core.base.ParserBase._parseSlowInt(I)V` | Parametro vulnerabile: indice 0 |
| `com.fasterxml.jackson.core.base.ParserBase.convertNumberToBigDecimal()V` | |
| `com.fasterxml.jackson.core.base.ParserMinimalBase.getValueAsDouble(D)D` | Parametro vulnerabile: indice 0 |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDecimal()` | Restituisce `BigDecimal` |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsDouble(Z)D` | |
| `com.fasterxml.jackson.core.util.TextBuffer.contentsAsFloat(Z)F` | |
Ciascuno di questi metodi elabora il buffer di cifre grezze senza prima validarne la lunghezza. Passare un token numerico sufficientemente lungo innesca allocazione heap illimitata ed esaurimento della CPU quando la JVM tenta di istanziare un `BigInteger` o `BigDecimal` dal contenuto del buffer non vincolato.
---
**Causa principale:** Prima della 2.15.0, `JsonParser` non imponeva alcun limite sulla lunghezza in byte dei token interi, in notazione scientifica, a virgola mobile semplici o composti. Quando un parser alloca il suo `_textBuffer` interno per accumulare cifre, un attaccante può fornire un numero con milioni di cifre, causando la crescita illimitata del buffer e portando infine all'esaurimento della memoria heap.
**Percorsi di codice vulnerabili:**
Esistono due percorsi vulnerabili strutturalmente distinti — uno condiviso dai tre parser sincroni, e un secondo percorso indipendente attraverso il parser asincrono.
**Path A — parser sincroni** (tre implementazioni, un sink condiviso):```
JsonParser.nextToken() // common entry point
│
├─ ReaderBasedJsonParser ─┐
├─ UTF8StreamJsonParser ├─→ ParserBase.resetInt() / resetFloat()
└─ UTF8DataInputJsonParser ─┘ │
▼
_textBuffer.contentsAsString()
⚠ no length check — buffer grows without bound
Path B — parser asincrono (percorso di codice indipendente, separatamente non protetto):``` 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
Il parser non bloccante (asincrono) è una superficie d'attacco particolarmente degna di nota: contiene i propri
cicli di accumulo di cifre in `_startPositiveNumber`, `_startNegativeNumber`,
`_finishNumberIntegralPart`, `_startFloat`, `_finishFloatFraction` e `_finishFloatExponent`
che impostano `_intLength` / `_fractLength` / `_expLength` direttamente senza passare mai attraverso
`ParserBase.resetInt()` o `resetFloat()`. Ciò significa che la correzione a monte della PR #827 (che ha aggiunto
la validazione solo a `ParserBase`) **ha lasciato `NonBlockingJsonParser` completamente non protetto**.
Questa scoperta è stata fatta durante un'analisi estesa della superficie d'attacco e corretta in questo branch.
**Vettori d'attacco:**
| # | Forma del token | Esempio di payload | `intLen` | `fractLen` | `expLen` | Totale | Vincolo |
|---|----------------|-------------------|----------|------------|----------|--------|---------|
| 1 | Intero | `999…` — 199.999 cifre consecutive | 199.999 | 0 | 0 | 199.999 | `validateIntegerLength` |
| 2 | Frazione decimale | `0.999…` — intero a 1 cifra, frazione a 1.001 cifre | 1 | 1.001 | 0 | 1.002 | `validateFPLength` |
| 3 | Notazione scientifica | `1e999…` — significando a 1 cifra, esponente a 1.001 cifre | 1 | 0 | 1.001 | 1.002 | `validateFPLength` |
| 4 | Virgola mobile composta | `0.999…e999…` — frazione a 500 cifre, esponente a 500 cifre | 1 | 500 | 500 | 1.001 | `validateFPLength` |
Osservazioni chiave:
- **Intero — il segno non è una cifra:** il `-` iniziale è escluso dall'accumulo di cifre; `-999…` e `999…` producono valori identici di `intLen` e attivano il vincolo alla stessa soglia.
- **Frazione decimale — intero corto, frazione illimitata:** la parte intera può essere una singola cifra (0) mentre la parte frazionaria cresce senza limite; il punto decimale stesso è escluso dal conteggio.
- **Notazione scientifica — compatta ma catastrofica:** a circa 1.004 byte è il payload efficace più piccolo; forza l'istanziazione di un `BigDecimal` con scala ±10^1001, richiedendo un'allocazione intermedia di heap illimitata nonostante la piccola dimensione del token.
- **Virgola mobile composta — elusione del limite suddiviso:** con `fractLen = 500` e `expLen = 500`, nessun componente raggiunge individualmente la soglia di 1.000 cifre. Il controllo unificato `validateFPLength(intLen + fractLen + expLen)` è l'unica difesa che chiude questa falla.
- **Parser non bloccante — bypass indipendente:** tutte e quattro le forme di token sopra sono sfruttabili indipendentemente attraverso `NonBlockingJsonParser` tramite `ByteArrayFeeder`. A differenza dei parser sincroni, `NonBlockingJsonParser` accumula cifre in cicli privati (`_startPositiveNumber`, `_finishNumberIntegralPart`, `_startFloat`, `_finishFloatFraction`, `_finishFloatExponent`) che scrivono `_intLength` / `_fractLength` / `_expLength` direttamente, bypassando completamente `ParserBase.resetInt()` e `resetFloat()`. La PR #827 a monte — che ha modificato solo `ParserBase` — ha quindi lasciato questo parser completamente non protetto, richiedendo sei patch indipendenti nei siti di chiamata in questa correzione.
Tutte e quattro le forme di token e il bypass non bloccante vengono rifiutati al momento della tokenizzazione — prima che qualsiasi `BigDecimal` o `BigInteger`
venga costruito — da `validateIntegerLength` e `validateFPLength` in `ParserBase` (parser sincroni)
e in sei siti di chiamata dedicati in `NonBlockingJsonParser` (parser asincrono). Con 2.13.5, tutte e quattro le forme di token vengono accettate silenziosamente; con questa correzione, ogni parser lancia
`StreamConstraintsException: Number length (N) exceeds the maximum length (1000)`.
> **Nota su `UTF8DataInputJsonParser` con payload grandi:** Il parser DataInput ha un
> limite interno del buffer preesistente di 65.536 byte ([jackson-core#493](https://github.com/FasterXML/jackson-core/issues/493)).
> I documenti che superano questa dimensione (ad es., payload PoC da 199.999 cifre ≈ 200 KB) attivano
> un `ArrayIndexOutOfBoundsException` prima che il vincolo di lunghezza possa scattare. La protezione
> della lunghezza numerica per `UTF8DataInputJsonParser` è quindi verificata con payload più brevi
> (≤ 1.001 cifre) dove il bug è ancora riproducibile.
---
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 — Bypass del vincolo di lunghezza del documento
**Dettagli di sicurezza**
| Campo | Valore |
|-------|--------|
| ID Snyk | [SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551](https://security.snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551) |
| Advisory GitHub | [GHSA-2m67-wjpj-xhg9](https://github.com/FasterXML/jackson-core/security/advisories/GHSA-2m67-wjpj-xhg9) |
| Descrizione | Allocazione di risorse senza limiti o limitazione |
| Divulgato | 2026-04-04 |
| Punteggio CVSS v4.0 | **8.7 ALTA** |
| CWE | [CWE-770](https://cwe.mitre.org/data/definitions/770.html) — Allocazione di risorse senza limiti o limitazione |
| Versioni affette | [2.8.0, 2.21.2) |
| Correzione a monte | jackson-core 2.18.7, 2.21.2 o superiore |
| Commit di correzione | [74c9ee25](https://github.com/FasterXML/jackson-core/commit/74c9ee25) (3.x), [7ce3622f](https://github.com/FasterXML/jackson-core/commit/7ce3622f) (2.18.x) |
**Causa principale:** Anche quando `StreamReadConstraints.maxDocumentLength` è configurato, le versioni precedenti
alla 2.18.7 / 2.21.2 non impongono il limite di lunghezza del documento in nessun percorso del parser. I parser bloccanti
(`UTF8StreamJsonParser`, `ReaderBasedJsonParser`) non convalidano mai i byte cumulativi letti rispetto al
limite configurato. Il parser asincrono (`NonBlockingJsonParser`) manca similmente di validazione in
`feedInput()`. `UTF8DataInputJsonParser` non ha alcun meccanismo per tracciare i byte totali consumati.
In jackson-core 2.13.5, `maxDocumentLength` non esisteva affatto, il che significa che non c'era modo di
limitare la dimensione del documento. Questa correzione introduce il campo `maxDocumentLength` in
`StreamReadConstraints` e lo impone in tutti i percorsi del parser.
**Percorsi di parser vulnerabili:**
| Parser | Percorso | Punto di imposizione |
|--------|----------|----------------------|
| `UTF8StreamJsonParser` | `InputStream` → `_loadMore()` | Convalida `_currInputProcessed + count` dopo ogni ricarica del buffer e all'EOF |
| `ReaderBasedJsonParser` | `Reader` → `_loadMore()` | Stesso schema di `UTF8StreamJsonParser` |
| `NonBlockingJsonParser` | `feedInput()` | Convalida `_currInputProcessed + _origBufferLen` dopo ogni blocco di input |
| `UTF8DataInputJsonParser` | `DataInput` | Fail-fast: lancia `StreamConstraintsException` se `maxDocumentLength` è configurato |
**Scenario d'attacco:** Un attaccante invia un documento JSON valido ma di dimensioni eccessive (ad es., una struttura
profondamente annidata o altamente ripetitiva che si estende per gigabyte) a un servizio che ha configurato
`maxDocumentLength` per prevenire l'esaurimento delle risorse. Senza imposizione, il parser elabora l'intero
documento indipendentemente dal limite configurato, consumando memoria e CPU illimitate.
---
## Impatto sulla sicurezza
Tutte e quattro le vulnerabilità sono sfruttabili da remoto senza autenticazione:
- Qualsiasi servizio che analizza JSON controllato dall'attaccante tramite un `JsonParser` (direttamente o attraverso
Jackson Databind, che avvolge `jackson-core`) è a rischio.
- L'attacco è banale da costruire — poche centinaia di byte di JSON sono sufficienti per innescare
un consumo illimitato di risorse.
- Nessun impatto sulla riservatezza o sull'integrità; la disponibilità (DoS) è l'unica classe di impatto.
---
## Dettagli della correzione
### Aggiornamento ufficiale (Raccomandato)
Aggiornare a **jackson-core 2.15.4** o qualsiasi release stabile successiva. Tutte le release 2.15.x e 2.16+
includono l'API `StreamReadConstraints` con valori predefiniti sicuri.```xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.4</version>
</dependency>
Se l'aggiornamento a una versione successiva non è immediatamente fattibile, questo branch applica una correzione completa alla codebase 2.13.5. Introduce StreamReadConstraints e StreamConstraintsException con un'API compatibile con 2.15.x, collega i vincoli a tutte e quattro le implementazioni di JsonParser — incluso il parser non bloccante, che non era coperto dalla correzione upstream — e applica i seguenti limiti predefiniti:
| Vincolo | Limite Predefinito |
|---|---|
| Profondità massima di annidamento | 1,000 |
| Lunghezza massima del token numerico | 1,000 cifre |
| Lunghezza massima del token stringa | 1,000,000 caratteri |
Magnitudine massima della scala di BigDecimal |
StreamReadConstraints (356 righe)Oggetto valore immutabile che contiene limiti di lettura del flusso per parser, costruito tramite un 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();
Metodi di validazione (chiamati dai parser su ogni nuovo token):```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;
Formato dei messaggi di eccezione:
"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 righe)Estende StreamReadException (che a sua volta estende JsonProcessingException). Viene sollevata esclusivamente dai metodi di validazione di StreamReadConstraints.
base/ParserBase.javaAggiunto il campo _streamReadConstraints (default a StreamReadConstraints.defaults()).
resetInt() e resetFloat() ora validano la lunghezza del token numerico immediatamente dopo che il token è stato accumulato:```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 … }
Nuovi metodi helper `_createChildArrayContext()` e `_createChildObjectContext()` racchiudono la creazione del contesto con un controllo di profondità:```java
protected JsonReadContext _createChildArrayContext(int line, int col) throws IOException {
_streamReadConstraints.validateNestingDepth(_parsingContext.getNestingDepth() + 1);
return _parsingContext.createChildArrayContext(line, col);
}
Tutti e quattro i parser ora chiamano i nuovi helper di controllo della profondità invece di accedere direttamente a _parsingContext.createChild*():
json/ReaderBasedJsonParser.javajson/UTF8StreamJsonParser.javajson/UTF8DataInputJsonParser.javajson/async/NonBlockingJsonParserBase.javaJsonStreamContext.javaAggiunto getNestingDepth() che percorre la catena dei genitori per calcolare la profondità assoluta:```java
public int getNestingDepth() {
int depth = 0;
JsonStreamContext curr = this;
while ((curr = curr.getParent()) != null) {
depth++;
}
return depth;
}
#### `json/JsonReadContext.java`
`createChildArrayContext()` e `createChildObjectContext()` firme aggiornate per propagare
`throws IOException`.
#### `json/async/NonBlockingJsonParser.java` (solo per Sonatype-2022-6438)
Questo è il principale fix aggiuntivo scoperto al di là dell'ambito della PR #827 upstream. Sei
siti di completamento numerico che bypassavano `ParserBase.resetInt()` sono stati remediati
individualmente:
| Metodo | Validazione aggiunta |
|--------|----------------------|
| `_startPositiveNumber()` — fast-path return | `validateIntegerLength(_intLength)` |
| `_startNegativeNumber()` — fast-path return | `validateIntegerLength(_intLength)` |
| `_finishNumberIntegralPart()` — final return | `validateIntegerLength(_intLength)` |
| `_finishToken()` case `MINOR_NUMBER_INTEGER_DIGITS` | `validateIntegerLength(_intLength)` |
| `_startFloat()` / `_finishFloatFraction()` / `_finishFloatExponent()` final returns | `validateFPLength(_intLength + _fractLength + _expLength)` |
| `_finishToken()` cases `MINOR_NUMBER_FRACTION_DIGITS` / `MINOR_NUMBER_EXPONENT_DIGITS` | `validateFPLength(...)` |
Tutti i siti sono raggiungibili: i metodi fast-path gestiscono il caso in cui il numero
completo è disponibile in una singola chiamata `feedInput()`; i casi di stato di ripresa
`MINOR_*` gestiscono il caso frammentato in cui le cifre del numero arrivano attraverso
chiamate multiple. Entrambi i percorsi devono essere protetti.
---
## Copertura dei test
### CVE-2025-52999 — Test della profondità di annidamento
| File di test | Metodo di test | Modalità parser | Copertura |
|--------------|----------------|-----------------|-----------|
| `read/ArrayParsingTest.java` | `testCVE_2025_52999` | stream | Traversal ricorsivo simulando l'uso reale dell'app; conferma `StreamConstraintsException` alla profondità 1001 (riparato) e `StackOverflowError` alla profondità 20.000 (2.13.5) |
| `read/ArrayParsingTest.java` | `testCustomNestingDepthConstraint` | direct API | `StreamReadConstraints.builder().maxNestingDepth(5)` — accessor, passaggio al limite, superamento del limite lancia eccezione |
| `read/ArrayParsingTest.java` | `testObjectNestingDepthLimit` | stream | Oggetti esattamente al limite 1000 (passaggio), oggetti al livello 1001 lanciano eccezione |
| `read/ArrayParsingTest.java` | `testDataInputParserDepthLimit` | `UTF8DataInputJsonParser` | `UTF8DataInputJsonParser` impone il limite di profondità di 1001 livelli |
| `read/ArrayParsingTest.java` | `testNonBlockingParserDepthLimit` | non-blocking | `NonBlockingJsonParser` impone il limite di profondità di 1001 livelli |
### Sonatype-2022-6438 — Test della lunghezza numerica
| File di test | Metodo di test | Modalità parser | Copertura |
|--------------|----------------|-----------------|-----------|
| `read/NumberOverflowTest.java` | `testSonatype_2022_6438` | `ALL_MODES` | Intero al limite (passaggio), intero oltre il limite (fallimento), float al limite (passaggio), float oltre il limite (fallimento), esponente in notazione scientifica al limite (passaggio), esponente oltre il limite (fallimento) — tutti e quattro i parser |
| `read/NumberOverflowTest.java` | `testNonBlockingParserNumericLengthLimit` | non-blocking | `NonBlockingJsonParser` impone la lunghezza numerica |
| `read/NumberOverflowTest.java` | `testNonBlockingParserExponentLengthLimit` | non-blocking | `NonBlockingJsonParser` impone la lunghezza dell'esponente in notazione scientifica tramite `validateFPLength` |
| `read/NumberOverflowTest.java` | `testCustomMaxNumberLengthConstraint` | direct API | `StreamReadConstraints.builder().maxNumberLength(5)` — accessor, passaggio al limite, superamento del limite lancia eccezione per entrambi `validateIntegerLength()` e `validateFPLength()`, formato del messaggio di errore |
> **Legenda delle modalità parser:**
> - `ALL_STREAMING_MODES` = `UTF8StreamJsonParser` (stream), `UTF8StreamJsonParser` (throttled), `ReaderBasedJsonParser`
> - `ALL_MODES` = le tre precedenti + `UTF8DataInputJsonParser`
> - `non-blocking` = `NonBlockingJsonParser` tramite `ByteArrayFeeder`
> - `stream` = `UTF8StreamJsonParser` (predefinito `JsonFactory.createParser`)
### SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 — Test della lunghezza del documento
| File di test | Metodo di test | Modalità parser | Copertura |
|--------------|----------------|-----------------|-----------|
| `constraints/LargeDocReadTest.java` | `testInputStreamExceedsLimit` | `UTF8StreamJsonParser` | Il parser InputStream impone `maxDocumentLength` — documento 20K rifiutato con limite 10K |
| `constraints/LargeDocReadTest.java` | `testInputStreamUnderLimitSucceeds` | `UTF8StreamJsonParser` | Il parser InputStream accetta documento entro il limite |
| `constraints/LargeDocReadTest.java` | `testReaderExceedsLimit` | `ReaderBasedJsonParser` | Il parser Reader impone `maxDocumentLength` — documento 20K rifiutato con limite 10K |
| `constraints/LargeDocReadTest.java` | `testReaderUnderLimitSucceeds` | `ReaderBasedJsonParser` | Il parser Reader accetta documento entro il limite |
| `constraints/LargeDocReadTest.java` | `testAsyncExceedsLimit` | `NonBlockingJsonParser` | Il parser asincrono impone `maxDocumentLength` — documento 20K rifiutato in `feedInput()` |
| `constraints/LargeDocReadTest.java` | `testAsyncUnderLimitSucceeds` | `NonBlockingJsonParser` | Il parser asincrono accetta documento entro il limite |
| `constraints/LargeDocReadTest.java` | `testDataInputWithDocLengthLimitFails` | `UTF8DataInputJsonParser` | Il parser DataInput fallisce rapidamente quando `maxDocumentLength` è configurato |
| `constraints/LargeDocReadTest.java` | `testDataInputWithoutDocLengthLimitWorks` | `UTF8DataInputJsonParser` | Il parser DataInput funziona normalmente senza `maxDocumentLength` configurato |
| `constraints/LargeDocReadTest.java` | `testDefaultFactoryNoLimit` | `UTF8StreamJsonParser` | La factory predefinita (nessun limite) accetta documenti grandi |
---
## Risultati completi della suite di test```
Tests run: 957, Failures: 0, Errors: 0, Skipped: 0
Tutti i 957 test superano sulla build corretta. Ripartizione dei nuovi test di sicurezza aggiunti:
Comando di build:```bash ./mvnw test
---
## Risultati di convalida
### Test di regressione contro jackson-core 2.13.5
I metodi di test CVE sono stati progettati per **fallire** sul codebase 2.13.5 e **passare** sulla build corretta.
**`NumberOverflowTest#testSonatype_2022_6438`** contro 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 contro 2.13.5:```
FAIL — CVE-2025-52999 VULNERABILITY PRESENT: StackOverflowError after 20000 nesting
levels — parser enforces no depth limit (2.13.5)
**Entrambi i test sulla build corretta: PASS.**
---
## Prova di concetto
### CVE-2025-52999 — Profondità di annidamento 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();
}
Tutte e quattro le forme di token attivano validateFPLength / validateIntegerLength prima che venga tentata qualsiasi conversione BigDecimal / BigInteger.```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(); } }
---
## Guida alla migrazione
### Opzione 1: Aggiornamento a jackson-core 2.15.4+ (Consigliato)```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>
Con 2.15+, puoi anche regolare i limiti a runtime se la tua applicazione necessita legittimamente di annidamento più profondo o numeri più lunghi:```java JsonFactory factory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(2000) .maxNumberLength(10000) .maxDocumentLength(50_000_000L) .build()) .build();
### Opzione 2: Applica questa correzione di sicurezza```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
Quindi aggiorna la dipendenza del tuo progetto per utilizzare l'artefatto 2.13.5-SNAPSHOT installato localmente, oppure distribuiscilo nel tuo repository di artefatti interno.
Totale: 16 file modificati, 1.606 inserimenti (come riportato da git diff jackson-core-2.13.5 --stat).
StreamReadConstraints (javadoc 2.15): https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.15.4/com/fasterxml/jackson/core/StreamReadConstraints.htmlQualsiasi applicazione che:
jackson-databind)è vulnerabile a entrambi gli attacchi.
Anche dopo la correzione, considera:
maxRequestSize nei contenitori Servlet) per rifiutare corpi di richiesta estremamente grandi prima che il parser venga invocato.StreamReadConstraints personalizzati se la tua applicazione richiede legittimamente documenti più grandi o più profondi — regola i limiti al minimo necessario per il tuo caso d'uso.| Dimensione | Requisito |
|---|---|
| JDK di build | Java 8 (JDK 1.8) o successivo — questo branch richiede Java 8+ per la build e i test |
| JRE runtime minimo | Java 8 o successivo |
| Maven | 3.6.3 o successivo (il wrapper incluso ./mvnw soddisfa automaticamente questo requisito) |
Nota: Il rilascio originale di jackson-core 2.13.5 era destinato a Java 6 (
-source 1.6 -target 1.6). A partire da questo branch di sicurezza, è richiesto Java 8 o successivo sia per la build che per il runtime. Nessuna API pubblica di Jackson 2.13 viene modificata; solo i runtime JDK 6/7 perdono compatibilità a causa dei requisiti di Maven e JDK.
./mvnw test
./mvnw install -DskipTests
---
## Licenza
Concesso in licenza ai sensi della [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.
Autore di Ricerca e Remediation di Vulnerabilità di Sicurezza : Jinwoo Hwang (https://JinwooHwang.com)
| ID | Tipo | Gravità | CVSS | Fix a monte |
|---|
| CVE-2025-52999 | Denial of Service — profondità di annidamento illimitata | Alta | 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 — lunghezza token numerici illimitata | Alta | 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 | Allocazione di risorse senza limiti o limitazione | Alta | 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 o superiore. |
| SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 / GHSA-2m67-wjpj-xhg9 | Allocazione di risorse senza limiti o limitazione — bypass vincolo lunghezza documento | Alta | 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 o superiore. |
| Versione | CVE-2025-52999 | Sonatype-2022-6438 / SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15365924 | SNYK-JAVA-COMFASTERXMLJACKSONCORE-15907551 |
|---|
| 2.13.5 | Vulnerabile | Vulnerabile | Vulnerabile | Vulnerabile |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438 | Remediata | Remediata | Remediata | Vulnerabile |
| 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 | Remediata | Remediata | Remediata | Remediata |
| 2.14.x | Vulnerabile | Vulnerabile | Vulnerabile | Vulnerabile |
| 2.15.x | Remediata | Remediata | Vulnerabile | Vulnerabile |
| 2.16.x | Remediata | Remediata | Vulnerabile | Vulnerabile |
| 2.17.x | Remediata | Remediata | Vulnerabile | Vulnerabile |
| 2.18.6+ | Remediata | Remediata | Remediata | Vulnerabile |
| 2.18.7+ | Remediata | Remediata | Remediata | Remediata |
| 2.21.1+ | Remediata | Remediata | Remediata | Vulnerabile |
| 2.21.2+ | Remediata | Remediata | Remediata | Remediata |
| Campo | Valore |
|---|
| ID CVE | CVE-2025-52999 |
| Pubblicato | 2025-06-25 |
| Ultima Modifica | 2025-06-26 |
| Fonte (CNA) | GitHub, Inc. |
| Punteggio CVSS v4.0 | 8.7 ALTA — 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 — Buffer Overflow basato su Stack |
| Avviso GitHub | GHSA-h46c-h94j-95f3 |
| PR Fix a monte | jackson-core#943 |
| 100,000 |
| File di test | Metodi nuovi / estesi |
|---|
read/ArrayParsingTest.java | testCVE_2025_52999, testCustomNestingDepthConstraint, testObjectNestingDepthLimit, testDataInputParserDepthLimit, testNonBlockingParserDepthLimit |
read/NumberOverflowTest.java | testSonatype_2022_6438 (esteso per includere casi di esponente), testNonBlockingParserNumericLengthLimit, testCustomMaxNumberLengthConstraint, testNonBlockingParserExponentLengthLimit |
constraints/LargeDocReadTest.java | testInputStreamExceedsLimit, testInputStreamUnderLimitSucceeds, testReaderExceedsLimit, testReaderUnderLimitSucceeds, testAsyncExceedsLimit, testAsyncUnderLimitSucceeds, testDataInputWithDocLengthLimitFails, testDataInputWithoutDocLengthLimitWorks, testDefaultFactoryNoLimit |
| File | Tipo di modifica | Righe modificate | Descrizione |
|---|
src/main/java/.../StreamReadConstraints.java | Nuovo | +356 | Configurazione dei vincoli + 5 metodi di validazione |
src/main/java/.../exc/StreamConstraintsException.java | Nuovo | +52 | Tipo di eccezione per violazioni dei vincoli |
src/main/java/.../base/ParserBase.java | Modificato | +44 | Hook di profondità/lunghezza nei reset e nei context helper |
src/main/java/.../json/JsonReadContext.java | Modificato | +6 | propagazione di throws IOException |
src/main/java/.../json/ReaderBasedJsonParser.java | Modificato | +30 | Usa helper _createChild* per il controllo della profondità |
src/main/java/.../json/UTF8StreamJsonParser.java | Modificato | +26 | Usa helper _createChild* per il controllo della profondità |
src/main/java/.../json/UTF8DataInputJsonParser.java | Modificato | +26 | Usa helper _createChild* per il controllo della profondità |
src/main/java/.../json/async/NonBlockingJsonParserBase.java | Modificato | +4 | Usa helper _createChild* per il controllo della profondità |
src/main/java/.../json/async/NonBlockingJsonParser.java | Modificato | +9 | NUOVO — validateIntegerLength / validateFPLength in 6 siti di completamento numerico; validateDocumentLength in feedInput() |
src/main/java/.../JsonStreamContext.java | Modificato | +20 | Aggiunto getNestingDepth() |
src/main/java/.../TSFBuilder.java | Modificato | +15 | Aggiunto campo _streamReadConstraints e setter streamReadConstraints() |
src/main/java/.../JsonFactory.java | Modificato | +12 | Collega i vincoli del builder nei costruttori; fail-fast di DataInput per maxDocumentLength |
src/test/java/.../read/NumberOverflowTest.java | Modificato | +241 | testSonatype_2022_6438 (incl. exponent cases), testNonBlockingParserNumericLengthLimit, testNonBlockingParserExponentLengthLimit, testCustomMaxNumberLengthConstraint |
src/test/java/.../read/NumberParsingTest.java | Modificato | +39 | Aggiornati 3 siti di chiamata di verifyException |
src/test/java/.../read/ArrayParsingTest.java | Modificato | +143 | testCVE_2025_52999, testCustomNestingDepthConstraint |
src/test/java/.../constraints/LargeDocReadTest.java | Nuovo | +200 | 9 test per l'applicazione di maxDocumentLength in tutti i percorsi del parser |
| Componente | Versione |
|---|
| Tag di base | jackson-core-2.13.5 |
| Branch | 2.13.5-CVE-2025-52999-sonatype-2022-6438-GHSA-2m67-wjpj-xhg9 |
| Strumento di build | Maven (wrapper: ./mvnw) |
| Framework di test | JUnit 3 / stile TestCase |
| Numero di test | 957 |