O changelog do GitHub apresenta o CodeQL 2.27.1 como uma versão de novas queries e suporte a linguagens, mas o ganho real está em outro lugar: menos alerta falso e menos ponto cego no rastreamento de dados.

Scanner estático que grita demais vira ruído. E ruído vira alerta ignorado. É assim que uma vulnerabilidade de verdade passa pelo pipeline com o selo de "já vimos esse tipo de aviso, é falso positivo".

O CodeQL 2.27.1, publicado pelo GitHub em 25 de setembro de 2026, ataca exatamente esse problema. Não é versão de manchete: não muda a linguagem de query, não reescreve o motor e não adiciona linguagem nova. É uma atualização incremental. Mas, para quem já roda code scanning no dia a dia, ela mexe nos dois pontos que definem se o time confia ou não na ferramenta: o que ela enxerga e o que ela reporta sem motivo.
 

Antes de tudo: o que é taint flow e por que um modelo novo importa

Boa parte das mudanças desta versão são "modelos de fluxo de dados". Vale entender o conceito antes de olhar a lista.

Taint flow é o rastreamento de um dado potencialmente contaminado, como uma entrada de usuário, desde a origem (source) até um ponto sensível (sink): execução de comando, query no banco, requisição de rede, escrita em disco. O CodeQL segue esse dado de chamada em chamada. O problema é que ele só sabe que uma função propaga o dado se alguém modelou essa função. Se não existe modelo, o rastreamento morre ali, sem erro e sem alerta.

O changelog usa dois tipos de modelo, e a diferença é sutil:

  • Modelos de taint flow: dizem ao motor que aquela API participa da cadeia de contaminação.
  • Flow summaries: resumem como o dado entra e sai de uma função ou tipo, sem o motor precisar analisar a implementação por dentro. Muito útil para bibliotecas externas.

Cada modelo novo é um ponto cego a menos. E é por isso que uma versão "só de modelos" pode mudar bastante o resultado do seu próximo scan.

C/C++: três APIs deixam de ser invisíveis

A mudança mais concreta para quem mantém C/C++ em produção é a cobertura de três APIs bastante usadas:

API O que é Tipo de modelo adicionado
boost::asio::ip::basic_resolver::resolve Resolução de endereços de rede no Boost.Asio Taint flow
BloombergLP::bdlbb::Blob Buffer de bytes segmentado do Bloomberg Development Environment Flow summary
google::protobuf::MessageLite API C++ do Protocol Buffers Flow summary

Na prática, se um serviço resolve endereço via Boost.Asio e repassa o resultado sem validação, essa chamada deixa de ser um buraco na análise. O mesmo vale para dados que atravessam mensagens Protobuf, algo comum em qualquer arquitetura que conversa via gRPC.

Aqui mora um efeito colateral que precisa ser comunicado ao time: modelo novo tende a gerar mais achados no primeiro scan após o upgrade, inclusive em código legado que estava lá havia anos. Não é regressão. É a ferramenta enxergando o que antes ignorava. Planeje uma rodada extra de triagem.

A nova query cpp/ambiguous-assignment-of-comparison

A versão também traz a query cpp/ambiguous-assignment-of-comparison. Ela aponta expressões que atribuem o resultado de uma comparação a uma variável e usam essa atribuição como valor de verdade. É o tipo de código que compila sem reclamar e deixa dúvida sobre a intenção de quem escreveu. Um exemplo ilustrativo:

bool encontrado;

// Atribuição ou comparação? O compilador aceita, o leitor hesita.
if (encontrado = total > 0) {
    processar();
}

// Intenção explícita: separe a atribuição do teste
encontrado = (total > 0);
if (encontrado) {
    processar();
}

É bug de code review: passa pelo olho humano justamente porque parece certo.

Kotlin 2.4.20 e o falso positivo do compilador K2

Para quem trabalha com Android ou back-end JVM em Kotlin, são duas mudanças: suporte oficial ao Kotlin 2.4.20 e uma correção na extração de argumentos no formato Foo::class.java quando o projeto usa o compilador K2.

O detalhe importa porque esse padrão aparece em todo lugar no Android, principalmente na criação de Intents explícitas:

// Intent explícita: o destino está definido pela classe
val intent = Intent(context, DetalheActivity::class.java)
val pending = PendingIntent.getActivity(
    context, 0, intent, PendingIntent.FLAG_IMMUTABLE
)

Segundo o GitHub, a correção reduz falsos positivos em queries como java/android/implicit-pendingintents. Ou seja: se o extrator não interpreta a referência de classe corretamente, uma Intent explícita pode parecer implícita, e o alerta de PendingIntent implícito dispara onde não deveria.

Se o seu time migrou para o K2 e passou a tratar esses alertas como "sempre errados", vale rodar o scan de novo com a 2.27.1. É exatamente esse cenário que a correção resolve.

Go: a cobertura acompanhando a stdlib 1.27

No Go, o trabalho é de manutenção de cobertura. Toda API nova da biblioteca padrão nasce como ponto cego até alguém modelar o fluxo. Nesta versão entraram ou foram melhorados modelos para APIs do Go 1.27:

  • bytes.CutLast e strings.CutLast;
  • database/sql.ConvertAssign e database/sql/driver.RowsColumnScanner.ScanColumn;
  • net/url.URL.Clone e net/url.Values.Clone;
  • o novo pacote encoding/json/jsontext.

O pacote strings também ganhou modelos mais amplos: Clone, Cut, CutPrefix, CutSuffix, Fields, FieldsFunc, Join, Builder, Reader e Replacer.

