Mitigação PHP2Shell: o que Configurar e Por que Não Basta

Os três ajustes oficiais compram horas, não segurança. Veja onde aplicar, como reiniciar cada worker PHP e o que fazer até o patch entrar.

por Cleverson Gouvêa

Terminal de servidor Linux com configuração do PHP-FPM aberta para aplicar a mitigação PHP2Shell

A mitigação PHP2Shell que você aplica hoje no php.ini compra tempo, mas não fecha a porta. As duas falhas (CVE-2026-109618 e CVE-2026-109619) permitem execução remota de código sem login em praticamente qualquer servidor PHP exposto. Neste guia eu mostro o que configurar enquanto a atualização não sai, como reiniciar todos os workers do jeito certo e por que o próprio time do PHP diz que nada disso substitui o patch.

TL;DR

  • O PHP2Shell são duas falhas críticas (CVSS 4.0 = 9.2), sem autenticação. A correção saiu em 21/10/2026 nas versões 8.5.12, 8.4.27, 8.3.36 e 8.2.35.
  • A mitigação PHP2Shell oficial tem três ajustes: memory_limit=-1, session.upload_progress.enabled=0 e, no PHP 8.5, fatal_error_backtraces=0. Eles reduzem a exposição, mas não deixam o servidor seguro.
  • Configuração só vale depois que cada processo PHP é reiniciado: FPM, Apache com mod_php, filas, workers longos e containers.
  • PHP 7.4 a 8.1 só têm backports mínimos de código-fonte. PHP 5.4 a 7.3 não têm correção nenhuma: a saída é migrar.
  • Em 23/10 saiu um alerta extra (CVE-2026-115560). Quem já desligou o upload progress está coberto até a próxima release regular.

O que é o PHP2Shell e por que a pressa

O PHP2Shell é o apelido de duas vulnerabilidades no núcleo do PHP que permitem a um atacante anônimo rodar código no seu servidor com uma requisição HTTP bem montada. Não precisa de senha, de plugin vulnerável nem de erro da aplicação.

  • CVE-2026-109618 é uma corrupção por falta de memória (out-of-memory). O PHP fica sem memória no meio da montagem da requisição, deixa estruturas internas pela metade e, na limpeza, usa esses dados inválidos.
  • CVE-2026-109619 é um problema de estado global obsoleto, um use-after-free entre requisições. Um estado interno sobrevive à memória da requisição anterior, e a próxima requisição atendida pelo mesmo worker age sobre esse resto.

A linha do tempo explica a urgência. Segundo o FAQ da Tenable, a Amazon registrou uma tentativa de exploração em seus honeypots em 17/10, quatro dias antes da divulgação. Os detalhes vazaram em redes sociais em 20/10, antes da data combinada, e o PHP antecipou o patch para 21/10/2026. A watchTowr relata tentativas de exploração na sua rede de honeypots desde o dia 21.

O alcance também assusta. A Palo Alto Networks (dona da Unit 42) disse ter identificado mais de 22,6 milhões de instâncias expostas potencialmente vulneráveis, conforme a TechTarget. Outras contagens são menores, porque cada empresa mede de um jeito. O recado é o mesmo para todas: se você roda WordPress, Laravel, Moodle ou um sistema PHP próprio, está no escopo.

Quais versões estão afetadas

Ramo do PHP Situação O que fazer
8.5 Corrigido na 8.5.12 Atualizar já
8.4 Corrigido na 8.4.27 Atualizar já
8.3 Corrigido na 8.3.36 Atualizar já
8.2 Corrigido na 8.2.35 Atualizar e planejar saída (fim de vida em 31/12/2026)
7.4, 8.0 e 8.1 Sem release oficial; só backports mínimos de código-fonte Pacote de distro/LTS ou migrar para 8.2+
5.4 a 7.3 Sem correção Migrar ou tirar da internet

Mitigação PHP2Shell em três ajustes oficiais

O aviso de segurança do PHP lista três configurações de mitigação PHP2Shell para quem ainda não consegue atualizar. Cada uma ataca um caminho específico de exploração, e nenhuma cobre tudo.

