Pular para o conteúdo
10 min de leitura

Programar com IA sem introduzir vulnerabilidades: o guia de código seguro assistido por LLM

Por Lucas Andrade ·

Assistentes de código aceleram o trabalho, mas herdam padrões inseguros do treino. Como revisar, contextualizar e testar o que a IA escreve para não gerar dívida de segurança.

Neste artigo

Um desenvolvedor pede a um assistente de IA uma função de login em poucos segundos, e o assistente entrega um bloco funcional, bem formatado, com nomes de variáveis razoáveis. O código roda, o teste feliz passa, o pull request segue. O que ninguém notou é que a query de verificação foi montada por concatenação de string, a senha é comparada com um hash de SHA-256 sem salt, e o token de sessão vem de Math.random(). Cada uma dessas escolhas é uma vulnerabilidade clássica, e todas chegaram embrulhadas na confiança que um código limpo e imediato inspira. O assistente não foi malicioso; ele reproduziu, com fluência, os padrões mais comuns que viu durante o treino — e a internet está cheia de exemplos inseguros porque foram escritos para ilustrar um conceito, não para ir a produção.

Assistentes de código baseados em LLM são uma das mudanças mais produtivas na engenharia de software recente, e usá-los é hoje parte do ofício. Mas incorporá-los sem entender como eles erram é trocar velocidade de digitação por dívida de segurança silenciosa. Este guia é sobre extrair a produtividade sem herdar as falhas — porque a responsabilidade pelo código que vai para produção é de quem faz o commit, não do modelo que sugeriu.

Por que o código gerado tende a ser inseguro#

O primeiro passo é entender a natureza do problema. Um LLM de código é treinado para prever a continuação mais provável dado o contexto — ele produz o que é estatisticamente comum, não o que é seguro. E o corpus de código público mistura, sem distinção de qualidade, tutoriais didáticos que ignoram segurança de propósito, respostas de fórum escritas às pressas, projetos antigos com práticas obsoletas, e código de produção sério. O modelo aprende de tudo isso. Quando você pede "conecte ao banco e busque o usuário", o padrão mais frequente que ele viu talvez seja a concatenação insegura, simplesmente porque tutoriais introdutórios a usam por ser mais curta de explicar.

Há um agravante: o modelo não tem, por padrão, o contexto de ameaça da sua aplicação. Ele não sabe que aquele endpoint é público, que aquele campo vem de usuário não confiável, que aquele sistema é multi-tenant e um vazamento cross-tenant seria catastrófico. Ele completa o padrão local sem o modelo de ameaças global. E como o resultado é sintaticamente perfeito e confiante, o viés de automação humano faz o revisor baixar a guarda: código que parece competente recebe menos escrutínio do que mereceria.

A regra mestra: você é o revisor, não o consumidor#

A mudança de postura mais importante é parar de tratar a saída da IA como algo a aceitar e passar a tratá-la como algo a revisar — com o mesmo rigor, ou mais, que você aplicaria ao pull request de um colega júnior talentoso mas descuidado com segurança. O código gerado é uma proposta, não uma decisão. Toda linha que vai para o seu commit é sua, e a autoria implica responsabilidade: se um incidente rastrear até aquela concatenação, "a IA escreveu" não é defesa técnica nem profissional.

Na prática, isso significa ler cada sugestão perguntando ativamente onde estão as fronteiras de confiança. De onde vem esse dado? Ele é usado numa query, num comando, numa renderização de HTML? Há autorização verificada no servidor antes desta ação? Segredos aparecem em texto no código? A resposta a essas perguntas não está no código gerado — está no seu entendimento da aplicação, e é exatamente o que a IA não tem.

As classes de falha que mais aparecem#

Alguns padrões inseguros reaparecem com frequência suficiente para merecer atenção especial ao revisar código de IA. Injeção é campeã: queries montadas por concatenação em vez de parâmetros, comandos de shell interpolados com entrada. Autenticação frágil: hashing de senha com algoritmo rápido em vez de argon2id ou bcrypt, tokens de Math.random(), comparação de segredo que vaza tempo. Controle de acesso ausente: endpoints que confiam no id vindo do cliente sem verificar propriedade, o clássico IDOR, especialmente porque o modelo completa o CRUD "feliz" sem pensar em autorização. Segredos embutidos: chaves de API e senhas coladas no código como valor literal, às vezes até chaves reais que vazaram para o treino. Tratamento de erro que engole exceções ou devolve o erro cru do banco ao cliente. E, no front-end, o uso de dangerouslySetInnerHTML ou innerHTML com dado que a IA não sabe se é confiável.

Conhecer essa lista transforma a revisão de código de IA num processo dirigido: em vez de reler tudo com atenção uniforme, você caça deliberadamente esses padrões, que é onde a probabilidade de falha se concentra.

Contexto no prompt: pedir seguro rende seguro#

A qualidade da saída melhora sensivelmente quando o contexto de segurança entra no pedido. Um prompt genérico convida ao padrão genérico; um prompt que especifica as restrições move a distribuição para o lado seguro. Pedir explicitamente "use consultas parametrizadas", "gere o token com um CSPRNG", "valide autorização no servidor com base no usuário do token", "não coloque segredos no código, leia de variável de ambiente" costuma produzir código que já nasce mais defensável. Fornecer o contexto de ameaça — "este endpoint é público e recebe entrada não confiável", "este sistema é multi-tenant" — ativa o modelo a considerar as fronteiras que ele ignoraria por padrão.

