Un simple retour à la ligne paraît anodin lorsqu’on pense à une application web. Pourtant, mal géré, il peut ouvrir la porte à des attaques sérieuses.
C’est précisément le cas des injections CRLF, une vulnérabilité souvent sous-estimée qui consiste à insérer des caractères de contrôle de fin de ligne dans des requêtes ou des réponses.
Derrière ce mécanisme technique se cachent des scénarios d’exploitation concrets pouvant aller de la fuite d’informations sensibles à la compromission de la fiabilité d’un système.
Cet article propose de découvrir en détail ce qu’est une injection CRLF, ses modes d’exploitation et les bonnes pratiques pour s’en protéger.
Guide complet sur les injections CRLF
Qu’est-ce qu’une injection CRLF ?
L’injection CRLF est une vulnérabilité qui repose sur l’utilisation détournée de deux caractères spéciaux : le Carriage Return (CR, représenté par “\r”) et le Line Feed (LF, représenté par “\n”).
Ensemble, ils indiquent à de nombreux systèmes informatiques qu’une nouvelle ligne doit commencer. C’est notamment le cas des serveurs web, qui interprètent la séquence “CRLF” comme un retour à la ligne.
Il faut noter que cette convention n’est pas universelle. Par exemple, dans les environnements Unix, le simple caractère LF suffit pour signaler une nouvelle ligne. Mais dans le cadre des applications web, l’association CRLF est fréquemment utilisée et constitue donc une surface d’attaque potentielle.
Une injection CRLF survient lorsque ces caractères sont introduits dans un endroit du système qui ne les attend pas. Si l’application ne les valide pas ou ne les encode pas correctement, un attaquant peut en profiter pour altérer le fonctionnement normal d’une requête ou d’une réponse. En pratique, cela revient à “casser” la structure prévue par le serveur et à insérer du contenu non désiré dans un contexte non prévu.
Ce principe peut paraître abstrait à première vue. C’est pourquoi nous allons l’illustrer à travers plusieurs scénarios concrets d’exploitation d’applications web, afin de mieux comprendre la portée et les risques de cette vulnérabilité.
Exploitations de failles d’injection CRLF et bonnes pratiques sécurité
Injection d’en-têtes SMTP (SMTP header injection)
L’un des scénarios les plus courants d’injection CRLF concerne le protocole SMTP, utilisé pour l’envoi et la réception d’emails.
Comment fonctionne une injection d’en-tête SMTP ?
Dans le contexte d’une application web, cette vulnérabilité se manifeste généralement dans les fonctionnalités qui envoient automatiquement des emails aux utilisateurs, comme la réinitialisation de mot de passe.
Lorsqu’un utilisateur demande à réinitialiser son mot de passe, l’application prend l’adresse renseignée, forge un message SMTP, puis l’envoie au serveur de messagerie. En conditions normales, ce processus reste transparent pour l’utilisateur.
Imaginons par exemple un échange SMTP d’un client envoyant un email :
telnet smtp.company.com 25
Connected to smtp.company.com.
220 smtp.company.com SMTP Ready
HELO client
250-smtp.company.com
250-PIPELINING
250 8BITMIME
MAIL FROM: <[email protected]>
250 Sender ok
RCPT TO: [email protected]
250 Recipient ok.
DATA
354 Enter mail, end with "." on a line by itself
Subject: Contact
Corps du texte
.
250 Ok
QUIT
221 Closing connection
Connection closed by foreign host.
Dans la requête HTTP, l’utilisateur aura le contrôle sur le champ « RCPT TO ».
La requête légitime sera la suivante :
POST /api/authentication/forgot-password HTTP/2
Host: vulnerable.vaadata.com
{"login":"[email protected]"}
Cette requête est correctement traitée. Le serveur SMTP construit l’email et le transmet uniquement à l’adresse indiquée ([email protected]
) avec le lien de réinitialisation du mot de passe.
Exploitation de la vulnérabilité
Le problème apparaît si les caractères CRLF ne sont pas filtrés. Un attaquant peut alors injecter un nouvel en-tête dans le flux SMTP. Par exemple :
POST /api/authentication/forgot-password HTTP/2
Host: vulnerable.vaadata.com
{"login":"[email protected]\r\nCc: [email protected]"}
Dans ce cas, les en-têtes générés ne se limitent plus au destinataire initial. On obtient :
From: [email protected]
Subject: Change your password
To: [email protected]
Cc: [email protected]
Grâce à cette manipulation, l’attaquant se met en copie du message (avec le header Cc) et reçoit lui aussi le lien de réinitialisation du mot de passe. L’exploitation peut être encore plus discrète en injectant un champ Bcc, qui reste invisible pour le destinataire légitime.
Cette vulnérabilité trouve souvent son origine dans des librairies de gestion SMTP utilisées par les applications. Qu’elles soient tierces ou développées en interne, le risque est le même : l’absence de validation et d’encodage des entrées utilisateur.
Comment prévenir les injections d’en-têtes SMTP ?
La correction passe donc par plusieurs niveaux de défense :
- Valider strictement l’entrée : l’adresse email doit correspondre à un format valide, sans tolérer les caractères “
\r
” et “\n
”. - Encoder les caractères de contrôle : s’ils apparaissent malgré tout, ils doivent être transformés pour ne pas être interprétés par le serveur SMTP.
- Corriger au niveau applicatif : si la librairie utilisée n’intègre pas de correctif, l’application ou l’API doit mettre en place ses propres mécanismes de protection.
En résumé, ce scénario montre qu’une simple absence de contrôle sur les retours à la ligne peut suffire à détourner une fonctionnalité critique comme la réinitialisation de mot de passe.
Injection de logs (log injection)
Les injections CRLF ne se limitent pas aux échanges SMTP. Elles peuvent également affecter le système de journalisation (logging) d’une application web.
Qu’est-ce qu’une injection de logs ?
La plupart des frameworks proposent des mécanismes de logs intégrés, et il est fortement recommandé de les utiliser, notamment pour détecter des intrusions ou suivre l’usage d’une application. Mais si les données ne sont pas correctement contrôlées avant d’être enregistrées, ces logs peuvent devenir une cible.
Prenons l’exemple d’une application qui enregistre les actions des utilisateurs dans un fichier, avec un format simple :
HTTP verb HTTP status Endpoint Client-IP X-User-Id
GET 200 /home 5.50.81.190 123-456
PATCH 200 /user 5.50.81.190 123-456
GET 200 /login 5.45.20.32 Unauthenticated
Chaque requête authentifiée contient un en-tête X-User-Id
, automatiquement ajouté par le navigateur. Dans le journal ci-dessus, on peut suivre le parcours de l’utilisateur ayant l’ID 123-456
, qui a visité la page d’accueil puis modifié son profil.
Pour éviter les abus, les développeurs ont bien prévu qu’il soit impossible d’envoyer une requête sans cet en-tête (sauf sur les routes publiques). Mais ils ont oublié un détail : les données de ce header sont enregistrées telles quelles, sans nettoyage. C’est là qu’une injection CRLF peut entrer en jeu.
Exemple d’attaque CRLF dans les logs
Un utilisateur malveillant, déjà authentifié, pourrait par exemple envoyer la requête suivante :
GET /search HTTP/2
Host: vulnerable.vaadata.com
Authorization: Bearer <...>
X-User-Id: 789-123\r\nGET 200 /admin 5.48.16.120 Unauthenticated
Le fichier de log généré ressemblerait alors à ceci :
HTTP verb HTTP status Endpoint Client-IP X-User-Id
GET 200 /home 5.50.81.190 123-456
PATCH 200 /user 5.50.81.190 123-456
GET 200 /login 5.45.20.32 Unauthenticated
GET 200 /search 5.50.81.190 123-456
GET 200 /admin 5.48.16.120 Unauthenticated
La ligne injectée fait croire qu’une adresse IP a accédé à la page d’administration, alors que ce n’est pas le cas. L’administrateur du système peut être induit en erreur, perdre du temps à enquêter et, plus largement, perdre confiance dans l’intégrité des journaux.
Même si cette attaque ne compromet pas directement les données ou le serveur, elle mine la fiabilité du système de logs, qui devient alors inutilisable comme outil de sécurité.
Prévenir les injections de logs
La solution consiste à empêcher l’interprétation des caractères spéciaux. Pour cela, les caractères CR (\r
) et LF (\n
) présents dans les entrées doivent être encodés (par exemple en URL-encoding) avant d’être stockés. Ainsi, ils ne pourront pas briser la structure du fichier de log.
XSS réfléchie
Comment une injection CRLF mène à une XSS réfléchie ?
Un autre scénario d’exploitation des injections CRLF concerne les failles de type XSS réfléchie.
Ce type de vulnérabilité apparaît lorsque l’application reprend des données issues de la requête HTTP pour les refléter directement dans sa réponse, sans les filtrer ni les encoder.
Exemple d’injection CRLF aboutissant à une XSS
Imaginons une application multi-tenant dans laquelle un utilisateur peut appartenir à plusieurs organisations. Pour déterminer quel environnement afficher, le navigateur envoie un paramètre X-Organization-Id
.
Une requête/réponse légitime pourrait ressembler à ceci :
GET /home?X-Organization-Id=1234 HTTP/2
Host: vulnerable.vaadata.com
Authorization: Bearer <...>
HTTP/2 200 OK
Date: Fri, 08 Aug 2025 08:11:55 GMT
Content-Type: application/json
X-Organization-Id: 1234
[… HTML CONTENT …]
On observe que le paramètre est repris tel quel dans la réponse du serveur. Cela ouvre la voie à une injection CRLF, en encodant par exemple les caractères spéciaux %0d%0a
(qui correspondent à \r\n
) :
GET /home?X-Organization-Id=1234%0d%0a%0d%0a<html><script>alert(1)</script></html> HTTP/2
Host: vulnerable.vaadata.com
Authorization: Bearer <...>
HTTP/2 200 OK
Date: Fri, 08 Aug 2025 08:11:55 GMT
Content-Type: application/json
X-Organization-Id: 1234
<html><script>alert(1)</script></html>
[… HTML CONTENT …]
Avec cette injection de deux retours à la ligne, l’attaquant parvient à sortir du contexte des en-têtes et à insérer du code HTML/JavaScript directement dans le corps de la réponse.
Le navigateur exécute alors ce code, ce qui provoque une XSS. Dans sa forme la plus simple, cela se traduit par une alerte à l’écran. Mais l’impact peut être bien plus sérieux si l’application utilise un système de cache : dans ce cas, une attaque de type Cache Poisoning pourrait permettre d’infecter tous les utilisateurs d’une organisation, voire l’ensemble de la plateforme.
Comment se prémunir d’une XSS par injection CRLF ?
Cet exemple illustre que, bien qu’elles soient moins connues que d’autres injections, les failles CRLF peuvent avoir des conséquences graves.
La remédiation reste la même quel que soit le vecteur : il faut s’assurer que les caractères CRLF (\r
et \n
) sont correctement encodés afin qu’ils ne soient jamais interprétés comme des retours à la ligne par le serveur.
Conclusion
Les injections CRLF illustrent parfaitement comment un mécanisme aussi banal qu’un retour à la ligne peut devenir une véritable faille de sécurité. Derrière ce détail technique se cachent des scénarios concrets et variés : vol de liens de réinitialisation de mot de passe via SMTP, falsification de journaux applicatifs ou encore déclenchement d’attaques XSS.
Si leurs impacts diffèrent selon le contexte, toutes ces exploitations reposent sur la même faiblesse : l’absence de contrôle ou d’encodage des caractères de retour chariot et de saut de ligne. C’est pourquoi la meilleure défense reste double : valider strictement les entrées utilisateur et encoder correctement les caractères sensibles avant qu’ils ne soient interprétés par un serveur ou stockés par l’application.
Bien que souvent négligées, ces vulnérabilités méritent toute l’attention des équipes de développement et de sécurité. En intégrant ces bonnes pratiques dès la phase de conception, il est possible de réduire considérablement les risques et de préserver l’intégrité des systèmes web face à ce type d’attaques discrètes mais redoutablement efficaces.
Auteur : Julien BRACON – Pentester @Vaadata