Falar com a gente
Menu
#segurança #infraestrutura #engenharia

PHP2Shell: falhas críticas no PHP e como se proteger

As falhas críticas no PHP CVE-2026-109618 e CVE-2026-109619 deixam invadir o servidor sem login. Veja como corrigir, mesmo sem poder atualizar.

Publicado em · por Wilson Molin Junior · 12 min de leitura

Em resumo

Em 21 de outubro de 2026 saíram correções de emergência para duas falhas críticas no PHP, a CVE-2026-109618 e a CVE-2026-109619, apelidadas de PHP2Shell. As duas permitem que alguém sem login execute código no seu servidor usando requisições HTTP. A correção completa é atualizar para o PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, ou para o pacote corrigido da sua distribuição, e reiniciar o PHP. Quem não pode atualizar hoje tem medidas que reduzem o risco, mas não o eliminam.

Atualização em 23 de outubro: o PHP divulgou outra falha, a CVE-2026-115560, bem mais restrita. A configuração session.upload_progress.enabled=0, recomendada abaixo, também a bloqueia. Os detalhes estão em Nova falha no PHP CVE-2026-115560.

O que aconteceu

O projeto PHP publicou as versões 8.5.12, 8.4.27, 8.3.36 e 8.2.35 às 11h (horário de Brasília) desta quarta-feira, 21 de outubro. Elas corrigem duas falhas com nota 9,2 de 10 no CVSS, a escala usada para medir a gravidade de vulnerabilidades.

As duas levam à execução remota de código: o atacante faz o servidor rodar comandos dele, com as permissões do usuário que roda o PHP. A partir daí ele pode ler a configuração do site, as senhas do banco de dados e as chaves de API, trocar páginas ou instalar programas no servidor.

Segundo o aviso oficial, está em risco toda instalação do PHP que atende requisições web: PHP-FPM, Apache com mod_php, php-cgi, FrankenPHP e LiteSpeed. O caso mais grave é o mod_php, em que uma requisição sem login dispara o ataque antes de qualquer código da aplicação rodar. Senha forte, plugin de segurança ou tela de login na aplicação não protegem.

Como a falha está na linguagem, e não num sistema específico, ela alcança WordPress, Drupal, Joomla, Magento, Laravel e qualquer outro sistema em PHP. A Calif, empresa que reportou as falhas primeiro, confirmou o ataque sem login contra versões recentes de WordPress, Drupal, Joomla, Magento, Nextcloud e phpMyAdmin, entre outros.

As duas falhas, sem jargão

O PHP atende o site com workers: processos que recebem uma requisição atrás da outra. As duas falhas exploram o que acontece quando uma requisição é interrompida no meio.

CVE-2026-109618: memória que acaba na hora errada

Todo PHP tem um teto de memória por requisição, o memory_limit. Quando uma requisição bate nesse teto, o PHP aborta a operação na hora. Em alguns pontos, porém, ele já tinha marcado dados internos como prontos antes de terminar de prepará-los. Ao encerrar a requisição, trata esses dados pela metade como válidos e corrompe a memória.

O atacante provoca isso de propósito com envios de formulário com arquivos (multipart) montados para esgotar a memória: requisições sem tamanho declarado, partes com cabeçalhos demais ou campos de arquivo vazios com nomes aninhados. No mod_php, a execução de código foi demonstrada com a configuração padrão. A correção muda o jeito de o PHP lidar com a falta de memória: em vez de abortar no meio da operação, ele espera um ponto seguro para encerrar a requisição.

CVE-2026-109619: sobra de uma requisição usada pela próxima

Alguns dados internos do PHP, de erro, de sessão e de extensões, sobrevivem de uma requisição para a outra no mesmo worker. Se a requisição anterior terminou com um erro fatal, uma falta de memória ou um tempo esgotado, esses dados podem continuar apontando para memória que já foi liberada. A requisição seguinte usa essa memória, um erro conhecido como use-after-free (uso depois de liberar), e o atacante consegue vazar dados da memória do servidor ou executar código.

Para isso ele precisa de duas peças no mesmo worker: uma requisição que deixa a sobra e outra que a usa antes de o PHP reiniciar esse estado. As que usam a sobra, confirmadas até agora, são o progresso de upload da sessão (session.upload_progress) e os avisos de configuração aplicada por diretório, como um php_value inválido no .htaccess.

Como as falhas foram encontradas

Os primeiros sinais apareceram em 2024. Um desenvolvedor do núcleo do PHP viu o problema de falta de memória enquanto corrigia outra falha. Na época, um ataque foi teorizado, mas ninguém tinha um caminho concreto para ele.

Em 30 de julho de 2026, a Calif começou a auditar o PHP dentro do Patch the Planet, iniciativa da OpenAI com projetos de código aberto. O pesquisador Ryan Austin estudava justamente o que acontece quando uma requisição estoura o limite de memória e, em 1º de agosto, achou o primeiro caminho. Segundo a Calif, o achado veio do conhecimento do histórico de falhas do PHP. Depois dele, a equipe usou agentes de IA para procurar o mesmo padrão no resto do código.

