Acordou hoje e ainda não atualizou seu WordPress? Talvez você queira ler isso antes do café.
A equipe de segurança do WordPress acabou de soltar a versão 7.1.2, um patch de emergência que corrige uma falha classificada como CVSS 9.2 (crítica). O problema? Um atacante anônimo, sem nenhuma conta no seu site, consegue incluir arquivos PHP arbitrários do servidor e, em muitos ambientes, executar código remoto. Isso mesmo: RCE sem login, sem plugin vulnerável, direto no core do WordPress.
E o pior: a vulnerabilidade existe desde a versão 4.7.0, lançada em 2016. São quase dez anos de código vulnerável dormindo no core.
O que é o CVE-2026-87902
A CVE-2026-87902 é uma falha de Local File Inclusion (LFI) na função get_page_template() do WordPress. Ela mora no arquivo wp-includes/template.php e afeta como o WordPress decide qual template de página carregar.
O advisory oficial classifica a vulnerabilidade como CWE-98: controle inadequado de nomes de arquivo para inclusão. Em português: o WordPress pega input do usuário e joga direto num require() sem validar direito.
O pesquisador Robert Ressl descobriu e reportou a falha de forma responsável, e o patch saiu hoje, 22 de setembro de 2026.
| Dado | Valor | |
|---|---|---|
| – | ||
| CVE | CVE-2026-87902 | |
| CVSS | 9.2 (Crítico) | |
| CWE | CWE-98 (Improper Control of Filename for Include) | |
| Versões afetadas | 4.7.0 a 7.1.1 | |
| Versão corrigida | 7.1.2 (e backports para todas as branches) | |
| Autenticação necessária | Nenhuma | |
| Descoberto por | Robert Ressl |
Como a falha funciona (passo a passo)
Eu sei que muita gente vai querer entender a parte técnica, então vamos lá.
O código vulnerável
A função get_page_template() constrói nomes de arquivos candidatos para templates de página. Ela faz isso usando a variável pagename da query string. O problema é que uma das branches do código monta o caminho assim:
$templates[] = "page-{$pagename}.php";
O $pagename vem direto do input do usuário. Existe uma chamada a validate_file() (a função do WordPress que bloqueia path traversal) numa branch vizinha do código, mas nessa branch específica ela simplesmente não existe.
A proteção existia três linhas acima do lugar onde ela faltava.
Leia de novo. Três linhas. Alguém adicionou a validação no lugar certo, e no caso logo abaixo, não copiou.
O truque do path traversal
Para que a travessia de diretórios funcione, duas coisas precisam acontecer:
1. O tema ativo precisa ter um diretório que começa com page-
O WordPress só aceita templates que resolvam para dentro de um diretório real do tema. Então o nome do arquivo precisa começar com page- (que é o prefixo fixo) e o diretório correspondente precisa existir. Acontece que muitos temas populares criam diretórios como page-templates/ no nível raiz do tema.
Quais temas são afetados? A lista inclui:
- Twenty Twelve (tema padrão legado)
- Twenty Fourteen (tema padrão legado)
- Neve
- Hestia
- Sydney
- Qualquer tema com diretório
page-*na raiz
2. O urldecode() processa o payload
O WordPress aplica urldecode() no slug do pagename. Isso significa que sequências URL-encoded de traversal (tipo %2e%2e%2f) são convertidas em componentes de caminho reais (../). Com isso, o atacante consegue escapar do diretório do tema e incluir qualquer arquivo .php legível no servidor.
O payload final fica algo como:
https://alvo.com/?pagename=page-templates/..%2f..%2f..%2f..%2fetc%2fpasswd%00
Mas espera: incluir um arquivo local não é a mesma coisa que executar código do atacante. Para isso, precisa de um segundo ingrediente.
De LFI para RCE: o truque do pearcmd.php
Aqui é onde a coisa fica realmente perigosa.
O caminho clássico de LFI para RCE em PHP envolve encontrar um arquivo .php no servidor que aceite argumentos e execute código. O candidato perfeito para isso é o pearcmd.php, o utilitário de linha de comando do PEAR (o gerenciador de pacotes legado do PHP).
O pearcmd.php usa $_SERVER['argv'] para receber argumentos. E aqui está o detalhe crucial: quando a diretiva register_argc_argv está habilitada no php.ini, o PHP popula essa variável a partir da query string da requisição HTTP.
Onde register_argc_argv vem habilitado por padrão?
- Todas as imagens Docker oficiais do PHP
- Ambientes cPanel com PHP abaixo do 8.5
- Muitas distribuições Linux com configuração padrão do PHP
O ataque funciona assim:
1. Atacante inclui /usr/local/lib/php/pearcmd.php via LFI
2. Passa argumentos via query string: config-create /<?=system($_GET['c'])?> /var/www/html/shell.php
3. pearcmd.php cria o arquivo shell.php com código PHP executável
4. Atacante acessa shell.php?c=whoami e tem RCE
Na prática, uma única requisição HTTP sem autenticação pode criar um webshell no servidor. Zero cliques. Zero credenciais.
Quem está em risco
Vamos ser honestos: se você roda WordPress e não atualizou, está em risco. Mas o nível de risco varia:
| Cenário | Risco | |
|---|---|---|
| — | – | |
| WordPress em Docker (imagem oficial PHP) | Crítico: register_argc_argv ON por padrão |
|
| WordPress em cPanel (PHP < 8.5) | Crítico: mesma configuração | |
WordPress com tema que tem diretório page-* |
Alto: pré-condição atendida | |
| WordPress em hosting gerenciado (WP Engine, Kinsta) | Médio: provavelmente já corrigiram ou têm WAF | |
| WordPress atualizado para 7.1.2 | Seguro: falha corrigida |
A combinação “Docker + tema com page-templates/” é a mais perigosa. E adivinha: boa parte dos setups modernos de WordPress roda em containers Docker.
O patch: o que o WordPress fez
O WordPress 7.1.2 implementou duas correções:
1. Validação direta
Adicionaram a chamada validate_file() na branch que estava faltando. Parece óbvio, mas é exatamente esse tipo de esquecimento que gera CVEs críticas.
// Antes (vulnerável)
$templates[] = "page-{$pagename}.php";
// Depois (corrigido)
if ( validate_file( $pagename ) === 0 ) {
$templates[] = "page-{$pagename}.php";
}
2. Camada de contenção
Além da correção pontual, a equipe de segurança introduziu uma nova função: _wp_is_template_path_allowed(). Essa função exige que todos os templates resolvidos passem por validação, independentemente do caminho de código.
Isso é inteligente. Em vez de confiar que cada branch individual do código faz a coisa certa, eles adicionaram um portão de segurança centralizado. A decisão sugere que trataram a resolução de templates como uma classe de problema, não como um bug isolado.
2026: o ano que o WordPress Core virou queijo suíço
Se você está acompanhando segurança de WordPress em 2026, já percebeu um padrão. Essa é a terceira vulnerabilidade crítica no core do WordPress só este ano:
wp2shell (Julho 2026)
A CVE-2026-63030 combinada com a CVE-2026-60137 formou a cadeia wp2shell: uma confusão de rotas no endpoint REST /wp-json/batch/v1 que permitia SQL injection no parâmetro author__not_in do WP_Query. O resultado? Um atacante anônimo podia criar uma conta de administrador e executar código.
O exploit era auto-limpante, deixando evidências mínimas nos logs. Os únicos rastros eram contas de admin com prefixo wp2_ ou w2s_ e rows orphans de oembed_cache no banco.
Imagick/Ghostscript RCE (Agosto 2026)
A CVE-2026-65640 afetou instalações que usam a extensão Imagick junto com Ghostscript para processar arquivos de mídia. Upload de arquivo malicioso resultava em execução de código.
CVE-2026-87902 (Setembro 2026, hoje)
E agora essa. Três RCEs no core em três meses consecutivos.
| Mês | CVE | Vetor | Pré-auth? | |
|---|---|---|---|---|
| —– | —– | – | —– | |
| Julho | CVE-2026-63030 + 60137 | SQL Injection via REST batch | Sim | |
| Agosto | CVE-2026-65640 | Imagick/Ghostscript upload | Não (precisa de upload) | |
| Setembro | CVE-2026-87902 | LFI via page template | Sim |
Dois dos três são pré-autenticação. Sem login. Sem nada. Basta uma requisição HTTP.
Como verificar se você está vulnerável
Antes de tudo, confira sua versão:
# Via WP-CLI
wp core version
# Via REST API (sem autenticação)
curl -s https://seusite.com/wp-json/ | jq '.description'
# Checar no arquivo
grep 'wp_version =' wp-includes/version.php
Se a versão for menor que 7.1.2 (ou menor que o patch da sua branch: 7.0.6, 6.9.9, 6.8.10, etc.), você está vulnerável.
Para verificar as pré-condições do RCE:
# Verificar se o tema tem diretório page-*
ls -d wp-content/themes/$(wp theme list --status=active --field=name)/page-* 2>/dev/null
# Verificar register_argc_argv
php -i | grep register_argc_argv
Se ambos retornarem resultados positivos, seu servidor está na zona de perigo máximo.
Como se proteger agora
1. Atualize imediatamente
# Via WP-CLI
wp core update
# Ou via Dashboard
# Painel > Atualizações > Atualizar agora
Sites com atualizações automáticas em background já devem estar atualizados. Se você desabilitou isso (e muita gente desabilita por medo de quebrar alguma coisa), corra e atualize manualmente.
2. Mitigações temporárias (se não puder atualizar agora)
Se por algum motivo você não consegue atualizar neste momento:
; No php.ini - desabilita register_argc_argv
register_argc_argv = Off
Isso quebra a cadeia LFI-para-RCE mesmo que o pearcmd.php ainda esteja presente. A inclusão local ainda funciona, mas sem execução de código.
Outra opção:
# Remover pearcmd.php se PEAR não é necessário
rm /usr/local/lib/php/pearcmd.php
3. Verifique se já foi explorado
Procure nos logs por requisições suspeitas:
# Buscar por tentativas de path traversal em pagename
grep -E 'pagename=.*\.\.' /var/log/nginx/access.log
grep -E 'pagename=.*%2e%2e' /var/log/nginx/access.log
# Buscar por arquivos PHP criados recentemente no webroot
find /var/www/html -name "*.php" -mtime -7 -newer /var/www/html/wp-config.php
Se encontrar algo, considere que o servidor foi comprometido e faça uma análise forense completa.
O problema maior: WordPress e a dívida técnica
Eu venho acompanhando WordPress faz tempo, e o que me incomoda não é a existência de bugs (todo software tem bugs). O que me incomoda é o padrão.
get_page_template() é uma função que existe desde 2016. A validate_file() já estava sendo usada na branch de cima. Alguém simplesmente esqueceu de adicionar na branch de baixo. Dez anos.
Isso não é um bug sofisticado. Não é uma race condition obscura ou um side-channel attack. É um if que faltou. E esse if faltando afeta 43% de todos os sites da internet (segundo dados da W3Techs para setembro de 2026).
O WordPress é o sistema de gerenciamento de conteúdo mais usado do mundo. E em 2026, a equipe de segurança está basicamente jogando whack-a-mole com falhas no core. Três RCEs em três meses não é coincidência: é sintoma de uma base de código enorme, com décadas de legado, onde cada revisão de segurança encontra mais buracos.
Isso não significa que você deve abandonar o WordPress (embora a Cloudflare esteja tentando te convencer disso com o EmDash). Significa que você precisa tratar segurança como prioridade número um: atualizações automáticas ligadas, WAF configurado, backups diários, e um plano de resposta a incidentes.
Checklist de ação
Se você administra sites WordPress, aqui está o que fazer agora:
- Atualizar para WordPress 7.1.2 (ou o patch da sua branch)
- Verificar se
register_argc_argvestá desabilitado - Remover
pearcmd.phpse PEAR não é usado - Auditar logs de acesso dos últimos 7 dias
- Confirmar que atualizações automáticas de segurança estão habilitadas
- Considerar um WAF como Cloudflare, Sucuri ou Patchstack
- Verificar se há contas de administrador desconhecidas (resquício do wp2shell de julho)
A próxima CVE crítica no WordPress não é uma questão de “se”, mas de “quando”. Quem estiver preparado vai dormir tranquilo. Quem não estiver, bom, vai descobrir pelo Google Search Console que o site agora redireciona para farmácia online.














