Skip to main content

Pas de panique : l’injection de template Thymeleaf ne fait des dégâts que si vous la laissez faire (CVE-2026-40478)

Écrit par

29 avril 2026

0 minutes de lecture

La vulnérabilité Thymeleaf, notée 9.1 sur l’échelle CVSS, attire l’attention, à juste titre. Mais avant de sonner l’alarme et d’en faire le nouveau Log4Shell, lisez ceci.

CVE-2026-40478 est une vulnérabilité d’injection de template côté serveur dans Thymeleaf, découverte par le pentester Dawid Bakaj. Thymeleaf est un moteur de templates Java utilisé pour le rendu de pages Web côté serveur. Un caractère de tabulation a permis de contourner le bac à sable qui empêche normalement l’exécution de code arbitraire. Et oui, cette vulnérabilité peut entraîner l’exécution de code à distance si elle est exploitée.

Mais voici le point le plus important : cette vulnérabilité ne vous concerne que si votre code fait déjà quelque chose qu’il ne devrait pas faire.

Ce que protège le bac à sable

Thymeleaf dispose d’un bac à sable de sécurité. Celui-ci limite les actions possibles des expressions SpEL (Spring Expression Language) lorsqu’elles évaluent du contenu dynamique. Ce bac à sable répond à un cas précis : lorsqu’une entrée contrôlée par l’utilisateur parvient, d’une manière ou d’une autre, au moteur d’expressions de Thymeleaf.

Si cela ne se produit jamais dans votre code, le bac à sable n’intervient pas et cette CVE ne vous concerne pas. La bonne façon d’utiliser Thymeleaf est simple : les entrées utilisateur sont transmises au modèle de données. Le template reste généralement statique, dans un fichier HTML.

Code Java :

@GetMapping("/greet/safe")
public String greetSafe(@RequestParam String name, Model model) {
   model.addAttribute("name", name);
   return "greet";
}

Template Thymeleaf :

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<body>
   <p th:text="${name}">Default name</p>
</body>
</html>

Thymeleaf affiche la valeur de name. Il ne l’analyse jamais comme une expression. Un attaquant peut envoyer la charge utile de son choix dans name, sans que rien de notable ne se produise. C’est ainsi que le système est conçu. C’est ainsi que Thymeleaf est censé fonctionner.

Détourner le moteur de templates

La vulnérabilité devient exploitable lorsqu’un développeur laisse une entrée utilisateur parvenir directement au moteur d’expressions. Si cela se produit, cela signifie que le framework est utilisé de manière abusive. Bien que ce soit possible, c’est assez difficile à réaliser, en particulier lorsque Thymeleaf est utilisé avec Spring Boot.

@ResponseBody
@GetMapping("/greet/unsafe")
public String greetUnsafe(@RequestParam String name, Model model) {
   Context context = new Context();
   SpringTemplateEngine templateEngine = new SpringTemplateEngine();
   templateEngine.setTemplateResolver(new StringTemplateResolver());
   context.setVariable(name, name);
   String template = "<p th:text=\"'Hello ' + ${"+ name + "}\">...</p>";
   return templateEngine.process(template, context);
}

Comme le montre le code ci-dessus, je dois créer manuellement une nouvelle instance de templateEngine et définir un résolveur, alors que Spring s’en charge normalement.
En plus de cela, je dois définir la variable dans le contexte pour que mon cas d’usage légitime fonctionne.

Cependant, dans l’exemple ci-dessus, l’entrée utilisateur est transmise au moteur d’expressions. C’est la condition préalable à l’exploitation de cette CVE.

La résolution dynamique des vues est un autre exemple d’utilisation abusive similaire. Au lieu de créer directement des chaînes de template, un développeur peut résoudre les vues à partir d’une entrée utilisateur :

@GetMapping("/page/unsafe")
@ResponseBody
public String showPageUnsafe(@RequestParam String page) {
   Context context = new Context();
   SpringTemplateEngine templateEngine = new SpringTemplateEngine();
   StringTemplateResolver resolver = new StringTemplateResolver();
   resolver.setTemplateMode(TemplateMode.TEXT);
   templateEngine.setTemplateResolver(resolver);
   context.setVariable(page, page);
   String template = "[[${" + page + "}]]";
   return templateEngine.process(template, context);
}

Le cas d’usage est légitime : un seul endpoint sert plusieurs pages. Mais l’entrée utilisateur influence désormais ce que Thymeleaf analyse. Même utilisation abusive, avec le même risque d’exploitation. Notez, là encore, tout le câblage manuel nécessaire pour en arriver là. La version sûre ne tient toujours qu’en trois lignes.

@GetMapping("/page/safe")
public String showPageSafe(@RequestParam String page) {
   return page;
}