1. memory_limit=-1 (contra a CVE-2026-109618)

A falha de out-of-memory depende de o PHP bater no teto de memória num ponto previsível. Com memory_limit=-1, esse teto por requisição deixa de existir. O PHP pede que o ajuste seja feito de forma que a aplicação não consiga sobrescrever, por exemplo com php_admin_value no pool do FPM ou na configuração do Apache, e que você confira se nenhum pool, diretório ou aplicação recoloca um limite finito.

O time do PHP faz um alerta que pega muita gente: não substitua por RLIMIT_AS ou RLIMIT_DATA, porque esses limites do sistema operacional podem provocar justamente a falha de alocação vulnerável.

2. session.upload_progress.enabled=0 (contra a CVE-2026-109619)

O recurso de upload progress das sessões vem ligado por padrão e é um dos caminhos confirmados de exploração. Desligar fecha esse caminho. O próprio PHP avisa que isso "bloqueia os caminhos confirmados de sessão, mas não outras variantes".

3. fatal_error_backtraces=0 (só no PHP 8.5)

No PHP 8.5, o backtrace de erro fatal é outro caminho confirmado da CVE-2026-109619. Desligar bloqueia apenas esse caminho.

Onde colocar (e onde não colocar)

A regra de ouro da mitigação PHP2Shell é simples: o ajuste precisa valer antes de o PHP processar a requisição. Use php.ini, o pool do FPM ou a configuração do servidor web. Não confie em ini_set() nem em .user.ini, porque eles entram tarde demais.

; /etc/php/8.3/fpm/pool.d/www.conf (ajuste o caminho à sua versão)
php_admin_value[memory_limit] = -1
php_admin_value[session.upload_progress.enabled] = 0
; somente PHP 8.5:
php_admin_value[fatal_error_backtraces] = 0

O guia da CIQ para Rocky Linux acrescenta dois reforços opcionais: post_max_size = 8M quando a aplicação não recebe uploads (32M quando recebe, com upload_max_filesize abaixo disso) e pm.max_requests = 1 no FPM, que impede a herança de estado entre requisições ao custo de muita performance.

Por que a mitigação PHP2Shell não basta

Aqui mora o erro mais caro: aplicar os três ajustes, ver o site no ar e riscar a tarefa da lista. O PHP é direto no aviso: essas medidas reduzem a exposição, mas não tornam a instalação segura. A única correção completa é atualizar.

São quatro motivos práticos:

  1. Cobertura parcial. A mitigação PHP2Shell fecha os caminhos confirmados. As variantes que ninguém publicou ainda continuam abertas.
  2. memory_limit=-1 não elimina a falha de memória. Segundo a CIQ, falhas de mmap() ou outras alocações ainda podem chegar ao trecho vulnerável. Você só tira o gatilho mais fácil.
  3. Efeito colateral real. Sem limite de memória, um script com loop infinito ou relatório pesado pode consumir a RAM inteira do servidor e acionar o OOM killer do Linux. A recomendação é colocar um limite por container ou cgroup, de preferência um grupo por worker. O PHP trata isso como barreira de disponibilidade, não como mitigação completa.
  4. WAF ajuda, mas não decide. A Cloudflare publicou regras emergenciais, mas elas só protegem o tráfego que passa por ela, e a própria empresa reconhece que regras baseadas em requisição não separam com confiança ataque de tráfego legítimo.

Tabela de decisão rápida

Ajuste Bloqueia Não bloqueia Custo
memory_limit=-1 Gatilho previsível de OOM Falhas de mmap() e outras alocações Risco de um script derrubar o servidor
session.upload_progress.enabled=0 Caminhos de sessão confirmados Outras variantes da 109619 Some a barra de progresso nativa de upload
fatal_error_backtraces=0 (8.5) Caminho do backtrace fatal Demais caminhos Menos detalhe nos logs de erro
pm.max_requests=1 Herança de estado entre requisições A falha de OOM Queda forte de performance
WAF (Cloudflare etc.) Parte dos payloads conhecidos Tráfego que não passa pelo WAF Falsos positivos

