Por que a NSA e a CISA estão pedindo o fim do C e do C++ em software crítico

Em junho de 2025, a Agência de Segurança Nacional dos Estados Unidos (NSA) e a Agência de Segurança Cibernética e de Infraestrutura (CISA) publicaram, em conjunto, um documento técnico com um recado direto para quem constrói software crítico: é hora de abandonar C e C++ como linguagens padrão e migrar para linguagens “memory-safe” — seguras quanto ao gerenciamento de memória — como Rust. O documento, Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development, não é uma opinião isolada nem moda passageira de comunidade de desenvolvedores. É a formalização de uma postura que o governo americano já vinha sinalizando desde 2022 e que, em 2025, ganhou o peso de recomendação técnica detalhada, com números, exemplos e caminho de adoção.

O argumento central não é sobre preferência de sintaxe ou produtividade — é sobre uma classe específica de falha que, há décadas, responde pela fatia mais expressiva das vulnerabilidades críticas exploradas em software real. Bugs de gerenciamento de memória, como estouro de buffer, uso de memória já liberada ou desreferenciamento de ponteiro nulo, permitem que um atacante corrompa a memória de um programa em execução e, na pior hipótese, execute código arbitrário remotamente. Segundo dados que a própria NSA cita no relatório, coletados por Microsoft, Google e Apple ao longo de quase uma década, entre metade e três quartos das vulnerabilidades críticas corrigidas nesses sistemas se enquadram nessa categoria.

Este artigo explica o que são esses bugs de memória, por que décadas de ferramentas de mitigação não resolveram o problema na raiz, o que muda quando uma linguagem impõe segurança de memória em tempo de compilação, e como essa recomendação já está em prática em sistemas que rodam bilhões de dispositivos.

O que é, na prática, um bug de segurança de memória

Linguagens como C e C++ dão ao programador controle manual e direto sobre a memória do computador: é o próprio código que aloca um espaço de memória, o usa e depois o libera. Essa flexibilidade é também a origem do problema. Se o programa tentar escrever além dos limites de um espaço alocado — o clássico buffer overflow —, ele pode sobrescrever dados adjacentes, incluindo estruturas de controle do próprio programa, como o endereço de retorno de uma função. Um atacante que consiga provocar esse erro de forma controlada pode, em muitos casos, redirecionar a execução do programa para código malicioso de sua escolha — uma execução remota de código (RCE), a categoria de vulnerabilidade mais grave que existe.

Outras variações do mesmo problema incluem o use-after-free (o programa continua usando um bloco de memória já liberado, permitindo que um atacante reaproveite aquele espaço com dados forjados), o double free (liberar o mesmo bloco duas vezes, corrompendo as estruturas internas do gerenciador de memória) e o desreferenciamento de ponteiro nulo. Nenhuma dessas falhas exige um erro de lógica sofisticado — costumam nascer de um cálculo de tamanho de array ou uma condição de borda mal tratada.

O que torna essa classe de bug particularmente perigosa não é só a frequência, mas a gravidade típica das consequências. Enquanto muitas vulnerabilidades levam a vazamento de informação ou negação de serviço, corrupção de memória tende a abrir caminho direto para execução de código arbitrário — por isso aparece de forma desproporcional entre as vulnerabilidades críticas e entre as efetivamente exploradas por atacantes reais, não apenas relatadas teoricamente.

Os números que sustentam a recomendação

O relatório da NSA e da CISA reúne dados de telemetria interna de diferentes fabricantes, e o padrão é consistente entre plataformas distintas. A Microsoft relatou que, em 2016, cerca de 70% das CVEs corrigidas em seus produtos estavam relacionadas a memória; anos depois, mesmo com investimento pesado em mitigação, a proporção continuava perto de 50%. A Apple encontrou 66% das CVEs do iOS 12 e 71% das do macOS Mojave associadas a problemas de memória. O Project Zero, do Google, ao estudar exploits usados ativamente contra usuários reais, identificou que 75% das CVEs exploradas eram falhas de memória — e, olhando só para dias zero em 2021, a proporção foi de 67%.

