flawopen.com/Teardowns/cve-2021-22960-nodejs-llhttp-request-smuggling
Detaillierte technische Quellcode-Analyse und Härtungsmaßnahmen für vulnerabilidade: How incomplete Transfer-Encoding chunk extension parsing in deps/llhttp caused HTTP request desynchronization, enabling cache poisoning and credential theft.
Anschauliche Analogie: Imagine a two-window ticket booth. Window 1 reads: 'One ticket for Alice'. Window 2 reads: 'Wait, there's another ticket for Bob glued to the back'. Because Window 1 ignored the extra ticket, Bob's ticket sits in the window until Charlie walks up. Charlie gets handed Bob's ticket and private receipt, allowing an attacker to steal user sessions.
llhttpHTTP Request SmugglingChunked Transfer-Encoding0\r\n\r\n chunk.Chunk Extensions0;extension=value\r\n).Die Grundursache liegt in nicht validierten Grenzparametern in Open-Source-Systemen, die eine Zustandsdesynchronisation und die Umgehung von Sicherheitskontrollen ermöglichen.
Technischer Ausführungsmechanismus: The attacker sends an HTTP request with chunk extensions containing unescaped control characters.
Technischer Ausführungsmechanismus: The frontend proxy treats the entire payload as a single continuous request body.
Technischer Ausführungsmechanismus: Node.js's llhttp stops parsing prematurely, leaving the smuggled second request in the TCP buffer.
Technischer Ausführungsmechanismus: The next innocent user's request is prepended to the smuggled request, exfiltrating their session tokens.
// VULNERABLE: deps/llhttp/src/llhttp.c before patch
int llhttp__on_chunk_extension(llhttp_t *parser, const char *p, const char *end) {
// ROOT CAUSE:
// Does not enforce strict ASCII validation on chunk extension tokens!
// Tolerates invalid whitespace and carriage return sequences, desyncing from proxies!
while (p < end && *p != '\r' && *p != '\n') {
p++; // Skips unvetted extension bytes
}
return 0;
}
// SECURE: deps/llhttp/src/llhttp.c patch
int llhttp__on_chunk_extension(llhttp_t *parser, const char *p, const char *end) {
// 1. Strictly validate characters inside chunk extensions according to RFC 9112
while (p < end && *p != '\r' && *p != '\n') {
uint8_t ch = (uint8_t)*p;
// Disallow spaces, control codes, and invalid token bytes
if (ch <= 0x20 || ch >= 0x7F || ch == ';') {
return HPE_INVALID_CHUNK_SIZE; // Reject immediately!
}
p++;
}
return 0;
}