A CISA, agência de cibersegurança dos EUA, foi mais longe: recomendou tirar do ar os sistemas PHP que não puderem ser corrigidos ou que rodem PHP 8.1 ou anterior. A CERT-EU sugere isolar aplicações expostas até a correção ser aplicada e verificada.

Como reiniciar workers sem deixar processo velho para trás

Configuração nova e binário novo só passam a valer quando cada processo PHP é reiniciado. O PHP repete isso em cada item do aviso: "reinicie todos os workers". Na prática, é aqui que muita correção fica pela metade: sem restart, a mitigação PHP2Shell existe só no arquivo.

PHP-FPM e Apache

# Debian/Ubuntu (ajuste a versão)
sudo systemctl restart php8.3-fpm
# Apache com mod_php: restart completo, não apenas graceful
sudo systemctl restart apache2   # ou httpd no RHEL/Rocky

Prefiro restart a reload numa correção de segurança. É um corte de poucos segundos, que você programa, em troca da certeza de que nenhum processo antigo sobreviveu.

Os processos que todo mundo esquece

A CIQ lembra que todos os processos PHP precisam reiniciar, inclusive jobs de CLI de longa duração. Na lista de verificação entram:

  • Filas Laravel: php artisan queue:restart (ou reinício do Horizon) e Octane com php artisan octane:reload.
  • Programas do Supervisor: sudo supervisorctl restart all nos grupos que rodam PHP.
  • Moodle: o cron e os executores de tarefas ad hoc que ficam rodando em loop.
  • Containers: docker restart reaproveita a mesma imagem. Você precisa baixar a imagem corrigida e recriar o container (docker compose pull && docker compose up -d).
  • Aplicações que embutem o próprio PHP: dependem de atualização do fornecedor.

Como provar que deu certo

Não confie no php -v do terminal: ele mostra a CLI, que pode ser outro binário. Verifique o que o servidor web está usando:

  1. Crie um arquivo temporário, acessível só pelo seu IP, com <?php echo PHP_VERSION, ' ', ini_get('memory_limit'), ' ', ini_get('session.upload_progress.enabled');. Acesse, confira e apague o arquivo.
  2. Veja a hora de início dos processos com ps -o pid,lstart,cmd -C php-fpm8.3. Tudo precisa ser mais novo que a instalação do pacote.
  3. No Debian/Ubuntu, o needrestart lista serviços que ainda carregam bibliotecas antigas.

Plano de 72 horas: o que fazer, em que ordem

Se você tem um servidor PHP exposto e ainda não atualizou, esta é a ordem que eu seguiria para combinar mitigação PHP2Shell e atualização:

  1. Inventário (hora 0). Liste todos os hosts com PHP, versão, SAPI (FPM, mod_php, CGI) e quem é exposto à internet. O mod_php é o mais exposto, com RCE confirmado em configuração padrão.
  2. Preserve logs. Antes de reiniciar ou reconstruir, guarde os logs do servidor web. A Amazon recomenda investigar a partir de 17/10.
  3. Aplique a mitigação PHP2Shell (horas 1-2) nos três ajustes, no lugar certo, e reinicie todos os workers.
  4. Atualize (horas 2-24). Ramos 8.2 a 8.5: pacote da distribuição ou do repositório que você usa. 7.4 a 8.1: pacote LTS da distro, se existir. 5.4 a 7.3: isole e agende a migração.
  5. Reinicie de novo e verifique com os três testes acima.
  6. Caça a vestígios (horas 24-72). Arquivos PHP novos em pastas de upload, usuários administrativos criados nos últimos dias, cron estranho. Como lembram os analistas ouvidos pela TechTarget, atualizar não remove um acesso que o atacante já conseguiu. Em servidor exposto e sem patch, troque as credenciais que o worker PHP tinha em memória (banco, APIs, SMTP).
  7. Só então reverta o que for incômodo, como o memory_limit=-1, devolvendo um limite finito razoável.

