@libp2p/kad-dht: Unvalidated PUT_VALUE records allow unbounded disk exhaustion on DHT server nodes
@libp2p/kad-dht: Unvalidated PUT_VALUE records allow unbounded disk exhaustion on DHT server nodes
Prioriteit & onderbouwing
Prioriteit: Verhoogd
Deze week beoordelen
Verhoogd (58/100): deze week beoordelen. Zwaarst wegend: technische ernst en exploitatie.
hoog
- Technische ernst (severity): Genormaliseerde ernst 'critical'; geen CVSS-score beschikbaar.
midden
- Exploit geclaimd: Een exploit wordt geclaimd maar is niet onafhankelijk bevestigd.
midden
- Gemeentelijke relevantie: Relevantiescore 35/100 uit de relevantie-engine (module 5).
verhoogd
- Technische ernst: Threat Score 85/100 x gewicht 25%.
- Exploitatie: Exploit Score 45/100 x gewicht 25%.
- Gemeentelijke relevantie: Relevantiescore 35/100 x gewicht 22%.
- Betrouwbaarheid van het signaal: Confidence 'likely' x gewicht 12%.
- Blootstellingskans: Geschatte blootstelling 30% x gewicht 10%.
- Betrouwbaarheid van de bron: Bronbetrouwbaarheid 88% x gewicht 6%.
De priority_score is de Action Urgency Score: een gewogen combinatie van de technische ernst, de exploitatie en de gemeentelijke relevantie.
Toelichting
### Summary An unauthenticated remote peer can exhaust the disk storage of any `@libp2p/kad-dht` node running in server mode by sending an unbounded stream of `PUT_VALUE` messages whose keys bypass all content validation. No credentials, no prior relationship, and no protocol deviation beyond a crafted key are required. The victim node's datastore fills until the host disk is exhausted, making the node unavailable. ### Details Two cooperating defects combine to produce the vulnerability. **Defect 1: `verifyRecord` silent early-return (`packages/kad-dht/src/record/validators.ts:19-21`)** ```typescript export async function verifyRecord(validators: Validators, record: Libp2pRecord, options?: AbortOptions): Promise { const key = record.key const keyString = uint8ArrayToString(key) // decode as UTF-8 const parts = keyString.split('/') if (parts.length < 3) { // No validator available return // <- silent success; record IS written to datastore } // ... } ``` Legitimate DHT keys (`/pk/ `, `/ipns/ `) have exactly 3 slash-delimited parts and are routed to registered validators. Any key whose UTF-8 representation splits into fewer than 3 parts, single-byte keys, or any value without two `/` characters, thus, bypasses validation entirely and is written to the datastore unconditionally. There is no audit log and no error returned to the caller. **Defect 2: Unbounded RPC message loop (`packages/kad-dht/src/rpc/index.ts:103-152`)** ```typescript let signal = AbortSignal.timeout(this.incomingMessageTimeout) // 10 s inactivity timer signal.addEventListener('abort', abortListener) const messages = pbStream(stream).pb(Message) // DEFAULT_MAX_DATA_LENGTH = 4 MB while (true) { if (stream.readStatus !== 'readable') { await stream.close({ signal }); break } const message = await messages.read({ signal }) await this.handleMessage(connection.remotePeer, message) // ... signal.removeEventListener('abort', abortListener) signal = AbortSignal.timeout(this.incomingMessageTimeout) // timer RESET each message signal.addEventListener('abort', abortListener) } ``` The inactivity timeout is reset after **every successfully received message**. There is no per-stream message count limit, no per-peer byte budget, and no rate limiter. An attacker who delivers each message within the 10-second window can stream an unlimited number of messages indefinitely. **Combined impact** - `DEFAULT_MAX_DATA_LENGTH = 4 MB` per message (from `@libp2p/utils`) - `DEFAULT_MAX_INBOUND_STREAMS = 32` concurrent streams per `kad-dht` instance - Attack throughput: 4 MB × unlimited messages × 32 streams - Minimum attacker cost: standard libp2p TLS handshake (no authentication beyond that) **Differential note**: `go-libp2p-kad-dht` enforces `record.Validator.Validate()` per-key at the RPC layer; records with unrecognised namespaces are rejected with an error, not silently stored. This divergence is JS-specific. ### PoC The proof-of-concept is a mocha test checked in alongside the package test suite. It uses an in-memory stream pair, thus, no network traffic, no external connections. **File**: `packages/kad-dht/test/rpc/poc-put-value-unvalidated.spec.ts`: ```typescript /** * PoC: kad-dht PUT_VALUE stored without validation for keys with < 3 slash-separated parts * * Affected: packages/kad-dht/src/record/validators.ts:19-22 * packages/kad-dht/src/rpc/handlers/put-value.ts * packages/kad-dht/src/rpc/index.ts (unbounded while loop) */ /* eslint-env mocha */ import assert from 'node:assert' import { start } from '@libp2p/interface' import { defaultLogger } from '@libp2p/logger' import { persistentPeerStore } from '@libp2p/peer-store' import { Libp2pRecord } from '@libp2p/record' import { streamPair } from '@libp2p/utils' import { MemoryDatastore } from 'datastore-core' import * as lp from 'it-length-prefixed' import { TypedEventEmitter } from 'main-event' import pDefer from 'p-defer' import Sinon from 'sinon' import { stubInterface } from 'sinon-ts' import { StreamMessageEvent } from '@libp2
Onderbouwing van de classificatie
Categorie 'supplier_incident' overgenomen van de bron; geen specifieker incidenttype gedetecteerd. Severity 'critical' bepaald op basis van: bronlabel 'high', trefwoord 'unauthenticated'. Confidence 'likely': gerenommeerd securityonderzoek (GitHub Security Advisories). Geen bekende leveranciers of producten herkend.
Kwetsbaarheden
- CVSS
- —
- EPSS
- —
- KEV
- Nee
Gemeentelijke relevantie
Deze dreiging scoort 35/100 voor de gemeentelijke relevantie. Meegewogen: een hoge ernstinschaling en een leveranciers- of ketenrisico. Geraakte processen: Netwerk en infrastructuur, Leveranciersketen.
Bestuurlijke duiding
Deze dreiging is relevant voor de gemeente. Omdat het een leverancier betreft, is de gemeente afhankelijk van diens herstel en is regie op de keten nodig. De impact is beheersbaar mits de geadviseerde maatregelen tijdig worden opgevolgd. Laat de CISO de voortgang bewaken en escaleer richting directie zodra nieuwe signalen daartoe aanleiding geven.
Geraakte processen
Geraakte technologie
Betrokken rollen
CISO · ISO · SOC · ICT beheer · Leveranciersmanager
Operationele acties
- Inventariseer welke koppelingen en gegevensstromen met de leverancier lopen.
- Schakel waar nodig de koppeling met de leverancier tijdelijk uit.
- Vraag bewijs van herstel op voordat de dienstverlening wordt hervat.
Concrete stappen voor ICT-beheer en het securityteam.
Aanbevolen acties
- Breng in kaart welke leveranciers en koppelingen zijn geraakt.
- Vraag de leverancier om een statusupdate en een herstelplan.
- Beoordeel de impact op de eigen dienstverlening.
Dit zijn algemene handelingsperspectieven. Stem de opvolging af op de eigen omgeving en het ISMS van uw gemeente.
Kenmerken
- Ernst
- Kritiek
- Categorie
- Leveranciersincident
- Zekerheid
- Waarschijnlijk
- Status
- Verrijkt
- CVE's
- CVE-2026-45783
- Prioriteitsscore
- 58 / 100 · Verhoogd
- Bron
- GitHub Security Advisories
- Gepubliceerd
- 19 mei 2026