Pular para o conteúdo

Incidente · Sênior

Cloudbleed 2017: parser vaza memória pela borda da CDN

Incidente real. Pontos centrais: bug de memória em parser e expurgo de caches de terceiros.

14 min de leitura · Incidente em 2017, durou · Fonte: Cloudflare · Conteúdo revisado em 23 de outubro de 2026

Resposta curta

Incidente real. Pontos centrais: bug de memória em parser e expurgo de caches de terceiros. Em 18 de fevereiro de 2017, a Cloudflare recebeu do Google os detalhes de um problema: um pesquisador do Project Zero havia visto páginas corrompidas devolvidas por servidores de borda. O post-mortem público da empresa é a fonte deste caso.

01 · CONTEXTO

Uma borda que reescreve o HTML dos outros

Em 18 de fevereiro de 2017, a Cloudflare recebeu do Google os detalhes de um problema: um pesquisador do Project Zero havia visto páginas corrompidas devolvidas por servidores de borda. O post-mortem público da empresa é a fonte deste caso.

Na borda da rede, a Cloudflare lê e modifica o HTML das respostas em trânsito, por exemplo para reescrever links, esconder partes da página de robôs ou ofuscar endereços de e-mail. Para isso, precisa analisar o HTML e achar os elementos que mudam.

O analisador original, escrito com a ferramenta Ragel, servia a todas essas modificações. A empresa passou a escrever um novo, o cf-html, e migrava funcionalidades aos poucos do antigo para ele. Os dois são módulos do NGINX que analisam buffers com HTML, fazem as alterações e passam os buffers adiante.

  1. No processo HTTP da borda, os dois analisadores são módulos de filtro: cada um recebe os buffers com HTML, modifica o que for preciso e passa adiante.

    Diagrama da arquitetura: Filtros de HTML na borda
    CLVisitante
    CPTerminação SSL isolada
    EDGProcesso HTTP da borda
    CPAnalisador antigo
    CPAnalisador novo
    CPServidor de origem
  2. O analisador antigo era o original; o novo foi escrito para substituí-lo, e as funcionalidades migravam aos poucos de um para o outro.

    Diagrama da arquitetura: Filtros de HTML na borda
    CLVisitante
    CPTerminação SSL isolada
    EDGProcesso HTTP da borda
    CPAnalisador antigoantigo
    CPAnalisador novonovo
    CPServidor de origem
  3. A terminação SSL ficava numa instância isolada de NGINX, que o bug não afetou.

    Diagrama da arquitetura: Filtros de HTML na borda
    CLVisitante
    CPTerminação SSL isoladaisolada
    EDGProcesso HTTP da borda
    CPAnalisador antigo
    CPAnalisador novo
    CPServidor de origem

02 · O BUG LATENTE

Um erro de ponteiro que dormiu por anos

A causa raiz foi um erro de ponteiro: o fim do buffer era verificado com um teste de igualdade, e o ponteiro podia pular o fim e seguir adiante, o que se chama estouro de buffer. Uma verificação com maior ou igual teria pego o salto. Esse teste era gerado automaticamente pelo Ragel, o que indicou que a ferramenta não estava sendo usada corretamente.

O código escrito pela equipe tinha um tratador de erro sem o fhold, que recua o ponteiro em uma posição. Esse recuo ausente foi o que causou o vazamento. Se a página terminava com uma tag HTML quebrada, o erro ocorria no fim do buffer e o ponteiro ficava depois do fim do documento. Acrescentar o fhold ao tratador corrige o problema.

O defeito existia havia muitos anos no analisador antigo, mas nenhuma memória vazava por causa da forma como os buffers internos do NGINX eram usados. Ao introduzir o cf-html, o uso dos buffers mudou sutilmente e permitiu o vazamento, embora o próprio cf-html não tivesse problema.

A diferença estava no que o analisador sabia sobre o último buffer. Com os dois analisadores presentes, o último buffer com dados chegava marcado como final, e o tratamento de erro rodava.