O caso do Android documenta uma trajetória, não apenas uma fotografia. Em 2019, segundo dados que o próprio Google publicou em seu blog de segurança, 76% das vulnerabilidades do Android eram relacionadas a memória — acima da média histórica do setor, então em torno de 70%. Em 2024, essa fatia havia caído para 24%; em novembro de 2025, o Google anunciou que a proporção caiu pela primeira vez para menos de 20% — inversão completa da tendência histórica, no mesmo período em que o código novo do Android passou a ser escrito predominantemente em Rust.

Vale uma ressalva: a proporção não caiu porque essas falhas passaram a ser mais bem encontradas — caiu porque a quantidade absoluta delas despencou. O guia “The Case for Memory Safe Roadmaps”, publicado em dezembro de 2023 pela CISA, NSA, FBI e autoridades de cibersegurança da Austrália, Canadá, Reino Unido e Nova Zelândia, resume um dado incômodo sobre a eficácia das abordagens anteriores: mesmo após décadas de investimento em mitigação, cerca de dois terços das vulnerabilidades relatadas em linguagens sem segurança de memória continuam sendo vulnerabilidades de memória.

Por que sanitizers, fuzzing e análise estática não resolveram o problema

A resposta da indústria a esse problema, por muito tempo, não foi trocar de linguagem, mas empilhar ferramentas em torno de C e C++: sanitizers como AddressSanitizer e MemorySanitizer, que instrumentam o binário para detectar corrupção de memória em tempo de execução; fuzzing, que bombardeia o programa com entradas aleatórias na esperança de provocar um crash revelador; analisadores estáticos, que tentam identificar padrões perigosos no código-fonte sem executá-lo; e revisão de código cada vez mais rigorosa. São técnicas genuinamente úteis, que reduzem a taxa de bugs em produção — nenhuma delas é dispensável ou está sendo descartada pelas equipes que já adotaram linguagens memory-safe.

O problema é que todas atuam como uma rede de segurança probabilística sobre uma linguagem que, por definição, permite a classe de erro que elas tentam capturar. Um sanitizer só detecta o problema se aquele caminho de código for executado durante o teste; um fuzzer só encontra o que consegue gerar como entrada no tempo disponível; um analisador estático esbarra na dificuldade de rastrear todos os ponteiros e tempos de vida possíveis num programa C ou C++ real, e acaba escolhendo entre excesso de falsos positivos ou casos reais não detectados. Nenhuma abordagem elimina a classe de bug — todas competem, numa corrida permanente, para encontrar instâncias dela antes que um atacante o faça, corrida que nunca termina porque cada nova linha escrita em C/C++ reabre a possibilidade de um novo erro.

É exatamente esse ponto que o relatório da NSA e da CISA aponta como a diferença fundamental de uma linguagem memory-safe: em vez de detectar o erro depois que o código é escrito, o compilador se recusa a aceitar o programa se ele contiver um padrão que poderia levar a uma violação de memória. O erro deixa de ser um risco a ser gerenciado e caçado, e passa a ser, estruturalmente, algo que não compila.

O que muda estruturalmente em uma linguagem memory-safe

Rust implementa segurança de memória por meio de um sistema de tipos com regras de posse (ownership) e empréstimo (borrowing), verificadas em tempo de compilação e sem custo de desempenho em tempo de execução — a principal diferença frente a linguagens memory-safe mais antigas, como Java, C# ou Go, que garantem segurança através de um coletor de lixo (garbage collector), abordagem eficaz mas com sobrecarga de desempenho que historicamente tornou essas linguagens inadequadas para componentes de baixo nível como kernels, drivers e navegadores. O compilador de Rust rastreia quem é o “dono” de cada bloco de memória e por quanto tempo referências a ele permanecem válidas; um programa que tente usar memória já liberada, ter duas referências mutáveis simultâneas ao mesmo dado, ou acessar um índice fora dos limites de um array sem checagem, simplesmente não compila.

