Skip to main content

Não entre em pânico: a injeção de template do Thymeleaf só causa danos se você permitir (CVE-2026-40478)

Escrito por

29 de abril de 2026

0 minutos de leitura

A vulnerabilidade do Thymeleaf, com pontuação CVSS 9.1, chama a atenção — e com razão. Mas, antes de convocar reforços e dizer que este é o novo Log4shell, leia isto primeiro.

CVE-2026-40478 é uma vulnerabilidade de injeção de template no lado do servidor do Thymeleaf, descoberta pelo pentester Dawid Bakaj. Thymeleaf é um mecanismo de templates em Java usado para renderizar páginas da web no lado do servidor. O sandbox que normalmente impede a execução arbitrária de código foi contornado usando um caractere de tabulação. E sim, isso pode levar à execução remota de código se a vulnerabilidade for explorada.

Mas aqui está o ponto mais importante: esta vulnerabilidade só se aplica se seu código já estiver fazendo algo que não deveria.

O que o sandbox protege

O Thymeleaf tem um sandbox de segurança. Ele limita o que expressões SpEL (Spring Expression Language) podem fazer ao avaliar conteúdo dinâmico. O sandbox existe para uma situação específica: quando uma entrada controlada pelo usuário chega, de alguma forma, ao mecanismo de expressões do Thymeleaf.

Se isso nunca acontece no seu código, o sandbox nunca é acionado, e esta CVE não afeta você. A forma correta de usar o Thymeleaf é simples: a entrada do usuário vai para o modelo de dados. Na maior parte do tempo, o template permanece estático em um arquivo HTML.

Código Java:

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

Template do Thymeleaf:

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

O Thymeleaf renderiza o valor de name. Ele nunca o interpreta como uma expressão. Um invasor pode enviar qualquer payload que quiser como name, e nada de interessante acontece. Esse é o design. É assim que o Thymeleaf deve funcionar.

Explorando o mecanismo de templates

A vulnerabilidade pode ser explorada quando um desenvolvedor permite que a entrada do usuário chegue diretamente ao mecanismo de expressões. Se isso acontece, é sinal de que o framework está sendo usado de forma indevida. Embora seja possível, é bem difícil chegar a esse ponto, especialmente ao usar o Thymeleaf com 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);
}

Como mostrado no código acima, preciso criar manualmente uma nova instância de templateEngine e definir um resolver. Normalmente, o Spring fornece isso.
Além disso, preciso definir a variável no contexto para que meu caso de uso normal e legítimo funcione.

No entanto, no exemplo acima, a entrada do usuário é passada ao mecanismo de expressões. Esse é o pré-requisito para que esta CVE seja relevante.

Um padrão de uso indevido semelhante é a resolução dinâmica de views. Em vez de criar strings de template diretamente, um desenvolvedor pode resolver views com base na entrada do usuário:

@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);
}

O caso de uso é legítimo: um endpoint atende a várias páginas. Mas agora a entrada do usuário influencia o que o Thymeleaf interpreta. É o mesmo padrão de uso indevido, com a mesma possibilidade de exploração. Repare, mais uma vez, em todo o trabalho manual necessário para chegar a esse ponto. A versão segura continua tendo apenas três linhas.

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

Como o caractere de tabulação contorna o sandbox do Thymeleaf

Quando o padrão de uso indevido está presente, a exploração propriamente dita é simples.

O sandbox procura por new (a palavra-chave seguida de um espaço) para bloquear a instanciação de objetos. O bypass usa new[TAB]. A verificação preliminar não encontra new, então a expressão passa. Já o SpEL aceita a tabulação como espaço em branco e a interpreta corretamente.

O payload é assim:

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

Após a verificação da palavra-chave, uma lista de bloqueio de tipos impede classes java.*. No entanto, as classes do Spring não estavam nessa lista. Como resultado, a lista incompleta, combinada com um filtro fraco para new, permitiu o carregamento de classes como FileSystemResource. Isso fez com que um arquivo fosse gravado no disco. Em teoria, um invasor poderia colocar um arquivo JSP que chama ProcessBuilder e executa um RCE.

Duas defesas falharam de forma independente: um problema com espaços em branco na verificação da palavra-chave e uma lista de bloqueio limitada. O bypass funcionou porque as verificações não definiam de forma completa o que era considerado um separador. A EndorLabs publicou uma análise mais detalhada da exploração, caso você queira saber mais.

Confira o repositório no GitHub para ver exemplos funcionais de código seguro e inseguro.

O que você precisa fazer

Aplique a correção primeiro. Atualize para o Thymeleaf 3.1.4, mesmo que você ache que seu código não foi afetado. Não espere os resultados da auditoria.

Se você usa o Thymeleaf por meio do Spring Boot, basta atualizar o parent do starter do Spring Boot para a versão mais recente (atualmente, 3.5.14 ou 4.0.6). Se estiver algumas versões atrás, vale conferir as receitas do OpenRewrite para migrar para a versão mais recente do Spring Boot 3.5 ou do Spring Boot 4.0.

Depois de atualizar, examine seu código para descobrir se strings de template ou a resolução de páginas são geradas dinamicamente a partir de entradas do usuário e passadas diretamente ao mecanismo de templates. Se isso acontece, é um padrão de uso indevido. Corrija o código, não apenas a versão da biblioteca.

A pontuação CVSS 9.1 é real, mas depende de uma condição

Uma pontuação CVSS crítica pressupõe que o pré-requisito foi atendido. Se seu código envia entradas do usuário ao mecanismo de expressões do Thymeleaf, a pontuação 9.1 é adequada, e o impacto é grave. Se não faz isso, a CVE em si não afeta você. Ainda assim, aplique a correção!

A pergunta que sua equipe deve fazer na auditoria não é apenas "qual versão do Thymeleaf estamos usando?". É: "construímos nomes de views ou expressões de template dinamicamente a partir de dados das requisições?"

Atualize o Thymeleaf para a versão 3.1.4 ou superior e, em seguida, descubra a resposta para essa segunda pergunta. Independentemente da resposta, continue analisando suas dependências durante o desenvolvimento e monitorando-as em produção com o Snyk Open Source. E o melhor: você pode começar gratuitamente.

Comece a proteger seus aplicativos Python

Encontre e corrija vulnerabilidades em Python gratuitamente com o Snyk.

Não é necessário informar cartão de crédito.

Ou cadastre-se com Azure AD Docker ID Bitbucket

Ao usar o Snyk, você concorda em cumprir nossas políticas, incluindo os Termos de Serviço e a Política de Privacidade.

Leia mais