flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal
CVE-2026-87902: Traversal de caminho nos templates do WordPress
Um nome de página decodificado sem validação entrou na resolução de templates do WordPress, permitindo inclusão local de PHP sem autenticação e RCE condicional quando tema e ambiente atendiam a requisitos específicos.[1]
Imagine uma bibliotecária que confere o pedido antes de buscar um livro. O WordPress verificava um caminho até os templates, mas não o caminho criado pelo nome decodificado; marcadores especiais podiam levá-la para fora das prateleiras do tema. A correção valida o nome e mantém o template dentro de um diretório permitido.[1], [2], [3]
Conceitos Centrais e Termos
Resolução de template- WordPress ordena candidatos PHP e procura o primeiro arquivo correspondente no tema ativo.[1], [2]
Traversal de caminho- Componentes como
..podem sair do diretório esperado quando a entrada não é validada.[1] Inclusão local de PHP- Carregamento de arquivo PHP já existente no servidor; RCE requer outras condições.[1]
`validate_file()`- Auxiliar do WordPress que rejeita componentes de caminho não permitidos antes do uso.[3]
Mapeamentos de frameworks
- Referência CWE para a fraqueza descrita neste guia: CWE-98
- CISA KEV — adicionado em 2026-09-25 — CVE-2026-87902
Análise de Causa Raiz
Em get_page_template(), WordPress decodificava pagename e adicionava um candidato page-{name}.php sem validate_file(). A ramificação vizinha já fazia essa validação. Assim, um caminho podia escapar do tema. A exploração exige uma pasta de tema de nível superior iniciada por page- e um PHP local legível; RCE também exige condições adicionais de PHP/servidor. A versão 7.1.2 valida o nome decodificado e restringe a raiz resolvida em locate_template(). O advisory do WordPress classifica essa fraqueza como CWE-98 (controle inadequado do nome de arquivo usado em include/require do PHP) e credita a descoberta e a divulgação responsável a Robert Ressl.[1], [2], [3], [7]
Alcance do CVE-2026-87902: exposição e RCE condicional
| Condição da instalação | O que as fontes primárias confirmam | Ação do operador |
|---|---|---|
| Versão do WordPress Core afetada | O GHSA lista versões afetadas por ramo, de 4.7.0–4.7.36 até 7.1.0–7.1.1. As correções correspondentes vão de 4.7.37 (backport mais antigo) a 7.1.2 (ramo atual), com uma versão corrigida específica para cada ramo listado. | Confira a versão instalada e aplique a correção do ramo correspondente. Atualize versões anteriores a 4.7 para uma versão com suporte. |
| Estrutura do tema ativo | O tema pai ou filho ativo precisa ter um diretório no nível superior cujo nome comece com page- (por exemplo, page-templates). | Inspecione os diretórios dos dois temas ativos. Reavalie essa condição quando o tema ativo mudar. |
| Arquivo PHP local legível | Precisa existir um arquivo .php escolhido fora dos diretórios dos temas ativos, legível pela conta do servidor web. | Revise quais arquivos PHP locais podem ser lidos pelo servidor web; não conclua que houve inclusão de arquivo apenas pela faixa de versões do CVE. |
| Ambiente para RCE condicional | O comunicado descreve RCE somente com condições adicionais de PHP/servidor. Os exemplos incluem pearcmd.php com register_argc_argv=On, a imagem oficial do PHP para Docker e configurações padrão do cPanel com PHP anterior à 8.5. | Avalie o runtime e a configuração PHP reais. Uma versão vulnerável do WordPress, por si só, não comprova RCE nem comprometimento. |
Fluxo de Ataque Passo a Paso
Entrada chega à seleção
Uma requisição sem autenticação fornece um nome usado para criar candidatos; não exige conta nem clique.[1]
Busca sai da raiz
Com uma pasta page-* e um PHP local legível, o tema pode resolver arquivo fora do seu diretório.[1]
Impacto condicional
RCE depende de requisitos adicionais de PHP e servidor; versão afetada, sozinha, não prova explorabilidade ou invasão.[1]
Código-Fonte: Vulnerável vs. Seguro
Este trecho compara as tags oficiais 7.1.1 e 7.1.2. O patch valida o valor após decodificá-lo; a mesma versão também limita caminhos resolvidos em locate_template(). É o código upstream, não um patch independente completo nem uma demonstração de exploração.[2], [3]
Trecho de origem: wp-includes/template.php — get_page_template()
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
Lista de Verificação de Segurança para Engenharia
- ✓Atualize para a versão corrigida do ramo e confirme a versão realmente executada.[1], [4]
- ✓Inventarie WordPress exposto à Internet e identifique versões sem suporte anteriores à 4.7.[1], [4]
- ✓Se houve exposição antes do patch, examine logs e arquivos PHP ou contas inesperados; um sinal inicia a investigação, não é prova isolada.
- ✓Em resolvedores próprios, valide componentes após decodificar e limite o caminho real canônico a diretórios permitidos.[1], [3]
- ✓Mantenha Core e temas em versões suportadas; trocar o tema pode alterar as condições de exposição.[1], [4]