Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

HTTP request smuggling primitive: bare LF accepted as a request-line terminator in strict mode

Ouverte
#877 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 6 jours

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
55/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
node.js, typescript

Piste de recherche

Commencez dans url.ts:176 et suivez url.exit.toHTTP09 jusqu'à headers_start, en comparant le chemin avec LF seul à la vérification LENIENT_OPTIONAL_CR_BEFORE_LF utilisée pour les autres terminateurs de la ligne de requête. Ajoutez une couverture de régression pour les requêtes sans version et avec version en mode strict, puis vérifiez que le mode strict rejette le cas du LF seul sans analyser les en-têtes HTTP/0.9 ni un corps.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

llhttp_set_lenient_optional_cr_before_lf documents that llhttp "would error when a LF is not
preceded by CR when terminating the request line", and that relaxing this exposes request smuggling.
url.ts:176 exits on a bare \n straight to the HTTP/0.9 adapter with no
LENIENT_OPTIONAL_CR_BEFORE_LF check — the only line terminator in the grammar that is ungated.

url.exit.toHTTP09 then continues into headers_start with no http_minor guard, so the message is
labelled HTTP/0.9 but headers and a Content-Length body are still parsed.

PoC

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

const srv = http.createServer((req, res) => {          // default parser, no options
  let body = '';
  req.on('data', c => body += c);
  req.on('end', () => {
    console.log(`  ACCEPTED  HTTP/${req.httpVersion}  ${req.method} ${req.url}` +
                `  headers=${JSON.stringify(req.headers)}  body=${JSON.stringify(body)}`);
    res.end('ok');
  });
});
srv.on('clientError', e => console.log(`  REJECTED  ${e.code}`));

const cases = [
  ['versionless + bare LF', 'GET /x\nHost: a\r\nContent-Length: 5\r\n\r\nhello'],
  ['versioned   + bare LF', 'GET /x HTTP/1.1\nHost: a\r\n\r\n'],
];

srv.listen(0, async () => {
  for (const [name, raw] of cases) {
    console.log(name);
    await new Promise(done => {
      const c = net.connect(srv.address().port, '127.0.0.1', () => c.write(raw));
      c.on('close', done); c.on('error', done);
      setTimeout(() => c.destroy(), 300);
    });
  }
  srv.close();
});
versionless + bare LF
  ACCEPTED  HTTP/0.9  GET /x  headers={"host":"a","content-length":"5"}  body="hello"
versioned   + bare LF
  REJECTED  HPE_INVALID_VERSION

The same terminator is rejected when a version is present and accepted when it is absent. The
accepted message is reported as HTTP/0.9 yet carries headers and a body, neither of which HTTP/0.9
defines.

Scope, stated plainly: this path sets keepalive=0, and a pipelined follow-up request is rejected
with HPE_CLOSED_CONNECTION, so on its own it is a divergence from the documented strict-mode
guarantee rather than a demonstrated desync. Two requests parse on one connection only with
lenient_keep_alive also enabled.

Langage dominant
TypeScript
Étoiles
2k
Forks
236
Merge moyen
5 j 2 h
PR mergées (30 j)
1

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de nodejs/llhttp

Toutes les issues de nodejs/llhttp

Issues similaires

Plus d'issues TypeScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.