Quando NÃO aplicar a mitigação PHP2Shell às cegas

  • Servidor pequeno e compartilhado com muitos sites: memory_limit=-1 sem cgroup é convite para um site derrubar todos. Nesse caso, atualizar direto costuma ser mais seguro que mitigar.
  • Aplicação que mostra barra de progresso de upload usando o recurso nativo de sessão: avise o time antes, porque a barra vai parar.
  • Ambiente que você não consegue reiniciar fora de janela: o ajuste não vale nada até o restart. Negocie a janela agora.

O alerta de 23/10: CVE-2026-115560

Dois dias depois do patch, o PHP publicou um aviso informativo sobre a CVE-2026-115560, um vetor de RCE que afeta inclusive versões já corrigidas, como a 8.5.12. A boa notícia: ele só existe se a aplicação definir session.serialize_handler como php_binary ou php_serialize na configuração e trocar para php em tempo de execução com ini_set() antes do session_start(), com o upload progress ainda ligado.

O PHP classificou o cenário como improvável e vai corrigi-lo na próxima release regular. A orientação é manter session.upload_progress.enabled=0 até lá. Se você aplicou esse item da mitigação PHP2Shell no dia 21, não precisa fazer mais nada, como resumiu The Hacker News. Por isso, não reverta esse ajuste junto com o memory_limit depois do patch.

O que isso significa para Moodle, WordPress e Laravel

O PHP2Shell atinge o interpretador, não a aplicação. Então não adianta esperar atualização do Moodle ou do WordPress: quem resolve é o pacote PHP do servidor.

No Moodle, o ponto de atenção é memória. O próprio Moodle eleva o limite em tempo de execução em tarefas pesadas, como backup de curso e relatórios. Com memory_limit=-1 isso deixa de ser problema, mas um backup grande passa a poder consumir a RAM toda. Se você ainda está no PHP 8.1 por causa de uma versão antiga do Moodle, este é o momento de rever os requisitos de servidor para Moodle 5.x e planejar o salto.

No WordPress e no Laravel, o cuidado maior é com workers longos (filas, Octane, cron do sistema) e com hospedagens compartilhadas em que você não controla o PHP. Se o seu provedor não informou a versão e a data do reinício, pergunte por escrito.

A mitigação PHP2Shell também não substitui o básico. Se o servidor nunca passou por um checklist de hardening de servidor Linux, ou se ainda não tem WAF, fail2ban e rate limit, a próxima falha vai encontrar a mesma porta aberta.

Como a Agathas Web resolve isso

A pergunta que este incidente deixou para muita empresa não é técnica: é quem estava de plantão no dia 21. Quando a correção sai às 14h UTC de uma quarta-feira, alguém precisa inventariar, aplicar, reiniciar, verificar e caçar vestígios no mesmo dia. Se essa pessoa não existe no seu time, esse é o serviço que vendemos.

Na hospedagem gerenciada da Agathas Web, a sustentação inclui:

  • Atualização de sistema operacional, runtime (PHP, Node, Python), banco e plugins críticos, em janela combinada e com teste em staging antes da produção.
  • Monitoramento contínuo (uptime, performance, erros e logs) com Grafana, Prometheus e Sentry, e alerta no WhatsApp da equipe técnica.
  • WAF da Cloudflare com regras customizadas, fail2ban, rate limit e hardening do sistema operacional.
  • Backup diário e incremental, criptografado e fora do servidor, com restauração testada todo mês.
  • Resposta em até 15 minutos para incidentes críticos, com SLA no contrato e plano de incidente documentado.
  • Atendimento direto com quem opera o seu ambiente, sem central de nível 1 lendo roteiro.

Como funciona: começamos com um diagnóstico do ambiente atual (versões, SAPI, workers, exposição). Se fizer sentido migrar, fazemos a migração em até 7 dias úteis com plano de rollback. Depois disso, alertas como este entram no nosso fluxo de sustentação: a mitigação PHP2Shell (ou a equivalente da próxima falha) no intervalo até o patch, a atualização em janela combinada e o reinício verificado dos workers, sem você precisar abrir chamado. Para contratar, fale com a equipe pelo WhatsApp na página da hospedagem gerenciada e descreva o que roda hoje. Se o seu caso é um AVA, também temos a hospedagem Moodle dedicada.

