Vulkro vs CodeQL
Two dataflow engines, two different operating models.
CodeQL compiles your code into a database and answers questions written in a query language, most often on a hosted CI runner. Vulkro is one binary that reads the tree on your disk and returns a fixed set of security verdicts with a pass or a fail. Both follow values through code. What a team actually feels is the difference in what it costs to get the first result, and where the analysis runs. No same-corpus head-to-head run exists between the two, so nothing on this page is a score.
- No head-to-head run exists
- No database build step
- No query language to learn
- Both write SARIF
01 / The short answer
Which one fits the team you have
This is what most readers came for, so it goes first. The two are not exclusive, and section 06 covers running both.
Choose CodeQL if
You want depth you can extend yourself
- Your repositories already run GitHub code scanning and the default query suites cover the languages you ship.
- You want to write your own interprocedural checks, and someone on the team will learn the query language and keep those queries alive.
- You need a language Vulkro does not read at all: C, C++, C#, Ruby, Swift or Kotlin.
- You want variant analysis: after fixing one bug, find every other place that matches its shape, across a codebase or across many repositories.
- You want to read the query that produced a finding before you trust it. The standard query packs are published openly.
Choose Vulkro if
You want a verdict with nothing to stand up first
- You want a result on a laptop or a runner with no database to build and no query to author. Install one binary, run one command.
- Your code cannot go to a hosted analysis service, or your build cannot be reproduced on a hosted runner.
- You want the same verdict twice on the same commit, so a merge gate can be left switched on instead of being disabled the first time it flakes.
- You want the security check in the pre-commit and pre-merge loop, where a scan measured in seconds is the difference between a gate people keep and a gate people route around.
- You want dependency CVEs, committed secrets, infrastructure configuration and container layers in the same pass as the code review, matched against a bundle on your own disk.
Neither column is a scoreboard. They describe different budgets: CodeQL buys depth and expressiveness with setup and expertise, Vulkro buys speed and locality by fixing the question set in advance.
02 / The architectural difference
A database you build and query, against a binary you run
One structural distinction explains most of the rest. CodeQL turns your code into an artifact and asks questions of it. Vulkro reads the tree and answers a fixed set.
CodeQL works by extraction. A pass over your project produces a relational database of the code, and analysis is then a query written in QL evaluated against that database. For interpreted languages the extractor reads source directly; for compiled languages it observes a real build, which is why a CodeQL setup normally has to be able to build the project. That design is the source of its strengths. The database is a reusable artifact, queries are code you can version and review, and a query written once can be pointed at any database.
The costs are the mirror image of the strengths. There is a build and extraction step before any result exists, a query language between a security engineer and a new check, and an environment that has to run both. Most teams meet CodeQL as GitHub code scanning, which means the analysis happens wherever CI happens rather than on the machine that holds the code.
Vulkro has no database and no query language. It parses the tree with tree-sitter grammars, builds a call graph and a route inventory, then runs a fixed detector set with taint over both. The output is a list of findings that each cite a file and a line, plus an exit code CI can act on. Nothing is compiled first, nothing is uploaded, and no server sits in the path. Cross-file taint runs in Python, JavaScript, TypeScript and Go for up to four hops; Java taint is same-file only, so a Java result set is narrower than a Python or Go one on the same codebase.
The trade is expressiveness, and it is worth stating twice. If a check is not in the detector set, Vulkro cannot be asked for it the way CodeQL can. Custom rules exist and they are YAML: a regular expression over file globs, or a single AST node match. Useful for an internal token format or a banned call, and not an interprocedural query.
Everything the scan needs stays on your machine: the code it reads, the map it builds of how your product fits together, the findings it writes, and the optional local model it can consult without leaving the machine. One line leaves.
- Stays on this machine
- source code, call graph + taint, findings, account layer, and the local model on 127.0.0.1
- One crossing
- A signed entitlement check and a usage counter, on a debounced cadence.
- Never crosses
- source code, file paths, file names, finding contents, project names, the hardware fingerprint
03 / Measured, or not measured
There is no CodeQL number on this page
The scored corpus this site publishes contains no CodeQL run, so this page publishes no comparative figure at all.
Three tools have a committed head-to-head row against the benchmark corpus. CodeQL is not one of them, and the honest consequence is that nobody here knows how the two compare on it. Every claim below is about architecture and capability, which is a different kind of statement from a score and is labelled as one.
Running it is not a matter of adding a line to the harness. Extraction for compiled languages needs each corpus project to build, and the result depends heavily on which query suite is selected. Choosing that suite ourselves would produce a figure describing our configuration rather than the tool, and a figure like that is worse than none: it looks like evidence and is not.
What is measured is published separately, with the method, the scoring rules, the false negatives and the artifact each figure was read from. Read the result and the boundary around it and the full methodology rather than taking a comparison page’s word for anything. If a defensible run against CodeQL is ever set up, the result goes here whichever way it lands.
04 / Where CodeQL wins
What CodeQL does better
Specific, and without a recovery clause. A comparison page that cannot name the other tool's strengths is an advertisement wearing a table.
- The query language
- QL is a real language with a large standard library, and it is the reason a security engineer can express a project-specific interprocedural check that no fixed detector set will ever contain. Vulkro has YAML custom rules: a regular expression over file globs, or a single AST node match in one language. That is useful for an internal token format or a banned call. It is not a query language, and nothing about how it is described changes that.
- Languages Vulkro does not read
- CodeQL covers a broader set, including C and C++, C#, Ruby, Swift and Kotlin. Vulkro parses five languages. On a C++ codebase this comparison is not close, because Vulkro reads none of it.
- Variant analysis
- Fix one bug, then hunt every other instance of its shape, including across a fleet of repositories at once. Vulkro has no equivalent: it runs a fixed detector set over the tree it is pointed at.
- Queries you can read
- The standard query packs are public, so you can open the rule that fired and see exactly what it matches. Vulkro’s detectors are closed. What this project publishes instead is the scoring method, the misses, and the evidence behind each individual finding.
- The research behind the rules
- Years of security research sit behind those packs, along with a long public record of real vulnerabilities found with them. That record is not marketing; it is checkable.
- It is already where your team looks
- If your code is on GitHub, results land in the security tab your team already reads, with no extra plumbing. Vulkro writes SARIF into that same tab, but wiring the upload is a step you take.
- Depth on a language both tools read
- No ordering is claimed here. Both follow values through code by different means, and with no shared measurement any statement about which one goes deeper on Python or Java would be invented. Section 03 explains why the measurement does not exist.
05 / Coverage
Capability against capability
No measurement appears in this table. It sets out what each tool is built to do, with the gaps on both sides left visible.
| Capability | Vulkro | CodeQL |
|---|---|---|
| Where the analysis runs | On your machine or your own runner. Source is never uploaded. | Wherever the database is built and queried. The common path is a hosted CI runner. |
| Before the first result | Install one binary and run one command. | Create a database, observing a real build for compiled languages, then run a query suite against it. |
| Writing your own check | YAML rules: a regular expression over globs, or a single AST node match. | QL, a full query language with a standard library. |
| Languages read as code | Python, JavaScript, TypeScript, Go, Java (5) | A broader set, including C and C++, C#, Ruby, Swift and Kotlin. |
| Taint across file boundaries | Python, JavaScript, TypeScript and Go, up to four hops. Java taint is same-file only. | Interprocedural dataflow is the core of the engine. |
| Endpoint inventory | Routes extracted per framework, then checked for missing authorization. | Not handed to you as an inventory. A query can be written to build one. |
| Dependency CVEs | In the same scan, matched against a checksummed bundle on your disk with no network call. | A different job. Dependency alerting on GitHub is handled by other features, not by CodeQL queries. |
| Secrets, infrastructure config, container layers | In the same pass as the code review. | Separate tooling. CodeQL analyses code. |
| Salesforce (Apex, Lightning, Flow, org metadata) | Read by Vulkro for Salesforce, which is this same review pointed at a Salesforce build. | Not a supported language. |
| Output and gating | SARIF and other machine formats, plus an exit code that is the gate. | SARIF, and code scanning alerts on GitHub. |
| Running with no network | Supported. A scan needs no network at all. | The command-line tool runs on a machine you control. The hosted code scanning path does not. |
| Language | Route mappingentry points | Taint, same filesource to sink | Taint, across filesvia call graph | Framework awarenessrouters, ORMs | Dedicated detectorslanguage rules |
|---|---|---|---|---|---|
| PythonDjango, Flask, FastAPI | Full | Full | Full | Full | Full |
| JavaScriptExpress, Koa, Next.js | Full | Full | Full | Full | Full |
| TypeScriptExpress, NestJS, Next.js | Full | Full | Full | Full | Full |
| Gonet/http, Gin, Echo, chi | Full | Full | Full | Full | Full |
| Javasame-file taint only | Full | Full | None | Full | Full |
| Apexentry points, not URL routes | Partial | Full | Partial | Full | Full |
| Terraform, Dockerfileconfiguration, not dataflow | None | None | None | Full | Full |
- Fullruns on every scan of that language
- Partiallimited to the cases named in the row
- Nonenot analysed at this depth today
Cross-file taint means a source in one file reaching a sink in another through the call graph. Java is same-file today: a tainted value that leaves the method is not followed into the callee's file, so a Java result set is narrower than a Python or Go one on the same codebase.
The matrix above describes one of the two tools only. It is included because the honest version of “we go deep” is a table with empty cells in it, and Java is the emptiest: taint does not cross a file boundary there. The full language page states every limit per language.
06 / Migration, or running both
There is no importer, and both sets can coexist
What it actually costs to add Vulkro next to CodeQL, and what it costs to replace it.
There is no CodeQL query importer in Vulkro, and promising one would be dishonest. QL expresses interprocedural analysis; a YAML rule matches a pattern. A converter would quietly drop the part of a query that made it worth writing, and hand back something that fires in the wrong places.
Running both is the sensible arrangement for a team that already has CodeQL working. They sit at different points in the loop: Vulkro on the developer machine and the pre-merge check, where a scan measured in seconds keeps a gate alive, and CodeQL on the schedule where a full database build is affordable. Both write SARIF, and GitHub code scanning accepts more than one SARIF upload for a commit when each upload carries its own category, so the two result sets sit beside each other instead of overwriting one another.
If the plan is to replace rather than to add, run them in parallel for a release cycle and diff the two sets before dropping anything. The categories to look at hardest are the ones only one tool reports: a check written in QL for your own codebase has no counterpart here, and dependency, secret and configuration findings have no counterpart there.
# no database to build, no query suite to choose $ vulkro scan . --min-confidence high SECURITY FINDINGS 1. [HIGH] SQL injection in order lookup order_id enters at the request handler and reaches cursor.execute() through two files. ↳ db/session.py:57 # the gate is the exit code, so CI parses nothing $ echo $? 1 # same commit, same findings, same order, every run $ vulkro scan . --min-confidence high --format sarif > vulkro.sarif