A cronologia, pelos relatos da Calif e da PHP Foundation:

  • 11 de agosto: a Calif reporta a primeira falha. A OpenAI reporta a mesma causa no mesmo dia.
  • 14 e 15 de agosto: a Calif envia uma prova de execução de código, e o PHP confirma que ela funciona.
  • 21 de agosto: a Calif reporta a segunda falha.
  • 24 de agosto: a Wiz, que chegou ao problema de forma independente, também reporta.
  • 20 de outubro, por volta do meio-dia: os números das CVEs começam a circular em fóruns e redes sociais, com data errada e nota 10. O PHP antecipa o aviso e traz a publicação do dia 22 para o dia 21.
  • 20 de outubro, no fim da tarde: a Calif publica por engano um vídeo do ataque funcionando em vários alvos, que se espalha pelas redes.
  • 21 de outubro, de madrugada: a Chainguard publica imagens com a correção antes do horário combinado, o que permite estudar a mudança antes da hora.
  • 21 de outubro, 11h: saem as versões corrigidas e os avisos oficiais.

A correção levou dois meses. Ela mexe no controle de memória e no tratamento de erros, partes que quase toda requisição usa. A PHP Foundation reconheceu que a demora também veio do seu processo de decisão e da falta de recursos, e anunciou mudanças nos dois.

Segundo a equipe de segurança do PHP, não havia ataque funcional público no momento da publicação. A Amazon, porém, diz ter registrado uma tentativa de exploração em 17 de outubro e outras no dia 21, e a Cloudflare relatou os primeiros ataques no dia da publicação. Já circula código de ataque na internet. Não rode esse código para testar o seu servidor: ninguém o verificou, e ele pode trazer malware.

Se você pode atualizar

Atualizar é a única correção completa. Estas são as versões que trazem a correção:

Versão em usoAtualize para
8.58.5.12
8.48.4.27
8.38.3.36
8.28.2.35
8.1, 8.0 e 7.4sem versão oficial (veja abaixo)
7.3 ou anteriorsem correção do PHP

Descubra primeiro a versão que o servidor web usa. O php -v mostra a versão de linha de comando, que pode ser outra. O binário do FPM (php-fpm8.3 -v no Debian e no Ubuntu) ou uma página com phpinfo(), apagada logo em seguida, mostram a versão certa.

Depois atualize pelo mesmo caminho por onde o PHP foi instalado:

  • Pacote da distribuição (apt, dnf): as distribuições Linux e os fornecedores de suporte estendido receberam a correção antes da divulgação. Algumas aplicam a correção sem mudar o número da versão do PHP, só o sufixo do pacote. Confira pelo histórico do pacote: apt changelog php8.3-fpm | grep CVE-2026-109618 ou rpm -q --changelog php-fpm | grep CVE-2026-109618.
  • Repositório do Remi: o PHP avisou que ele não teria atualização no dia da divulgação e recomenda trocar pelos pacotes da distribuição ou compilar do código-fonte.
  • Docker: troque a imagem base por uma versão corrigida, refaça a imagem e suba os containers de novo.
  • Hospedagem compartilhada ou painel (cPanel, Plesk): quem atualiza é o provedor. Confira a versão no painel e pergunte ao suporte se a correção já foi aplicada.
  • Código-fonte: baixe a versão corrigida em php.net e compile.

Reinicie o PHP-FPM e o Apache em seguida (systemctl restart php8.3-fpm, systemctl restart apache2). Um worker antigo continua rodando o código vulnerável até ser reiniciado. Confira a versão de novo depois do reinício.

Se você não pode atualizar agora

As medidas abaixo fecham os caminhos de ataque conhecidos, mas não as variantes. O PHP é claro: elas reduzem a exposição e não deixam a instalação segura. A CISA, agência de cibersegurança dos Estados Unidos, recomenda tirar do ar o sistema em PHP que não possa ser atualizado de imediato. Quando isso não for possível, aplique tudo o que couber e marque a data da atualização.

Feche os caminhos conhecidos na configuração

Aplique no php.ini, no pool do PHP-FPM ou na configuração do Apache. Não use ini_set() nem .user.ini: eles agem tarde demais, e a aplicação pode desfazer a mudança. Num pool do PHP-FPM:

; /etc/php/8.3/fpm/pool.d/www.conf
; tira o teto de memória que o ataque usa (CVE-2026-109618)
php_admin_value[memory_limit] = -1
; desliga o progresso de upload da sessão (CVE-2026-109619)
php_admin_flag[session.upload_progress.enabled] = off
; limita o tamanho do envio: 8M sem upload de arquivos, 32M com
php_admin_value[post_max_size] = 8M

No Apache com mod_php, as mesmas diretivas vão no VirtualHost:

php_admin_value memory_limit -1
php_admin_flag session.upload_progress.enabled off
php_admin_value post_max_size 8M