Conclusão: mitigue hoje, atualize amanhã, verifique sempre

A mitigação PHP2Shell é um torniquete. Ela segura o sangramento por algumas horas enquanto você atualiza para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, reinicia todos os workers e confirma pelo servidor web que a versão nova está rodando. Quem parou no php.ini está menos exposto, mas continua exposto.

Se você ainda roda PHP 8.1 ou anterior, o PHP2Shell é o empurrão que faltava: não haverá release oficial para esses ramos. E se o seu servidor depende de alguém lembrar de olhar as notícias de segurança, talvez o problema real seja esse. Conheça a hospedagem gerenciada da Agathas Web e deixe o próximo patch de emergência com quem opera servidor todo dia.

Perguntas frequentes

A mitigação PHP2Shell protege meu servidor sem atualizar o PHP?

Não. O próprio PHP afirma que os ajustes reduzem a exposição, mas não tornam a instalação segura. O memory_limit=-1 tira o gatilho mais previsível da CVE-2026-109618, e desligar o session.upload_progress e o fatal_error_backtraces fecha os caminhos confirmados da CVE-2026-109619. Variantes ainda não publicadas e falhas de alocação como as de mmap() continuam possíveis. Trate a mitigação como ponte de algumas horas até instalar 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 e reiniciar todos os processos PHP.

Posso aplicar memory_limit=-1 com ini_set() ou .user.ini?

Não funciona. O ataque acontece durante o processamento da requisição, antes de o seu código rodar, então ini_set() e .user.ini entram tarde demais. O ajuste precisa estar no php.ini, no pool do PHP-FPM (de preferência com php_admin_value, que a aplicação não consegue sobrescrever) ou na configuração do Apache. Depois, confira se nenhum outro pool, diretório ou aplicação recoloca um limite finito, e reinicie todos os workers. Também evite trocar por RLIMIT_AS ou RLIMIT_DATA: o PHP avisa que eles podem provocar justamente a falha vulnerável.

Basta dar reload no PHP-FPM depois de atualizar?

Em correção de segurança, prefira restart completo do PHP-FPM e, no caso do mod_php, do Apache. Além deles, reinicie tudo que roda PHP por muito tempo: filas do Laravel (queue:restart ou Horizon), Octane, programas do Supervisor e executores do cron do Moodle. Em Docker, recriar o container com a imagem nova é obrigatório, porque docker restart reaproveita a imagem antiga. Para confirmar, verifique a versão por uma requisição web, não pelo php -v da linha de comando, e compare a hora de início dos processos com a da instalação do pacote.

Uso PHP 7.4 ou 8.1. O que fazer contra o PHP2Shell?

Esses ramos não terão release oficial: o PHP publicou apenas backports mínimos de código-fonte para 7.4, 8.0 e 8.1, que exigem compilar o PHP. O caminho mais seguro é o pacote corrigido da sua distribuição ou de um fornecedor LTS, se existir, ou a migração para 8.2 ou superior. No PHP 5.4 a 7.3 não há correção nenhuma. Enquanto a migração não sai, aplique a mitigação, coloque o servidor atrás de um WAF e restrinja o acesso. A CISA chegou a recomendar tirar do ar sistemas que rodem PHP 8.1 ou anterior.

A CVE-2026-115560 exige outra mitigação?

Para a maioria dos ambientes, não. O PHP publicou em 23/10/2026 um aviso informativo sobre esse vetor de RCE, que afeta até as versões já corrigidas. Ele só existe quando a aplicação muda o session.serialize_handler em tempo de execução com ini_set() antes do session_start(), com o upload progress ligado. A orientação oficial é manter session.upload_progress.enabled=0 até a próxima release regular. Quem aplicou esse ajuste no dia 21 já está coberto, e por isso ele não deve ser revertido junto com o memory_limit depois do patch.