DEV Community

Cover image for O prompt de AppSec que eu criei achou 4 gaps de segurança
Tiago Vilas Boas (Montanha)
Tiago Vilas Boas (Montanha)

Posted on Edited on

O prompt de AppSec que eu criei achou 4 gaps de segurança

Eu quase cometi o maior pecado da segurança de software: quase mandei um relatório gerado por IA com 23 "vulnerabilidades" direto para os mantenedores de grandes projetos open source.

O modelo me devolveu uma lista enorme cheia de termos impressionantes: XSS crítico, falha de CORS, cabeçalho CSP ausente e até um arquivo SVG "potencialmente perigoso". À primeira vista, parecia um trabalho brilhante. Mas antes de clicar em enviar, eu me perguntei: se eu fosse o engenheiro mantendo esse repositório, eu levaria esse relatório a sério?

A resposta foi um sonoro NÃO. Dos 23 alertas gerados na primeira rodada sem contrato, 17 eram avisos inofensivos de formatação de strings e cabeçalhos opcionais de dev, 5 eram suposições sobre dependências sem vetor de ataque explorável e exatamente zero tratava de quebra de regras de negócio. O ruído foi de 22 descartes em 23 apontamentos (95,6% de falsos alarmes medidos).

A virada de chave aconteceu quando entendi que pedir para a IA "audite a segurança do meu código" é a pior abordagem possível. Para obter auditoria real de segurança (AppSec) com IA, você precisa de direção e disciplina.

Neste artigo, vou mostrar como estruturar um contrato estrito de auditoria, por que scanners tradicionais não acham falhas de autorização e como a postura responsável de divulgação separa um engenheiro de um gerador de spam.


1. O Problema: Scanners Vêem o Que Está Lá; o "Hunt" Vê o Que Falta

Scanners estáticos convencionais (como Semgrep, SonarQube ou CodeQL) são fundamentais. Eles rodam no CI em segundos e procuram padrões sintáticos conhecidos: funções depreciadas, queries concatenadas e variáveis sem tipagem.

Mas eles têm um ponto cego crítico: falhas lógicas de autorização (BOLA / IDOR - OWASP API1:2023).

[ Código Vulnerável a IDOR ]
app.get('/api/pedido/:id', async (req, res) => {
    // Sintaticamente perfeito! O linter e o scanner estático aprovam com louvor.
    // Mas cadê a validação de quem é o dono desse pedido?
    const pedido = await db.pedidos.findUnique({ where: { id: req.params.id } });
    return res.json(pedido);
});
Enter fullscreen mode Exit fullscreen mode

Para o scanner tradicional, o código acima usa métodos seguros do ORM. Mas semanticamente, qualquer usuário autenticado pode ver o pedido de outro cliente trocando o ID na URL!

É aqui que entra o Code Hunt orientado por invariantes. Em vez de uma busca genérica, formulamos uma pergunta cirúrgica:

"Em toda rota que devolve dados de pedidos, existe a garantia explícita de que o tenant_id ou o user_id da sessão logada faz parte do filtro de busca?"


2. A Disciplina do Prompt de AppSec: Cortando o Teatro da IA

Se você não der limites severos, a IA vai inventar vulnerabilidades apenas para não admitir que o código está seguro.

Para impedir alucinações, o modelo deve operar sob um contrato de auditoria estrito:

                  ┌───────────────────────────────────────────┐
                  │          Contrato de Auditoria            │
                  └─────────────────────┬─────────────────────┘
                                        │
           ┌────────────────────────────┼────────────────────────────┐
           ▼                            ▼                            ▼
  [ Padrão Externo ]           [ Invariante Única ]          [ Regra de Fato ]
  Exclusivamente OWASP         Uma afirmação objetiva        Sem arquivo:linha
  ASVS 5.0 com IDs reais       e falsificável por rota       NÃO É FINDING
           │                            │                            │
           └────────────────────────────┼────────────────────────────┘
                                        │
                                        ▼
                  ┌───────────────────────────────────────────┐
                  │    Denominador Obrigatório (X de Y)       │
                  │ "Encontrei 1 rota insegura de 174 rotas"  │
                  └───────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