Parece detalhe, mas pense no caminho típico de uma entrada HTTP em Go: ela é cortada, limpa, concatenada e, no fim, vira parte de uma URL ou de uma query. Se uma dessas funções de string não está modelada, a cadeia se rompe no meio e o sink final nunca é alcançado pela análise.

// Ilustrativo: o dado do usuário atravessa funções de strings
alvo := r.URL.Query().Get("destino")
_, caminho, _ := strings.Cut(alvo, "://")
url := strings.Join([]string{"https://", caminho}, "")

// Sem modelo para Cut/Join, o rastreamento poderia parar antes daqui
resp, err := http.Get(url)

[COMPLETAR: experiência minha com Go, se houver algum caso de validação de entrada ou análise estática]

JavaScript/TypeScript: Fastify no estilo encadeado

O CodeQL agora reconhece servidores Fastify configurados por métodos encadeados, como fastify().withTypeProvider() e fastify().setValidatorCompiler(...).

const app = fastify().withTypeProvider();

// Antes, rotas registradas a partir desse encadeamento
// podiam não ser atribuídas corretamente ao servidor
app.post('/login', async (request, reply) => {
  // ...
});

A melhora na atribuição de rotas corta nos dois sentidos. Pode adicionar resultados em queries como js/missing-rate-limiting, porque rotas que passavam despercebidas agora são vistas. E pode remover falsos positivos quando plugins registrados globalmente já protegem essas rotas. Quem usa Express ou Koa não sente diferença aqui.

Rust: atenção se você mantém queries próprias

Três mudanças no Rust:

  • modelos de fluxo de dados para core::fmt::Write, melhorando a detecção de dado contaminado escrito em buffers de saída formatada;
  • correção na resolução de caminhos m::{self} quando m é um trait;
  • o extrator passou a usar o rust-analyzer 0.0.347.

A terceira é a que exige cuidado. A atualização do rust-analyzer muda a AST da biblioteca Rust com novos tipos de nó e novas APIs de acesso. Se o seu time mantém queries CodeQL customizadas para Rust, leia as notas de migração no changelog completo da 2.27.1 antes de atualizar. Query que dependia da estrutura antiga pode quebrar.

C#: uma query nova e duas sugestões que deixam de errar

A query cs/linq/missed-firstordefault identifica loops foreach que só procuram o primeiro elemento correspondente e poderiam ser escritos com FirstOrDefault:

// Antes: loop manual para achar o primeiro
Pedido? pendente = null;
foreach (var p in pedidos)
{
    if (p.Status == Status.Pendente)
    {
        pendente = p;
        break;
    }
}

// Depois: a intenção fica explícita
var pendente = pedidos.FirstOrDefault(p => p.Status == Status.Pendente);

Além disso:

  • As queries da família cs/linq/missed-* pararam de sugerir reescritas com lambda que capturam parâmetros in, out ou ref. Essas sugestões geravam código que não compilava, já que lambdas não podem capturar esses parâmetros.
  • A cs/web/missing-token-validation agora reconhece o AutoValidateAntiforgeryTokenAttribute do ASP.NET Core quando registrado como filtro MVC global via AddControllersWithViews e métodos relacionados. Menos alerta falso em ações que já estavam protegidas.

GitHub Actions: menos barulho no pinning

A query actions/unpinned-tag, que cobra que as actions usadas no workflow estejam fixadas, ficou mais precisa em dois casos:

  • não reporta mais actions fixadas por uma entrada estruturalmente válida em .github/workflows/actions.lock para o workflow em questão;
  • não reporta mais referências ao próprio repositório, como uses: $/path/to/action, que resolvem para o mesmo commit em execução e, por isso, já são fixadas por natureza.

A mudança que passa batido: NuGet privado

Tem um item no fim do changelog que não é sobre query, mas pode afetar o build do scan. Registros NuGet privados com a opção Replaces base ativada na configuração de registro privado da organização agora substituem os feeds padrão do NuGet sempre que o CodeQL baixa dependências. Isso vale mesmo quando o projeto configura explicitamente os feeds padrão.

Para quem trabalha em .NET com registro corporativo, vale conferir se essa regra de precedência não muda a resolução de algum pacote durante a análise.

Quem recebe a atualização e quando

Ambiente Como chega a 2.27.1
Code scanning no github.com Deploy automático, sem ação do time
GitHub Enterprise Server 3.24 Incluída nativamente
GHES em versões anteriores Upgrade manual do CodeQL

A última linha é a que exige atenção. Em GHES anterior à 3.24, as correções de falso positivo desta versão só chegam se alguém fizer o upgrade manual. O GitHub mantém um guia de atualização manual do CodeQL para esse cenário.

Checklist antes e depois do upgrade

  • Aumento de alertas em C/C++ logo após a atualização? Provavelmente são os novos modelos de Boost.Asio, Bloomberg BDE ou Protobuf. Faça triagem antes de concluir que é regressão.
  • Projeto Kotlin no K2 com alertas de PendingIntent ignorados? Rode o scan de novo e reavalie os que foram descartados em lote.
  • Queries customizadas para Rust? Leia as notas de migração da AST antes de atualizar.
  • API em Fastify com configuração encadeada? Espere mudanças em js/missing-rate-limiting, para mais ou para menos.
  • .NET com NuGet privado e "Replaces base" ativo? Verifique se a resolução de pacotes no scan continua como esperado.
  • GHES abaixo da 3.24? Coloque o upgrade manual do CodeQL no backlog com data, não com "quando der".

Nenhuma ferramenta de análise estática é útil se o time parou de ler os alertas. Versões como essa não ganham manchete, mas são elas que devolvem a confiança no scanner. E confiança, no fim, é o que faz alguém abrir o próximo alerta em vez de fechá-lo.

Fonte: GitHub Changelog