Ainda assim, prompt melhor não substitui revisão. Ele aumenta a fração de saídas seguras, mas o modelo continua probabilístico e continua capaz de, mesmo instruído, escorregar num detalhe. O contexto no prompt é uma alavanca de qualidade, não uma garantia — e tratá-lo como garantia é recriar o problema original num nível mais sutil.

Fechar a rede com automação#

A defesa mais escalável contra a introdução de falhas — por IA ou por humano — é não depender só de olhos no code review, e sim ancorar gates automáticos no pipeline. Análise estática (SAST) marca queries concatenadas, sinks perigosos e uso de funções fracas independentemente de quem escreveu o código. Varredura de dependências (SCA) pega o pacote vulnerável que o modelo sugeriu importar — inclusive o caso em que a IA "alucina" o nome de um pacote que não existe e um atacante o registra com código malicioso, um vetor real conhecido como slopsquatting. Varredura de segredos barra a chave que vazou para o commit. Linters de segurança e a compilação em modo estrito pegam o resto. Esses gates tratam o código gerado exatamente como qualquer outro: ele precisa passar pelas mesmas catracas, sem exceção por ter vindo rápido.

O ponto sutil é resistir à tentação de afrouxar os gates porque a IA "produz muito". Se o volume de código sobe, a disciplina de verificação precisa subir junto, não ceder. Baixar o limiar de cobertura, silenciar um alerta de SAST ou pular a revisão porque "é só o que a IA gerou" é como o código inseguro entra em produção em escala.

Alucinação de dependências e a cadeia de suprimentos#

Um risco específico do código assistido por IA merece uma seção própria porque é novo e contraintuitivo: a alucinação de nomes de pacotes. Modelos, ao sugerir imports, às vezes inventam o nome de uma biblioteca que soa plausível mas não existe — uma composição estatística de nomes reais. Isso seria inofensivo se apenas quebrasse o build, mas atacantes perceberam o padrão e registram, nos repositórios públicos de pacotes, exatamente esses nomes alucinados recorrentes, preenchendo-os com código malicioso. Quando um desenvolvedor copia a sugestão sem verificar e roda a instalação, ele baixa e executa o pacote do atacante. O ataque, apelidado de slopsquatting, é uma variação de typosquatting alimentada pela previsibilidade das alucinações do modelo.

A defesa começa com um reflexo simples: todo pacote que a IA sugere é verificado antes de entrar no projeto. Existe? Quem o mantém? Tem histórico, downloads, código-fonte auditável? A versão é a esperada? Esse escrutínio se estende à cadeia inteira — a IA pode sugerir uma dependência real, porém abandonada, vulnerável ou com licença incompatível. Trate cada sugestão de import com a mesma desconfiança que você teria ao adicionar um dependência qualquer manualmente, porque é exatamente isso que ela é: uma adição à sua cadeia de suprimentos, com todo o risco que isso carrega. Varredura automática de dependências no pipeline fecha a rede, mas o primeiro filtro é humano e barato.

Nem todo código gerado merece o mesmo escrutínio#

Um contrapeso honesto: aplicar rigor máximo a toda linha gerada é irreal e desnecessário, e insistir nisso leva o time a abandonar a disciplina por exaustão. O critério que sustenta a prática no longo prazo é calibrar o escrutínio pelo risco do trecho. Código que não toca dados sensíveis, não cruza fronteira de confiança e não decide autorização — um utilitário de formatação de data, um helper de layout, um teste — pode ser aceito com revisão leve, porque uma falha ali tem impacto contido. Já código que processa entrada não confiável, monta queries, verifica identidade, decide permissão, manipula segredo, renderiza HTML de terceiro ou dá poder a um agente merece o escrutínio máximo, porque é onde uma falha vira incidente. Saber distinguir os dois é uma habilidade de engenharia de segurança em si: é a mesma priorização por fronteira de confiança que orienta o threat modeling, aplicada agora ao ato de revisar sugestões de IA. Gastar atenção onde o risco está concentrado, e economizá-la onde ele é irrelevante, é o que torna a disciplina sustentável em vez de um teatro que ninguém mantém.

A IA também é boa defensora#

Vale inverter a lente: o mesmo modelo que introduz falhas é uma ferramenta poderosa para encontrá-las. Pedir a um assistente que revise um trecho procurando vulnerabilidades, que explique o modelo de ameaças de uma função, ou que sugira casos de teste hostis (entrada com aspas, unicode, byte nulo, valores de fronteira) costuma render achados úteis e amplia a cobertura de teste barata. Usar a IA como um segundo par de olhos adversarial no code review, ou para gerar casos de teste de segurança que você não pensaria, é um uso legítimo e produtivo — desde que os achados sejam validados, porque o revisor de IA também erra e também tem pontos cegos. A postura equilibrada é usá-la nos dois papéis, gerador e revisor, sem confiar cegamente em nenhum dos dois.

O princípio que não muda#

Ferramentas mudam a velocidade e o formato do trabalho, mas não mudam o princípio: código seguro é resultado de intenção, verificação e camadas, não de sorte na primeira sugestão. A IA acelera a produção de código e, sem contrapeso, acelera na mesma proporção a produção de dívida de segurança. O contrapeso é um desenvolvedor que entende as classes de falha, revisa cada sugestão como proposta e não como verdade, injeta contexto de segurança no pedido, e apoia tudo isso em gates automáticos que não se dobram ao volume. Feito assim, o assistente vira um multiplicador legítimo de produtividade. Feito sem isso, ele vira um gerador industrial de vulnerabilidades bem formatadas — e o custo aparece depois, quando alguém troca um número na URL e encontra o que não deveria.

Leituras relacionadas

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly