Quando uma consulta CodeQL aparentemente correta devolve zero resultados, a frustração é imediata: será que o problema está na base de código ou na lógica da própria consulta? Para desenvolvedores, pesquisadores de segurança e até profissionais de marketing que dependem da confiabilidade de sites e plugins, identificar vulnerabilidades antes que elas virem manchete é essencial. Entender como debugar consultas CodeQL faz toda a diferença entre um relatório vazio e uma descoberta que previne incidentes, multas e queda de reputação.
Nesta quinta parte da série “CodeQL Zero to Hero”, a engenheira de segurança Sylwia Budzynska compartilha um passo a passo detalhado de como transformar uma consulta estagnada em um detector funcional usando técnicas internas da ferramenta. O caso concreto envolve a framework Gradio e uma falha de desserialização insegura via pickle.load() — típica situação em que o usuário faz upload de um arquivo aparentemente inofensivo e, com dois cliques, ganha execução de código no servidor.
Por que consultas CodeQL falham (e como começar a correção)
CodeQL se inspira na lógica de Prolog e avalia programas de forma declarativa. Diferente de Python ou JavaScript, não há “print() de depuração” ou gdb para percorrer a execução. Quando você recebe um resultado inesperado, os motivos costumam ser:
- Fonte ou sink mal definidos.
- Fluxo de dados interrompido por estruturas que CodeQL não propaga automaticamente.
- Consultas muito gerais, gerando ruído ou, ao contrário, muito específicas, gerando silêncio.
O primeiro conselho da autora é reduzir o problema: crie um exemplo mínimo e gere um banco CodeQL apenas com esse código. Isso elimina distrações e acelera a análise.
Ferramentas nativas de depuração no CodeQL
Com o ambiente enxuto, o próximo passo é aplicar recursos internos:
- Quick Evaluation: executa trechos isolados da consulta (predicados e classes) para verificar se retornam algo.
- AST Viewer: mostra a árvore sintática de um arquivo, revelando exatamente como CodeQL enxerga cada nó.
- getAQlClass(): lista as classes CodeQL associadas a um nó, útil para descobrir se aquilo é um
ExprNode,ParameterNode, etc. - Partial Path Graphs: grafa o fluxo parcial entre fonte e possíveis sinks, indicando onde o taint “morre”.
Estudo de caso: desserialização insegura no Gradio
No código simplificado, o usuário faz upload de um arquivo via gr.File. O caminho do arquivo fica em config_file.name. Depois, o app o abre com open() e o desserializa via pickle.load(). Em tese, uma consulta de taint tracking — fonte em gr.File, sink em pickle.load() — deveria denunciar o risco. Mas não denuncia. Eis o que foi feito para chegar ao resultado:
Imagem: Internet
- Verificar fonte e sink: Quick Evaluation confirmou que ambos eram encontrados, porém o sink precisava apontar para o primeiro argumento de
pickle.load(), não para a chamada inteira. - Usar Partial Path Graph: revelou que o taint parava em
config_file, não alcançavaconfig_file.name. - Adicionar taint steps manuais:
- Primeiro, propagou do objeto para o atributo
name. - Depois, ligou o argumento de
open()ao resultado deopen(), permitindo que o fluxo continuasse atépickle.load().
- Primeiro, propagou do objeto para o atributo
- Refinar para evitar falsos positivos: limitou a propagação apenas a objetos do tipo
gr.File.
Com essas duas regras extras na configuração (isAdditionalFlowStep), a consulta final passou a apontar exatamente a linha vulnerável.
Boas práticas para depurar sem enlouquecer
- Mantenha consultas modulares: classes e predicados isolados facilitam Quick Evaluation.
- Sempre comece com o exemplo mínimo; só depois volte ao projeto inteiro.
- Use
explorationLimit()em path graphs para não explodir a memória em bases grandes. - Se precisar de taint steps manuais, documente-os bem — são potenciais fontes de falsos positivos.
Além do “sem resultados”: por que dominar a depuração no CodeQL vale o esforço?
Para equipes que dependem de WordPress, extensões de navegador ou qualquer stack com componentes de terceiros, saber ler — e escrever — consultas CodeQL sob medida é uma vantagem competitiva. Primeiro, porque diminui a janela entre a introdução de um bug e sua correção; segundo, porque antecipa exigências de compliance (LGPD, PCI, etc.) que penalizam falhas de segurança. E, num cenário em que vulnerabilidades viram press releases em minutos, descobrir e corrigir internamente evita crises de reputação e queda de receita publicitária — incluindo AdSense, afiliados e afins.
Mais que encontrar um único bug, o método detalhado por Sylwia Budzynska ensina a pensar como o analisador estático: reduzir o escopo, observar a árvore sintática, traçar fluxos parciais e, quando necessário, ensinar novas regras ao motor. Esse mindset transfere-se para outras linguagens suportadas pelo CodeQL (Java, JavaScript, C/C++), ampliando a cobertura de segurança de qualquer projeto.
No fim das contas, debugar consultas é sobre ganhar visibilidade: entender para onde os dados vão, onde podem ser manipulados e como transformar esse conhecimento em código confiável. Quem domina essa prática não apenas encontra vulnerabilidades — constrói software que inspira confiança.