SituaçãoSó o analisador antigoOs dois analisadores
Marcação do último buffer com dadosMarcado como não sendo o últimoMarcado como o último
Fim de arquivo (eof)NuloAponta para o fim do buffer
Bloco de erroNão é executadoÉ executado

Para a memória vazar, o último buffer com dados tinha de terminar com uma tag de script ou de imagem malformada e ter menos de 4k. Além disso, o cliente precisava ter ativo um recurso que combinasse os dois analisadores, como o Email Obfuscation. Essas condições explicam por que o estouro ocorria tão raramente.

03 · O IMPACTO

Memória de um cliente na página de outro

A memória vazada vinha de um processo baseado em NGINX que trata HTTP e podia conter cabeçalhos, trechos de corpos de POST (talvez com senhas), JSON de chamadas de API, parâmetros de URI, cookies e credenciais como chaves de API e tokens OAuth.

Como a infraestrutura é compartilhada, uma requisição a um site vulnerável podia revelar informação de outro site da Cloudflare.

  1. Em certas condições, o processo HTTP da borda lia além do fim de um buffer e devolvia memória com dados privados, como cookies, tokens e corpos de POST.

    Diagrama da arquitetura: Caminho do vazamento até o cache
    CLVisitante de outro site
    EDGProcesso HTTP da bordalê além do buffer
    CPProcesso SSL isolado
    CPSite do cliente vulnerável
    CLRastreador de buscador
    CHCache do buscador
  2. Por ser uma infraestrutura compartilhada, a memória devolvida podia trazer informação de outro site da Cloudflare.

    Diagrama da arquitetura: Caminho do vazamento até o cache
    CLVisitante de outro sitedados em trânsito
    EDGProcesso HTTP da borda
    CPProcesso SSL isolado
    CPSite do cliente vulnerável
    CLRastreador de buscador
    CHCache do buscador
  3. As chaves privadas SSL dos clientes não vazaram: o processo de SSL tem heap separado do processo que trata HTTP.

    Diagrama da arquitetura: Caminho do vazamento até o cache
    CLVisitante de outro site
    EDGProcesso HTTP da borda
    CPProcesso SSL isoladonão afetado
    CPSite do cliente vulnerável
    CLRastreador de buscador
    CHCache do buscador
  4. Buscadores guardaram parte da memória vazada em cache, por seus processos normais de rastreamento.

    Diagrama da arquitetura: Caminho do vazamento até o cache
    CLVisitante de outro site
    EDGProcesso HTTP da borda
    CPProcesso SSL isolado
    CPSite do cliente vulnerável
    CLRastreador de buscador
    CHCache do buscadormemória em cache
  5. A empresa, com os buscadores, identificou as URIs em cache e pediu o expurgo antes de anunciar o problema.

    Diagrama da arquitetura: Caminho do vazamento até o cache
    CLVisitante de outro site
    EDGProcesso HTTP da borda
    CPProcesso SSL isolado
    CPSite do cliente vulnerável
    CLRastreador de buscador
    CHCache do buscadorexpurgo

Mesmo com as chaves SSL dos clientes protegidas, vazou uma chave privada usada nas conexões entre as máquinas da própria Cloudflare, e havia na memória alguns segredos internos de autenticação.

No pior período, de 13 a 18 de fevereiro, cerca de 1 em cada 3.300.000 requisições HTTP podia vazar memória. A empresa não encontrou evidências de exploração maliciosa.

04 · RESPOSTA E EXPURGO

Desligar por recurso, depois limpar os caches

Uma equipe multifuncional se formou em São Francisco e Londres, e o trabalho passava entre os escritórios a cada 12 horas para que a equipe atuasse 24 horas por dia.

