CodeQL in GitHub Advanced Security: what it actually covers
Actualizado: 2026-05-03
CodeQL is GitHub’s semantic code analysis engine, successor to Semmle, and for three years the heart of the GitHub Advanced Security offering. With Rust support reaching preview in late 2024 and the continuous improvement of query libraries, CodeQL today covers almost every language a mid-sized company uses. The question deserving an honest answer is what it actually detects, what it doesn’t, and how to integrate it so the team takes advantage of it rather than ignoring it.
This is a balance from use across several codebases: where it works well, where repeat false positives appear, what vulnerabilities slip through, and what review habits make it useful. Read it alongside the analysis of Semgrep as a complementary SAST for a full picture of the landscape.
Key takeaways
- CodeQL treats code as queryable data: it detects real data flows, not just lexical patterns.
- Java, C#, and JavaScript are most mature; Rust still in preview with a small catalog.
- Excels at injections, XSS, unsafe deserialization, and cryptography misconfiguration.
- Does not detect business logic, race conditions, or vulnerable dependencies.
- Three decisions matter: tune the query set, integrate in PRs, and write custom queries.
How it works under the hood
CodeQL treats code as queryable data. The compiler extracts a database representing the source code: tables of functions, calls, types, control flow, and data flow. Queries written in a declarative language resembling SQL with recursive logic run over that database.
This architecture is the essential difference from classic SAST based on regex or simple AST:
- A regex grep detects “they call
evalhere.” - CodeQL detects “this
evalconsumes a value originally coming from the POST endpoint’susernameparameter, without passing through thesanitizefunction the project considers safe.”
The second detection reflects real risk, not generic potential risk. The process has two costs: database extraction (requires compiling the whole project, taking minutes to an hour on large repos) and query execution (relatively cheap once the database is built).
Languages and how mature they are
The current supported list includes:
- C, C++, C#, Go, Java, JavaScript/TypeScript, Python, Ruby, Swift, and Rust (preview).
Not all have the same maturity. Java, C#, and JavaScript are most polished, with extensive query libraries and fine-grained detection of typical vulnerabilities. Python and Go are solid. Ruby and Swift have good coverage but fewer framework-specific queries. Rust is in preview with a still-small catalog.
Detection quality depends on both the language and the framework. CodeQL catches SQL injection very well in Spring Java or Express JavaScript; it catches it worse with a custom ORM or an uncommon data-access layer, because the library doesn’t model that flow.
Languages CodeQL doesn’t cover that remain common:
- Kotlin (community alpha support exists).
- Scala, PHP, Elixir, Dart.
If your stack runs on these, CodeQL won’t be the main coverage piece and you’ll need language-specific tools to complement.
What it catches well
Categories where CodeQL excels:
- Injections (SQL, command, LDAP, NoSQL, XPath) where there’s a clear source and sink with non-convoluted flow.
- Reflected and stored XSS in web apps with recognized frameworks.
- Unsafe deserialization in Java and C#, especially with known gadget chains.
- Overflow and use-after-free in C and C++, though with higher false positive rates than in managed languages.
- Cryptography misconfiguration: weak algorithm use, hardcoded keys, unsafe random generation.
- Container and cloud patterns: secret exposure in environments, excessive permissions.
A strength that becomes apparent over time is extensibility. CodeQL lets you write your own queries in the same declarative language. If your company has its own auditLog function that should be invoked in every data-modifying endpoint, you can write a query detecting modifying endpoints without that call. This is where CodeQL differs most from tools offering only predefined rules.
What escapes it
Not everything is detectable via static analysis. What slips through most often:
- Business logic problems: IDOR, authorization breaks, threat modeling errors. These remain human work or dynamic analysis.
- Runtime-dependent vulnerabilities: real race conditions in complex concurrency, issues only emerging under load, failures triggered by specific external services.
- Dependency chains: a vulnerable library in
package.jsonis detected by Dependabot (also GHAS), not CodeQL. - Poorly modeled frameworks: if you use Next.js with app router or SvelteKit, some flows between server and client components aren’t well represented and data flow analysis interrupts.
How to integrate it so it’s useful
The easy path is enabling CodeQL with the default workflow and forgetting. The useful path is incorporating it so the development team appreciates it instead of ignoring it. Three decisions make the difference:
First, tune the query set. By default security and quality queries run. On a dirty codebase, quality queries generate so much noise they cover the security ones. The recommendation is starting only with security-extended, fixing the flow so clean alerts appear, and then adding quality as a second layer.
Second, integrate with pull request review. CodeQL can run both on pushes to main and on PRs, inline-commenting new findings introduced by a change. The developer sees the notice in the context of their change, not in a security console nobody visits.
Third, invest in custom queries for what matters in your context. Default queries cover common vulnerabilities, but internal conventions are company-specific. Spending a day each quarter writing one or two custom queries produces a battery that turns CodeQL into part of the team’s style. This pairs well with the strategy of using Semgrep for lighter patterns.
Operational costs
GitHub Advanced Security bills per active committer on private repositories. In mid-sized organizations it can accumulate quickly and is worth modeling before broad activation. For public repositories, CodeQL is free.
The less visible cost is CI minutes. On a large multi-language repository, database extraction can consume tens of minutes per run. This is managed well with:
- Extraction caches.
- Running only on certain events (not every push of every branch).
- Splitting analysis by language for parallelism.
The last cost is human: someone has to look at alerts, filter false positives, maintain custom queries, and decide when to reject a PR on security grounds. Without that role, the tool generates debt instead of value.
When it’s worth it
CodeQL inside GHAS pays off when several conditions hold: your stack is among the well supported; you have a team capable of attending generated alerts; your threat model includes statically detectable vulnerabilities as relevant risk; and you are willing to invest in custom queries so the tool adapts to your conventions, not the other way around.
If you can only afford one security tool in your pipeline and work on GitHub, CodeQL is very likely the best first investment, for its integration and coverage. If you already have a mature SAST from another vendor, the decision complicates: pilot CodeQL in parallel for a quarter and compare on the same code before deciding. Beyond the engine, what distinguishes a useful integration from a useless one is the review habit: without that habit, any SAST is just noise with a budget.