Comment le caractère de tabulation contourne le bac à sable de Thymeleaf

Une fois qu’un schéma d’utilisation abusive est en place, l’exploitation est simple.

Le bac à sable recherche le mot-clé « new » suivi d’une espace pour bloquer l’instanciation d’objets. Le contournement envoie plutôt new[TAB]. La vérification préalable ne trouve pas « new », qui passe donc. SpEL, en revanche, interprète la tabulation comme un espace blanc valide et analyse correctement l’expression.

La charge utile ressemble à ceci :

new[TAB]org.springframework.core.io.FileSystemResource('shell.jsp').getOutputStream()

Après la vérification du mot-clé, une liste de blocage des types est appliquée pour interdire les classes java.*. Toutefois, les classes Spring n’y figuraient pas. Résultat : cette liste incomplète, associée à un filtre trop permissif pour « new », a permis de charger des classes comme FileSystemResource. Un fichier a ainsi pu être écrit sur le disque. En théorie, un attaquant peut déposer un fichier JSP qui appelle ProcessBuilder et exécute du code à distance.

Deux mécanismes de défense ont échoué indépendamment : un problème lié aux espaces blancs dans la vérification du mot-clé et une liste de blocage trop limitée. Le contournement a réussi parce que les vérifications ne définissaient pas correctement les caractères considérés comme des séparateurs. EndorLabs propose une analyse plus détaillée de l’exploitation si le sujet vous intéresse.

Consultez le dépôt GitHub pour voir des exemples fonctionnels de code sûr et vulnérable.

Ce que vous devez faire

Appliquez d’abord le correctif. Passez à Thymeleaf 3.1.4, que vous pensiez ou non que votre code est concerné. N’attendez pas les résultats de l’audit.

Si vous utilisez Thymeleaf avec Spring Boot, mettez simplement à jour votre parent starter Spring Boot vers la dernière version (actuellement 3.5.14 ou 4.0.6). Si vous avez plusieurs versions de retard, vous pouvez consulter les recettes OpenRewrite pour migrer vers la dernière version de Spring Boot 3.5 ou de Spring Boot 4.0.

Après la mise à jour, vérifiez si des chaînes de template ou la résolution de pages sont générées dynamiquement à partir d’entrées utilisateur transmises directement au moteur de templates. Si c’est le cas, il s’agit d’une utilisation abusive. Corrigez le code lui-même, pas seulement la version de la bibliothèque.

Le score CVSS de 9.1 est bien réel, mais il est conditionnel

Un score CVSS critique suppose que la condition préalable est remplie. Si votre code transmet des entrées utilisateur au moteur d’expressions de Thymeleaf, le score de 9.1 est justifié et l’impact est grave. Dans le cas contraire, la CVE elle-même ne vous concerne pas. Mais appliquez tout de même le correctif !

La question à poser à votre équipe lors de l’audit n’est pas seulement « quelle version de Thymeleaf utilisons-nous ? », mais aussi « construisons-nous dynamiquement des noms de vues ou des expressions de template à partir des données des requêtes ? »

Mettez Thymeleaf à jour vers la version 3.1.4 ou ultérieure, puis trouvez la réponse à cette deuxième question. Quelle qu’elle soit, continuez à analyser vos dépendances pendant le développement et à les surveiller en production avec Snyk Open Source. Et le meilleur, c’est que vous pouvez commencer gratuitement.

Sécurisez vos applications Python dès maintenant

Détectez et corrigez gratuitement les vulnérabilités Python avec Snyk.

Aucune carte de crédit requise.

Ou inscrivez-vous avec Azure AD Docker ID Bitbucket

En utilisant Snyk, vous acceptez de respecter nos politiques, notamment nos Conditions d’utilisation et notre Politique de confidentialité.

Lire la suite

Blog

Les modèles de pointe ont trouvé les vulnérabilités. Seul l’attaquant a trouvé les chaînes d’exploitation.

L’analyse statique a détecté les failles, mais seuls des tests d’attaque en conditions réelles ont prouvé comment elles pouvaient être enchaînées pour provoquer des compromissions. Comparaison d’Evo COS, de Claude Security et de Claude Code Security.

feature insights context
Blog

Les attaques autonomes sont déjà là. La défense doit suivre leur rythme.

Les attaquants autonomes réduisent la fenêtre de défense. Découvrez comment la découverte, la correction, la validation et la prévention continues peuvent aider les équipes de sécurité à suivre le rythme.

Blog

Pourquoi les agents de codage IA créent-ils sans cesse des failles de contrôle d’accès ?

Les agents de codage IA peuvent générer une logique d’autorisation qui compile et passe la revue, tout en exposant les données d’un tenant à un autre. Découvrez pourquoi les failles de contrôle d’accès sont difficiles à détecter et comment les prévenir.