O documento lista, entre as linguagens memory-safe, Ada, C#, Delphi/Object Pascal, Go, Java, Python, Ruby, Rust e Swift — mas é explícito ao apontar que nem todas têm o mesmo perfil de aplicabilidade para infraestrutura crítica, justamente pela questão do coletor de lixo. Rust ganha destaque por ser a linguagem madura mais próxima de oferecer o mesmo controle sobre desempenho e memória que C e C++ sem abrir mão da segurança em compilação — o que a torna viável como substituta em componentes onde C e C++ dominam por razões de performance: sistemas operacionais, navegadores, bancos de dados e firmware.

Vale frisar o que essa garantia cobre e o que não cobre: segurança de memória elimina uma classe inteira de vulnerabilidades, mas não elimina bugs de lógica, falhas de autenticação, erros de configuração ou vulnerabilidades em dependências de terceiros. O próprio relatório recomenda que a adoção de linguagens memory-safe seja tratada como parte de uma estratégia mais ampla, alinhada ao NIST Secure Software Development Framework, e não como solução única para todos os problemas de segurança de um software.

Casos reais de migração já em andamento

O argumento deixaria de ser abstrato caso não houvesse evidência de adoção em sistemas que já rodam em escala. O caso mais citado é o do kernel do Linux: depois de anos de debate técnico, o suporte experimental a Rust como segunda linguagem do kernel — ao lado do C, que segue majoritário — foi incorporado a partir da série 6.1, no fim de 2022, com Linus Torvalds confirmando publicamente o caminho de integração. Novos drivers e subsistemas passaram a poder ser escritos em Rust, reduzindo a superfície de código C exposta a erros de memória.

No Android, o Google documentou a transição mais detalhada e mensurável até hoje. Segundo o Google Security Blog, em novembro de 2025 já havia cerca de 5 milhões de linhas de Rust no Android, com densidade de apenas 0,2 vulnerabilidade de memória por milhão de linhas, contra uma estimativa de cerca de 1.000 por milhão de linhas em C/C++ comparável — diferença de mil vezes. O Google também relatou ganhos operacionais: mudanças em Rust têm taxa de reversão 4 vezes menor que as equivalentes em C++ e exigem 20% menos revisões.

O Chromium, motor do Chrome, passou a permitir bibliotecas de terceiros em Rust desde janeiro de 2023, para reduzir código C++ exposto a erros de memória sem reescrever o navegador de uma vez. A Microsoft vem reescrevendo componentes centrais do Windows em Rust desde 2023 — incluindo partes do kernel gráfico (DirectX) —, embora tenha sido clara ao afirmar que não pretende reescrever o Windows inteiro, e sim priorizar Rust em código novo e componentes de alto risco. Em todos os casos, o padrão é o mesmo que a NSA e a CISA recomendam como estratégia realista: priorizar a linguagem memory-safe para código novo, em vez de reescrita completa de sistemas legados de uma vez.

Uma política de segurança de infraestrutura, não uma preferência técnica

Esse relatório não surge isolado. A Casa Branca, através do Office of the National Cyber Director (ONCD), já havia publicado em fevereiro de 2024 o relatório Back to the Building Blocks: A Path Toward Secure and Measurable Software, que argumentava que linguagens memory-safe “podem eliminar a maior parte dos erros de segurança de memória” e recomendava sua priorização como parte da iniciativa mais ampla de Secure by Design, que busca deslocar o ônus da segurança dos usuários finais para os fabricantes de software. Já em novembro de 2022, a própria NSA havia publicado um primeiro documento sobre o tema, que lançou as bases técnicas do relatório de junho de 2025.

O relatório de dezembro de 2023, “The Case for Memory Safe Roadmaps”, foi endereçado a fabricantes de software, pedindo que publiquem roteiros públicos e mensuráveis de migração, como compromisso de responsabilização e liderança executiva — não apenas uma decisão de engenharia interna. O documento de junho de 2025 vai além, funcionando como guia prático de adoção: reconhece os obstáculos reais da transição, da falta de bibliotecas maduras em certos domínios ao custo de treinar equipes numa linguagem nova, e recomenda priorizar código novo e componentes de maior exposição a entradas não confiáveis, em vez de reescritas completas — reconhecendo que trocar de linguagem em sistemas legados de milhões de linhas é processo medido em anos.


Fontes citadas neste artigo:

Deixe um comentário