Três recursos usavam a mesma cadeia de parser HTML causadora do vazamento. Todo recurso da Cloudflare tem uma feature flag, chamada de global kill, e desligá-los fez com que a memória não pudesse mais ser devolvida em respostas HTTP.

  1. Três recursos usavam a mesma cadeia de parser HTML que causava o vazamento.

    Diagrama da arquitetura: Desligamento global dos recursos
    CPControle de feature flags
    CPEmail Obfuscationusa a cadeia
    CPAutomatic HTTPS Rewritesusa a cadeia
    CPServer-Side Excludesusa a cadeia
    EDGCadeia de parser HTML
  2. A chave de desligamento global do Email Obfuscation foi acionada 47 minutos após a empresa receber os detalhes do problema.

    Diagrama da arquitetura: Desligamento global dos recursos
    CPControle de feature flags
    CPEmail Obfuscationdesligado
    CPAutomatic HTTPS Rewrites
    CPServer-Side Excludes
    EDGCadeia de parser HTML
  3. A do Automatic HTTPS Rewrites foi acionada 3h05m depois. Desligar um recurso levou poucos segundos em todo o mundo.

    Diagrama da arquitetura: Desligamento global dos recursos
    CPControle de feature flags
    CPEmail Obfuscation
    CPAutomatic HTTPS Rewritesdesligado
    CPServer-Side Excludes
    EDGCadeia de parser HTML
  4. O Server-Side Excludes também era vulnerável e não tinha chave global, por ser anterior a esse mecanismo. A empresa criou a chave e implantou um patch na frota.

    Diagrama da arquitetura: Desligamento global dos recursos
    CPControle de feature flags
    CPEmail Obfuscation
    CPAutomatic HTTPS Rewrites
    CPServer-Side Excludessem chave global
    EDGCadeia de parser HTML
  5. Com os recursos desligados, a memória já não podia ser devolvida em respostas HTTP.

    Diagrama da arquitetura: Desligamento global dos recursos
    CPControle de feature flags
    CPEmail Obfuscation
    CPAutomatic HTTPS Rewrites
    CPServer-Side Excludes
    EDGCadeia de parser HTMLsem retorno de memória
RecursoComo entrava no vazamentoAlcance
Email ObfuscationUsava os dois analisadoresAlterado em 13 de fevereiro; principal causa da memória vazada
Automatic HTTPS RewritesUsa o analisador novo; só vazava em combinação com outro recurso do analisador antigoPouco usado
Server-Side ExcludesUsa o analisador novo; só vazava em combinação com outro recurso do analisador antigoExecuta só para IPs de má reputação

A empresa cita que o padrão da indústria para corrigir um bug assim costuma ser de três meses, e que terminou globalmente em menos de 7 horas, com mitigação inicial em 47 minutos.

Como buscadores tinham guardado parte da memória vazada, a equipe de segurança identificou as URIs em cache e pediu o expurgo antes do anúncio público, por entender que tinha o dever de cuidado. Com a ajuda dos buscadores, foram achadas 770 URIs únicas em 161 domínios.

05 · LIÇÕES

Caçar o resto do bug e olhar para o código antigo

Depois de achar um estouro de ponteiro no código gerado, a equipe foi atrás de outros. Parte do time de segurança fez fuzzing do código gerado, outra equipe montou testes com páginas malformadas encontradas na internet, e engenheiros inspecionaram o código manualmente.

Decidiu-se também adicionar checagens explícitas a todo acesso por ponteiro no código gerado e registrar os erros. Com esse registro, cada linha de log indicava uma requisição que poderia ter vazado memória.

Perguntas frequentes

O que é Cloudbleed 2017: parser vaza memória pela borda da CDN?

Incidente real. Pontos centrais: bug de memória em parser e expurgo de caches de terceiros.

O que o design de Cloudbleed 2017: parser vaza memória pela borda da CDN cobre?

Ele está organizado nestas seções: Uma borda que reescreve o HTML dos outros, Um erro de ponteiro que dormiu por anos, Memória de um cliente na página de outro, Desligar por recurso, depois limpar os caches e Caçar o resto do bug e olhar para o código antigo.

Quanto tempo leva Cloudbleed 2017: parser vaza memória pela borda da CDN e qual é o nível?

Leva cerca de 14 minutos para ler e tem nível Sênior.

Agora projete você mesmo

Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.