# Sécuriser un formulaire HubSpot contre l’injection d’en-têtes email

> Un champ de formulaire mal validé transmis à une API d'emailing peut permettre d'injecter des en-têtes CC ou BCC et détourner l'envoi. Snippet de validation stricte pour s'en protéger.

- Auteur : WordPress Développement
- Publié le : 2022-03-18
- Mis à jour le : 2022-03-18
- Catégorie : Sécurité
- URL : https://www.wpmoderne.fr/securite/securiser-formulaire-hubspot-injection-en-tetes-email/

## L’essentiel

- Un retour à la ligne dans un champ texte peut suffire à injecter un en-tête
- Valider le format attendu de chaque champ, pas seulement sa présence
- Filtrer côté serveur, jamais uniquement côté API tierce

Un retour chariot (`\r\n`) glissé dans un champ « Nom » d'un formulaire de contact : deux caractères invisibles à l'écran, mais capables, sur une intégration mal protégée, d'ajouter une ligne `Bcc:` arbitraire à l'e-mail généré automatiquement par l'API HubSpot lors de la soumission du formulaire. C'est le principe classique de l'injection d'en-têtes e-mail, connu depuis longtemps mais toujours exploitable dès qu'un champ de formulaire est transmis sans validation stricte à un service qui génère un e-mail à partir de son contenu.

Ce type de faille a été identifié sur un formulaire de demande de devis, où le champ « Nom de l'entreprise » était directement inséré dans l'objet de l'e-mail de notification généré par HubSpot, sans qu'aucune validation ne restreigne les caractères autorisés dans ce champ.

## Comprendre le mécanisme de l'injection

La plupart des systèmes de génération d'e-mails construisent leurs en-têtes en concaténant des champs fournis par l'utilisateur avec des libellés fixes, par exemple `Subject: Nouvelle demande de {entreprise}`. Si le champ `{entreprise}` contient un retour à la ligne suivi d'un nouvel en-tête (`\r\nBcc: attaquant@exemple.com`), et que le système de génération ne filtre pas ces caractères avant assemblage, l'en-tête injecté devient un en-tête réel du message final, avec toutes les conséquences que cela implique : copie cachée vers une adresse arbitraire, modification du destinataire, voire dans certains cas ajout de corps de message supplémentaire.

HubSpot filtre une partie de ces cas côté plateforme, mais un champ personnalisé injecté dans un template d'e-mail transactionnel configuré manuellement peut échapper à ce filtrage selon la façon dont le template a été construit, ce qui a été précisément le cas sur ce projet.

> L'essentiel à retenir : Un retour à la ligne dans un champ texte peut suffire à injecter un en-tête ; Valider le format attendu de chaque champ, pas seulement sa présence ; Filtrer côté serveur, jamais uniquement côté API tierce

## Le correctif : valider le format attendu, pas seulement la présence

La correction distingue deux niveaux de validation trop souvent confondus : vérifier qu'un champ n'est pas vide ne garantit rien sur son contenu. La validation doit porter sur le format réellement attendu pour chaque champ, en rejetant explicitement tout caractère de contrôle avant transmission à l'API :

```
function valider_champ_formulaire($valeur, $type_champ) {
    // Rejet systématique des caractères de contrôle et retours à la ligne
    if (preg_match('/[\r\n\x00-\x1F]/', $valeur)) {
        return new WP_Error(
            'caractere_invalide',
            'Ce champ ne peut pas contenir de saut de ligne.'
        );
    }

    switch ($type_champ) {
        case 'nom_entreprise':
            if (!preg_match('/^[\p{L}0-9\s\-\'&.]{1,120}$/u', $valeur)) {
                return new WP_Error('format_invalide', 'Nom d\'entreprise invalide.');
            }
            break;
        case 'email':
            if (!is_email($valeur)) {
                return new WP_Error('email_invalide', 'Adresse e-mail invalide.');
            }
            break;
    }

    return sanitize_text_field($valeur);
}
```

La fonction WordPress `sanitize_text_field()` supprime déjà une partie des caractères de contrôle et des retours à la ligne, mais s'appuyer uniquement sur elle sans validation de format explicite laisse passer des valeurs syntaxiquement valides tout en étant sémantiquement inattendues pour le champ concerné, comme un nom d'entreprise contenant une adresse e-mail complète ou une URL.

## Traiter aussi le côté template HubSpot

Au-delà de la validation côté WordPress, le template d'e-mail transactionnel configuré dans HubSpot a été révisé pour ne plus insérer directement de champ personnalisé dans l'en-tête `Objet` du message : la personnalisation se limite désormais au corps de l'e-mail, où une injection d'en-tête n'a plus aucun effet, un retour à la ligne dans le corps du message restant un simple retour à la ligne, sans conséquence sur la structure des en-têtes.

## Tester la correction

Le test de non-régression consiste à soumettre volontairement le formulaire avec un champ contenant une séquence `\r\nBcc:` encodée, en vérifiant à la fois que la requête est rejetée côté WordPress avant tout envoi vers HubSpot, et que l'e-mail final, en cas de contournement de cette première couche, ne contient aucun en-tête supplémentaire par rapport à un envoi normal.

## En résumé

Un champ de formulaire destiné à alimenter un e-mail automatique mérite une validation aussi stricte qu'un champ destiné à une requête SQL : le format attendu doit être défini explicitement, et tout caractère de contrôle rejeté avant transmission à l'API tierce, plutôt que de faire confiance au filtrage éventuel du service d'emailing en bout de chaîne.