O que cada uma faz e o que custa:

  • memory_limit = -1: sem teto, o atacante não consegue forçar a falta de memória pelo limite do PHP. O custo é que uma requisição pode consumir a memória toda do servidor. Compense com um limite no container ou no cgroup, de preferência um que derrube só o worker afetado, e acompanhe o uso de memória. Não use ulimit (RLIMIT_AS ou RLIMIT_DATA) para isso: ele faz a alocação falhar e reabre o caminho vulnerável. Volte o limite normal depois de atualizar.
  • session.upload_progress.enabled = off: o recurso só serve para barras de progresso de upload, e poucas aplicações o usam. O PHP recomenda deixá-lo desligado mesmo depois da atualização, se você não precisa dele.
  • post_max_size baixo: reduz o espaço para montar o ataque. Mantenha upload_max_filesize menor que post_max_size.
  • No PHP 8.5, fatal_error_backtraces = off: fecha o caminho confirmado que passa pelo rastro de erros fatais.

Reinicie todos os workers depois de mudar a configuração e confira que nenhum pool, .htaccess ou configuração da aplicação volta a impor um limite de memória.

Barre o ataque antes de ele chegar ao PHP

No Nginx, no Apache ou no proxy, limite o tamanho da requisição, inclusive das que chegam sem tamanho declarado, e o número de campos, de partes de upload e de cabeçalhos. No PHP, baixe max_input_vars e max_input_nesting_level. Se a aplicação não recebe arquivos, bloqueie as requisições multipart/form-data antes do PHP.

Um WAF (firewall de aplicação web, um filtro que examina o tráfego antes de ele chegar ao servidor) ajuda como paliativo. A Cloudflare publicou regras para os ataques conhecidos, liberadas em todos os planos, inclusive no gratuito. Elas só cobrem o tráfego que passa pela Cloudflare, e já há tentativas de contorno.

Corrija o que termina em erro fatal

A segunda falha depende de uma requisição que termina em erro fatal ou tempo esgotado. Revise o log de erros e corrija os erros fatais que um visitante consegue provocar: upload, importação, páginas de erro. Tire do .htaccess as diretivas php_value inválidas ou obsoletas, que geram avisos antes de a requisição começar. Esconder os erros com display_errors, error_reporting ou @ não adianta.

Se o desempenho não for prioridade, pm.max_requests = 1 no pool do PHP-FPM faz cada worker atender uma única requisição, e não sobra nada para a próxima. O custo é um servidor bem mais lento.

PHP 8.1 ou mais antigo

Não há versão oficial corrigida. A equipe de segurança do PHP publicou correções mínimas no código-fonte do 7.4, do 8.0 e do 8.1, para quem compila o próprio PHP. Quem usa uma distribuição com suporte estendido deve procurar a correção do fornecedor. Do 7.3 para trás, até o 5.4, não há correção: isole o sistema, deixe-o acessível só por VPN ou por uma lista de IPs, e planeje a migração para o 8.4 ou o 8.5.

Depois de corrigir, procure sinais de invasão

Atualizar fecha a porta, mas não expulsa quem já entrou. A Amazon recomenda revisar o período desde 17 de outubro. Procure por:

  • worker do PHP abrindo um shell ou rodando id, whoami, curl, wget, base64 ou nc;
  • arquivos novos em /tmp, /dev/shm, /var/tmp ou nas pastas em que o usuário do site pode gravar, e arquivos PHP desconhecidos nas pastas do site;
  • mudanças em authorized_keys e tarefas novas no cron do usuário do site;
  • usuários novos ou alterados no banco da aplicação, como administradores no WordPress;
  • no log, muitos POST grandes do mesmo IP, erros PHP Fatal error com in Unknown on line 0 e envios com o campo PHP_SESSION_UPLOAD_PROGRESS;
  • conexões de saída estranhas a partir do servidor.

Apague também as sessões gravadas na pasta de session.save_path: uma sessão adulterada antes da correção continua sendo lida até expirar. Os usuários vão precisar entrar de novo.

Se encontrar algum sinal, trate como invasão: isole o servidor, troque as senhas e chaves a que ele tinha acesso (banco de dados, APIs, arquivos .env) e restaure de um backup anterior ao ataque.

O que fazer hoje

  1. Liste todo servidor, container e hospedagem com PHP, inclusive os esquecidos: site antigo, painel, phpMyAdmin.
  2. Atualize e reinicie, começando pelo que está exposto na internet e pelo que roda mod_php.
  3. Onde não der para atualizar hoje, aplique as medidas de configuração e marque a data da atualização.
  4. Revise os logs desde 17 de outubro.
  5. Se você roda o PHP 8.2 ou anterior, planeje a migração: o 8.2 deixa de receber correções em 31 de dezembro de 2026.

Atualizar servidores e aplicar essas medidas sem derrubar o site é o dia a dia da nossa gestão de servidores. Se a sua aplicação precisa de ajustes para rodar numa versão nova do PHP, veja o nosso desenvolvimento web sob medida.

Fontes