As Regras de Ouro da Disciplina:

  • Sem arquivo:linha exato: O achado é descartado sumariamente.
  • CWE ou CVE inventado: A sessão é abortada na hora.
  • Denominador obrigatório: Dizer que "achou um bug" sem dizer quantas rotas foram analisadas não é ciência, é achismo. Exija sempre: "1 de 174 rotas auditadas falhou".
  • Quem acha não corrige na mesma sessão: Separar a etapa de descoberta da etapa de correção impede que o modelo faça gambiarras no código motivado pelo calor do momento.

3. Silêncio Também é Resultado

Em segurança da informação, não encontrar falhas é uma vitória, não um fracasso.

Quando rodei esse protocolo em repositórios abertos de alta relevância (como Cal.com, Dub, Formbricks e Medusa):

  • Em vários módulos de webhooks, 8 de 8 verificavam rigorosamente a assinatura criptográfica antes de processar eventos.
  • Em vez de forçar a barra e abrir issues barulhentas elogiando o código, o resultado correto é o silêncio.

O resumo dessa disciplina em números reais:

Repositório Aberto O Que a Disciplina Fez Resultado Real
Formbricks Descartou falso positivo de XSS; encontrou configuração contraditória de CORS Hardening aceito: Issue #9081
Dub.co 7 de 7 webhooks autenticados; apontou uso de !== em comparação de hash Sugestão de timing safe: Issue #4415
Cal.com 8 de 8 webhooks autenticados; padronização de timingSafeEqual Hardening reportado: Issue #30100
Repositório Privado De 174 rotas analisadas, 173 estavam seguras e 1 rota possuía gap de autorização 1 IDOR real corrigido antes de produção

Sem o contrato estrito, o modelo teria aberto dezenas de falsos relatórios, queimando credibilidade com os mantenedores.


4. As Três Portas da Divulgação Responsável (Responsible Disclosure)

Achar um gap de segurança com IA é apenas 20% do trabalho. Os outros 80% são saber onde e como reportar:

[ Finding Confirmado com Evidência ]
                 │
                 ├──> Porta 1: Issue Pública no GitHub
                 │    APENAS para melhorias gerais de configuração (hardening),
                 │    cabeçalhos ou avisos já tratados no README.
                 │
                 ├──> Porta 2: Canal Privado (Security Advisory / E-mail do Time)
                 │    OBRIGATÓRIO para falhas de autorização (IDOR), vazamento de
                 │    chaves, SQL injection ou bypass de login. NUNCA publique no tracker!
                 │
                 └──> Porta 3: O Arquivo Local (Silêncio)
                      Quando a invariante foi respeitada ou o risco não possui
                      impacto real comprovado.
Enter fullscreen mode Exit fullscreen mode

Como Orquestrar Isso no Seu Ambiente

Para executar varreduras desse tipo sem gastar fortunas de API:

  1. Comece com uma análise local de complexidade: utilize o Downshift (harness-downshift) em Go para verificar o tamanho dos handlers e a complexidade do escopo.
  2. Encaminhe para modelos de ponta com alto raciocínio lógico (como Claude Sonnet 5.5 ou Opus) via OpenRouter somente para a etapa de validação da invariante, mantendo os custos sob controle.

Referências Técnicas Canônicas

Para quem deseja se aprofundar em segurança de aplicações, autorização em APIs e auditoria orientada a contratos:


O Que Você Pode Fazer Amanhã no Seu Time

No seu próximo code review ou investigação de segurança:

  1. Defina a invariante antes de ler o código: ex: "Nenhum usuário atualiza o registro X sem pertencer à organização Y".
  2. Rode o linter/scanner padrão primeiro: deixe a máquina fazer o trabalho mecânico de regex.
  3. Use a IA apenas para validar a invariante: exigindo sempre arquivo:linha e denominador completo.

Segurança séria com IA não é sobre quantidade de alarmes gerados. É sobre a precisão cirúrgica de impedir que falhas reais de negócio cheguem aos usuários.

Top comments (0)