veilletech.fr
16 oct. Feed du jour
#02 SYMFONY Article

Symfony : trois CVE, visez 6.4.48 et 7.4.21

Un simple en-tête Cache-Control suffisait à saturer le processeur.

Symfony a publié le 15 octobre trois avis de déni de service sans authentification : un ReDoS dans HeaderUtils::split() via l'en-tête Cache-Control (CVE-2026-108082), une récursion non bornée dans le lexeur YAML (CVE-2026-109413) et une imbrication non bornée dans ExpressionLanguage (CVE-2026-109449). Les premiers correctifs étaient incomplets ou régressifs : il faut viser 5.4.54, 6.4.48, 7.4.21 ou 8.1.9.

3 min de lectureintermédiairevidéo 1:23
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. Les mécanismes
  3. Le piège des premiers correctifs
  4. Que faire
  5. À retenir

Ce qui se passe

Le 15 octobre 2026, Symfony a publié trois avis de sécurité le même matin. Tous trois font planter un processus PHP, sans authentification ; aucun ne permet d'exécuter du code, et aucune exploitation n'est signalée.

CVE Composant Cause Versions corrigées
CVE-2026-108082 HttpFoundation HeaderUtils::split() analyse Cache-Control avec une expression régulière à retour arrière explosif 5.4.54, 6.4.46, 7.4.19, 8.1.7
CVE-2026-109413 Yaml le lexeur des collections en ligne ([[[…]]]) récurse sans borne 5.4.54, 6.4.45, 7.4.18, 8.1.6
CVE-2026-109449 ExpressionLanguage le parseur construit un arbre sans limite de profondeur 5.4.54, 6.4.48, 7.4.21, 8.1.9

Les mécanismes

HttpFoundation. Le motif acceptait les espaces à l'intérieur de ses éléments, suivis d'un (?<!\s) : une série d'espaces avant un séparateur pouvait se répartir de façon exponentielle entre les itérations, et le moteur les essayait toutes. HeaderBag appelle cette fonction pour Cache-Control à chaque construction d'une Request : toute application qui reçoit du HTTP est atteignable. Mesure de l'avis, PHP 8.5, en-tête de 8 Ko : 813 ms pour 17 espaces, et le temps double à chaque espace. À partir de 18, preg_match_all() abandonne à pcre.backtrack_limit et split() renvoie un tableau vide : toutes les directives de l'en-tête disparaissent sans bruit. Signalé par r3verii, corrigé par Nicolas Grekas.

Yaml. lexInlineStructure() appelait lexInlineMapping() et lexInlineSequence() à chaque { ou [ sans entrer dans le niveau que borne maxNestingLevel ailleurs dans le parseur. Un document de crochets imbriqués épuise la pile. Tout code qui lit du YAML non fiable est concerné, y compris #[MapRequestPayload] quand Yaml est installé et que l'endpoint ne restreint pas acceptFormat : une requête sans compte, avec un type de contenu YAML, suffit.

ExpressionLanguage. Des dizaines de milliers d'opérateurs unaires, de littéraux de tableau, d'opérateurs binaires ou d'accès de propriété imbriqués font planter le processus à la libération de l'arbre. #[Assert\ExpressionSyntax] passe la valeur à ExpressionLanguage::lint() : une application qui valide des expressions saisies par ses utilisateurs tombe sur une seule requête. Le parseur lève désormais une SyntaxError au-delà de 256 niveaux.

Le piège des premiers correctifs

Ne vous arrêtez donc pas à la première version qui porte le correctif : les versions à viser sont 5.4.54, 6.4.48, 7.4.21 et 8.1.9.

Que faire

Terminal
composer update "symfony/*"
composer show "symfony/*"

Vérifier ensuite que symfony/http-foundation, symfony/yaml et symfony/expression-language sont au moins aux versions ci-dessus, puis lancer la suite de tests. Si un endpoint n'a pas besoin du YAML, restreindre acceptFormat pour #[MapRequestPayload].

Source : blog Symfony, CVE-2026-108082, 15 octobre 2026 ; avis liés : CVE-2026-109413 et CVE-2026-109449.