Pular para o conteúdo
    AnáliseSegurança e privacidade

    PHP2Shell: as falhas críticas achadas com IA e a promessa quebrada do PHP

    Duas falhas de execução remota sem autenticação no PHP, uma delas achada com o GPT‑5.6 Sol, violam a premissa de que cada requisição nasce limpa. A análise cobre o mecanismo, o que atualizar e o quanto a narrativa da OpenAI se sustenta.

    Elefante azul de pelúcia sobre bancada de oficina, com etiqueta de correção 8.5.12 presa à orelha, iluminado por luz lateral de fim de tarde
    Duas falhas críticas de execução remota sem autenticação colocam em xeque a premissa de que cada requisição no PHP começa limpa; a correção chega na versão 8.5.12.
    Neste artigo

    O PHP sempre fez ao programador uma promessa pouco declarada e muito confortável: cada requisição começa do zero e termina sem deixar rastro. Você abre conexões, monta arrays enormes, esquece de liberar coisas, e no fim o interpretador varre tudo. A requisição seguinte chega a um mundo recém-criado. Boa parte da tolerância do PHP com código descuidado vem dessa amnésia programada. As duas vulnerabilidades corrigidas em 21 de outubro, apelidadas de PHP2Shell, interessam menos por serem graves (são) do que pelo lugar onde estão. Ambas moram nas frestas dessa promessa, nos momentos em que o mundo da requisição ainda não terminou de ser construído ou já foi demolido sem que ninguém avisasse.

    O que foi corrigido

    O PHP (abre em nova aba) publicou as versões 8.5.12, 8.4.27, 8.3.36 e 8.2.35 para fechar duas falhas que, segundo o aviso oficial, permitem execução remota de código sem autenticação. As duas receberam nota 9.2 no CVSS v4.0. O projeto anunciou o lançamento na véspera, marcado para as 14h UTC do dia 21, e recomendou atualização imediata.

    A lista de quem está exposto é a parte que deveria tirar o sono de quem opera infraestrutura: todas as instalações de PHP que atendem requisições web, incluindo PHP-FPM, Apache com mod_php, php-cgi, FrankenPHP e LiteSpeed. O time de segurança do PHP considera o risco maior no mod_php, onde há um exploit demonstrado em que uma requisição não autenticada dispara o ataque antes que qualquer código da aplicação rode.

    Administrador de sistemas, de costas, digita em um terminal diante de um rack de servidores em corredor técnico iluminado por luz fria durante a madrugada
    Servidores com Apache e mod_php estão entre os que precisam de atualização imediata para corrigir as falhas de execução remota sem autenticação.

    Esse detalhe muda a conversa. Quase toda defesa que um time de desenvolvimento controla vive dentro da aplicação: validação de entrada, framework atualizado, middleware de autenticação, revisão de código. Uma falha que é explorada antes de a aplicação existir torna tudo isso irrelevante. Não importa se o seu Laravel está em dia ou se o seu WordPress tem só três plugins auditados. O ataque acontece num andar abaixo.

    Duas maneiras de o passado vazar

    A primeira falha, CVE-2026-109618, está documentada no advisory do php-src no GitHub (abre em nova aba). O PHP usa longjmp() para lidar com erros de falta de memória: quando uma alocação falha, o interpretador salta para fora do contexto atual e aborta a requisição. É uma saída de emergência e, como toda saída de emergência, presume que o prédio está num estado em que se pode simplesmente ir embora. O problema aparece quando a alocação falha num instante específico, em que a memória da requisição já está acessível mas ainda não foi inicializada por completo. O salto deixa essa estrutura pela metade. Depois, a rotina de limpeza encontra a estrutura e a trata como válida, porque nada nela indica o contrário.

    Dá para pensar numa ficha de cadastro em que alguém preencheu o nome e foi arrancado da mesa antes de preencher o resto. Quem arquiva a ficha depois não sabe que ela está incompleta. Arquiva assim mesmo, e o lixo que ficou nos campos vazios passa a ser tratado como dado. Segundo o advisory, várias estratégias de esgotamento de memória conseguem provocar essa condição de forma consistente. A execução remota completa foi validada via HTTP contra mod_php com os limites padrão de entrada e de memória e com configurações prefork normais, com múltiplos workers. Para o FPM, a análise do código-fonte indica suscetibilidade, mas nenhum exploit completo foi demonstrado nesse SAPI. Essa distinção merece ser lida com cuidado. "Não demonstrado" não equivale a "não explorável", e ninguém deveria adiar a atualização de um pool FPM por causa dela.

    A segunda falha, CVE-2026-109619, é ainda mais diretamente uma violação da promessa original. Segundo o PHP, um estado interno que pertence à requisição pode sobreviver depois que a memória que o sustentava foi liberada. Uma requisição posterior, atendida pelo mesmo worker, pode usar esse estado velho antes que a inicialização normal o redefina. É o fantasma clássico do use-after-free, agora atravessando a fronteira que o PHP sempre vendeu como intransponível, a que separa uma requisição da seguinte.

    Postas lado a lado, as duas falhas formam um par quase simétrico. A primeira explora o momento em que a requisição ainda não nasceu direito. A segunda explora o momento em que ela já morreu, mas deixou algo para trás. O modelo de "nada compartilhado" do PHP continua verdadeiro na média dos casos. O que essas falhas mostram é que ele nunca foi uma propriedade da linguagem. É uma disciplina que o motor precisa cumprir em cada caminho de execução, inclusive nos caminhos de erro que quase ninguém percorre.

    Por que a correção levou dois meses

    A correção da primeira falha, diz o advisory, remove o uso de longjmp() no tratamento de falta de memória. Parece uma linha num changelog. Na prática, significa reescrever como o interpretador se comporta quando o mundo acaba no meio de uma operação, e esse comportamento está espalhado por um motor com décadas de código C. A OpenAI (abre em nova aba), que coordenou a divulgação, justificou o prazo assim em seu perfil oficial:

    Nos últimos dois meses, lideramos uma coalizão de mantenedores, pesquisadores e fornecedores de segurança para preparar correções e proteções antes da divulgação. Esse prazo foi necessário porque a correção era bastante intrincada e exigiu uma mudança grande no motor do PHP.

    — OpenAI (@OpenAI), 21 de out. de 2026, no X

    Isso ajuda a entender a mitigação oferecida para quem não pode atualizar já. O advisory descreve configurar memory_limit=-1 administrativamente como a principal mitigação por configuração e avisa que ela não é completa. Faz sentido: se o gatilho é provocar falta de memória dentro do limite do PHP, remover o limite tira do atacante a forma mais fácil de puxar a alavanca. Mas a falha continua no código, e um processo sem teto de memória cria seus próprios problemas operacionais num servidor compartilhado. Trate como torniquete, não como cura.

    Para versões antigas, a situação é a de sempre, só que mais aguda. O PHP 8.1 e anteriores não recebem mais atualizações do projeto. Dada a gravidade, o time de segurança publicou backports mínimos em código-fonte para 7.4, 8.0 e 8.1, e algumas distribuições e fornecedores de suporte estendido oferecem correções próprias. Quem roda 7.4 em produção em 2026 acaba de ganhar uma cortesia que não deveria esperar de novo.

    O que a IA fez, e o que não fez

    Aqui a história precisa ser contada com mais precisão do que a manchete permite. Segundo a OpenAI, a empresa Calif identificou uma falha crítica usando o GPT‑5.6 Sol, dentro da iniciativa Patch the Planet. O texto oficial fala em "uma falha", no singular. Na mesma frase, a OpenAI informa que a Wiz (abre em nova aba) também descobriu e reportou, de forma independente, as duas vulnerabilidades. Os créditos do advisory listam quatro relatores, cujos identificadores remetem a organizações diferentes, entre eles um ligado à Wiz e outro à OpenAI. A correção foi desenvolvida por mantenedores do PHP. A própria OpenAI escreve que os mantenedores lideraram as correções e o lançamento.

    Isso não diminui o feito. Um modelo de linguagem participou da descoberta de uma falha de memória num interpretador maduro, num caminho de erro raramente exercitado, e o resultado se sustentou até virar exploit validado. Há poucos anos isso seria ficção. Mas a descoberta independente pela Wiz aponta numa direção menos confortável do que a narrativa oficial sugere: essas falhas eram encontráveis. Se duas equipes chegaram a elas por caminhos distintos, a probabilidade de uma terceira, sem interesse em divulgação coordenada, ter chegado também não é desprezível.

    A OpenAI afirma que, até onde sabe, a IA de fronteira encontrou essas vulnerabilidades antes dos atacantes, e chama isso de "Janela do Defensor". A ressalva "até onde sabemos" está fazendo trabalho pesado nessa frase. A reportagem do BleepingComputer (abre em nova aba) relata que, antes da publicação dos patches, o CTO da Cloudflare (abre em nova aba), Dane Knecht, confirmou que a empresa já observava ataques iniciais contra as duas falhas depois de implantar regras de WAF, e que essas proteções eram temporárias. Não sei, e as fontes não dizem, se esses ataques vieram de quem já conhecia a falha antes, de vazamento durante a coordenação ou de engenharia reversa a partir das próprias regras. Qualquer das três hipóteses mostra que a janela existiu, mas foi estreita, e que se fechou antes de o patch chegar a todos.

    A segunda parte do post oficial deixa claro como a OpenAI quer que o episódio seja lembrado:

    A frase é verdadeira. Também é inevitavelmente simétrica, e a OpenAI só fala de um dos lados. Se a IA consegue encontrar bugs com impacto em escala de internet, consegue para quem tiver acesso a modelos equivalentes. A "Janela do Defensor" não é uma propriedade da tecnologia. É uma vantagem temporária de quem chegou primeiro aos modelos mais capazes, e dura enquanto durar essa diferença de acesso. É nesse contexto que a OpenAI anuncia US$ 1 bilhão em acesso subsidiado ao Daybreak, pelo programa Daybreak for Frontline Defenders. É uma tentativa de alargar a janela distribuindo a ferramenta para o lado certo antes que o outro lado a tenha por conta própria.

    A coreografia em volta

    O episódio também mostra como a divulgação coordenada de uma falha dessas virou um evento de política pública. A OpenAI diz ter envolvido várias partes do governo americano, incluindo a Super Intelligence Force da Casa Branca, o Office of the National Cyber Director e a CISA, além de parceiros internacionais. O BleepingComputer relata que o National Cyber Security Centre do Reino Unido orientou organizações britânicas a atualizar imediatamente os sistemas com PHP ou tirá-los do ar até que pudessem ser corrigidos. Uma agência nacional dizer "desligue se não puder atualizar" é raro e dá a medida da gravidade com mais honestidade do que qualquer adjetivo em comunicado.

    Há um desconforto nesse arranjo que vale nomear. O PHP é um projeto comunitário, e foram seus mantenedores que escreveram a correção difícil. Mas a narrativa pública está sendo contada por uma empresa de IA, que também distribui a ferramenta de verificação e anuncia o programa de subsídio na mesma página. Isso não é desonesto: a OpenAI dá crédito explícito aos mantenedores e à Wiz. Só que, a cada episódio desses, o centro de gravidade da segurança de software aberto se desloca um pouco mais para quem controla os modelos. É bom que haja dinheiro e capacidade entrando nisso. É prudente lembrar que a capacidade de descobrir falhas e a capacidade de corrigi-las ainda estão em mãos diferentes, e que a segunda continua mal financiada.

    O que fazer agora

    A prioridade é simples e não admite nuance: atualizar. A tabela resume a situação por ramo, segundo o aviso do PHP.

    RamoVersão corrigidaObservação
    8.58.5.12Suportado
    8.48.4.27Suportado
    8.38.3.36Suportado
    8.28.2.35Fim de vida em 31/12/2026
    8.1, 8.0, 7.4Sem release oficialBackports mínimos em código-fonte; verificar distribuição ou fornecedor LTS

    Se você está no 8.2, este é o patch que te mantém seguro por pouco mais de dois meses. Planeje a migração agora, enquanto a dor está fresca na memória de quem aprova orçamento.

    Para inventariar o que está exposto, a OpenAI publicou o php2shell-checker (abre em nova aba), distribuído como skill do Codex e também executável diretamente com Node:

    # verificar um site pela URL
    node phpcheck.js "https://example.com"
    
    # verificar o binário PHP local
    node phpcheck.js --local

    No Codex, o README indica pedir $skill-installer install both skills from https://github.com/openai/php2shell-checker. A skill phpcheck-server serve para quando há acesso ao servidor, e a phpcheck-url para quando só se tem a URL. Os códigos de saída são 0 para OK, 1 para VULNERABLE, 3 para UNKNOWN e 2 para argumentos inválidos, o que facilita encaixar a verificação num script de inventário.

    Duas consequências práticas decorrem disso. Servidores bem configurados, que escondem a versão do PHP nos cabeçalhos, vão aparecer como UNKNOWN na verificação por URL, e é justamente nesses que você precisa entrar e rodar a verificação local. Além disso, distribuições que aplicam correções retroativas costumam manter o número de versão antigo. Uma checagem baseada só em versão não tem como saber disso. Para pacotes de distribuição, a fonte de verdade é o aviso de segurança da própria distribuição, não o número que o PHP exibe.

    Por último, saiba qual SAPI você roda. Se é mod_php, você está no cenário com exploit demonstrado, e o tempo conta em horas. Se é FPM, o risco é tecnicamente menos comprovado, mas a análise de código já indica suscetibilidade, e exploits costumam migrar de um SAPI para outro mais depressa do que os advisories são revisados.

    Julgamento

    A OpenAI está certa no essencial: este é um dos incidentes de segurança mais sérios dos últimos anos, e o fato de um modelo ter participado da descoberta numa base de código madura, num caminho de erro obscuro, marca uma mudança real no ofício. Mas a moldura da "Janela do Defensor" é mais otimista do que os fatos sustentam. A Wiz achou as mesmas falhas por conta própria, e a Cloudflare viu ataques antes de o patch sair. Esses dois fatos sugerem que a janela é estreita e que a vantagem do defensor depende de distribuição de acesso, não de alguma assimetria intrínseca da tecnologia. A lição técnica mais duradoura, porém, não é sobre IA. É sobre premissas. O PHP tratou o "cada requisição nasce limpa" como garantia, e ele sempre foi uma promessa cumprida caminho a caminho, inclusive nos caminhos de erro que ninguém testa. Modelos capazes de varrer esses caminhos sem cansaço vão encontrar outras promessas assim em outros runtimes, e a pergunta útil para qualquer equipe técnica não é se a IA vai achar a próxima, mas quanto tempo a sua infraestrutura leva para aplicar um patch depois que alguém achar. Para quem roda PHP hoje, essa pergunta tem prazo: a resposta certa é hoje.

    Filipe Mendes

    Ver perfil completo