FlawOpen

flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal

● CVE-2026-87902 · CVSS 9.2[1] · Crítica
Pesquisa · FlawOpen

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]

💡 Explicação em Linguagem Simples (ELI5)

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]
CWE-98
CWE-98 — Controle inadequado do nome de arquivo em include/require: a entrada não é restringida corretamente antes de selecionar um arquivo PHP.[1], [7]

Mapeamentos de frameworks

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çãoO que as fontes primárias confirmamAção do operador
Versão do WordPress Core afetadaO 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 ativoO 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ívelPrecisa 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 condicionalO 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

Passo 1

Entrada chega à seleção

Uma requisição sem autenticação fornece um nome usado para criar candidatos; não exige conta nem clique.[1]

Passo 2

Nova decodificação

get_page_template() decodifica o nome novamente; versões afetadas omitiam a validação do candidato decodificado.[2], [3]

Passo 3

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]

Passo 4

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()

IMPLEMENTAÇÃO VULNERÁVEL
if ( $pagename ) {
    $pagename_decoded = urldecode( $pagename );

    if ( $pagename_decoded !== $pagename ) {
        $templates[] = "page-{$pagename_decoded}.php";
    }
}
PATCH SEGURO E ROBUSTO
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

Fontes