Vulkro vs Trivy
Trivy reads what you assembled. Vulkro reads what your team wrote.
Both tools run on your machine and neither uploads your source, so the offline argument that usually decides these pages is a tie here and this one will not pretend otherwise. The real split is the subject: Trivy scans the artifacts and manifests your build produced, while Vulkro follows a request value through the code your team wrote until it reaches something that trusted it. A lot of teams should be running both.
- No head-to-head score exists
- Offline posture: a tie
- Trivy is Apache 2.0
- Java taint is same-file
01 / The short answer
Which one your risk actually needs
High on the page because it is what you came for, and because for this pairing the honest answer is often not one of the two columns.
Choose Trivy if
Their ground
- Your exposure is in what you ship rather than what you wrote: base images, OS packages in a layer, Kubernetes and Terraform configuration, a cluster you inherited.
- You need dependency CVE matching across many more package ecosystems than the five manifest formats Vulkro parses.
- You want SBOM generation and SBOM scanning, plus a licence inventory, from the same binary.
- You want a tool that is Apache 2.0, costs nothing, and needs no account and no licence key to run in anger.
- You do not need a call graph. Nothing in Trivy is trying to build one, and for its job it does not need to.
Choose Vulkro if
Our ground
- The bugs that worry you are in code your team wrote: broken access control, injection, server-side request forgery, insecure direct object references, mass assignment, authentication bypass.
- You want the path printed with the finding: where the request value entered, the hops between, and the call that trusted it.
- Your services are Python, JavaScript, TypeScript, Go or Java, and you want the depth chart before you install rather than after.
- You want application findings, secrets, dependency CVEs and configuration in one report with one severity model, rather than stitched together downstream.
- You want a vendor on the hook: support, an issued licence, and someone to answer when a detector is wrong.
Run both if you can
These two are not competing for the same finding. An image with a vulnerable OS package and a handler that trusts a path parameter are different failures with different fixes, and a team with production exposure usually has both. The cost of running both is pipeline minutes and one decision about who owns the classes that overlap, which section 06 covers.
02 / The architectural difference
Facts about artifacts, or a path through your code
One tool matches things it can look up. The other builds a map of your application and walks it. Neither approach is a weaker version of the other.
Trivy answers a lookup question, and answers it well: is anything I assembled known to be vulnerable or misconfigured. An OS package in an image layer, a resolved version in a lockfile, a storage bucket left open in a Terraform resource, a credential committed by accident. Every one of those is a fact about an artifact matched against a database or a policy, which is why it is fast, why it needs no grammar for your application framework, and why it works the same on a repository nobody on your team wrote.
Vulkro answers a reachability question about code your team wrote. It parses the source, builds a call graph, maps the routes your framework registers, and follows a value from the request that carried it to the call that trusted it. That is what produces a finding no manifest could contain: this endpoint has no authorisation check, this identifier is read from the URL and used to fetch a record belonging to someone else, this parameter reaches a query string four files away. Across files it follows Python, JavaScript, TypeScript and Go for up to four hops. Java taint does not cross a file boundary at all, so a Java result set is narrower than a Python or Go one on the same codebase.
The two overlap on the perimeter, and the overlap is real rather than token: dependency CVEs, secrets, Dockerfiles and infrastructure configuration are scanned by both. On that overlap Trivy is broader, and the only thing Vulkro adds there is the reachability verdict below, which comes from the call graph it built for the application analysis anyway.
The offline posture is a tie, and it is worth saying flatly because every other comparison on this site leans on it. Trivy runs locally, uploads no source, and documents self-hosting its databases for air-gapped use. Vulkro runs locally, uploads no source, and matches against a checksummed bundle already on disk. There is one asymmetry and it runs against us: Trivy needs no account and no licence key, while Vulkro requires an account (an air-gapped machine uses a signed, machine-bound licence file, and VULKRO_OFFLINE=1 refuses every outbound call). That is a cost on our side, not a feature.
- CRITorg.apache.commons:commons-text@1.9MavenCVE-2022-42889reachable
pom.xmlStringSubstitutor.replace called from ReportController.render at src/main/java/com/acme/report/ReportController.java:88
- HIGHlodash@4.17.20npmCVE-2021-23337GHSA-35jh-r3h4-6jhmreachable
package-lock.jsontemplate() called from buildInvoice at routes/invoice.ts:47, two hops from the POST /invoices route
- MEDurllib3@1.26.4PyPICVE-2021-33503unknown
poetry.lockadvisory declares no vulnerable symbols, so no reachability claim is made and the severity is left as matched
- INFOgithub.com/gin-gonic/gin@1.7.7GoCVE-2023-29401unreachable
go.sumContext.FileAttachment is not called from the forward closure of any route, main, or plugin hookdowngraded from medium
- INFOtime@0.1.44crates.ioCVE-2020-26235unreachable
Cargo.lockpulled in transitively by chrono; no project function in the forward closure calls the affected symboldowngraded from high
Unreachable findings are downgraded, not dropped. Severity falls to Info, the row keeps its call-graph reason, and it stays in the report and in the JSON. A call site missed through dynamic dispatch shows up as down-ranked rather than as absent.
Five manifest formats are parsed (npm, PyPI, Go modules, crates.io, Maven), and the default published bundle currently covers npm and PyPI, with the wider bundle covering the rest. Trivy matches across many more ecosystems than that, so on breadth alone its dependency answer is the fuller one.
03 / Measured, or not measured
There is no head-to-head number here, in either direction
No scored run of Trivy against our corpus exists, and no scored run of Vulkro against container and infrastructure breadth exists either. Both gaps are stated, because only mentioning the first one would be a way of winning by omission.
Our benchmark harness has no Trivy arm. Even if it did, scoring Trivy on a corpus of application bugs would measure a tool on ground it never claimed: nothing in its documentation offers dataflow analysis of application source, so a low score would say more about the test than about the tool. Running the comparison the other way, over image and infrastructure coverage, is the test Trivy would be expected to win, and we have not built that harness either.
So the comparison here is capability and architecture, both checkable against published documentation. That is a weaker claim than a measurement and it is the claim we actually have.
- What we can say
- Vulkro’s own scored result on application-class bugs, published with its method: precision 0.78, recall 0.57, F1 0.66 on a corpus of real projects with independently documented bugs, at the confidence floor we recommend in CI, with 36 of the 83 catalogued bugs missed and left in the corpus. One column. A single column is a result, not a comparison.
- What we cannot say
- Anything of the form "more accurate than Trivy", and anything at all about Trivy’s precision or recall on any corpus. We have also not measured our own image or infrastructure coverage against theirs, which is why section 04 concedes that ground on documentation rather than pretending it is contested.
Artifactbench/comparison/scorecard-high.md · vulkro 0.18.0 · measured 2026-07-18 · Tier 1 corpus, min-confidence high, match window file + line plus or minus 5
The scoring rules, the corpus provenance and the list of what the scanner misses are on /proof and in the benchmark documentation.
04 / Where Trivy wins
The things it is simply better at
No qualifiers on the ends of these sentences. Trivy is excellent at what it is for, and a page that could not say so would not be worth reading on anything else.
Container images, end to end
Infrastructure as code, with a policy engine
Ecosystem breadth for dependencies
SBOM and licences
It is free and open source
It is already installed
05 / Coverage
Capability against capability, with the gaps left in
Read it as two tools with different jobs rather than as a scoreboard. Ours is empty where clusters and breadth live; theirs is empty where authored code lives.
| Capability | Vulkro | Trivy |
|---|---|---|
| Dataflow through code your team wrote | Source to sink across files: Python, JavaScript, TypeScript and Go up to four hops. Java taint is same-file only | Not attempted. No call graph is built, and the documentation does not describe taint analysis |
| Route and endpoint inventory | Built per framework before any rule runs, so an unauthenticated route is visible as a route | Not a scan target |
| Access control, object references, mass assignment, auth bypass | Dedicated detectors, ranked by the evidence behind each one | Not the product. Nothing in the documentation claims this class |
| Dependency CVE matching | Offline against a checksummed bundle on disk. Five manifest formats parsed | Offline once the database is local. Many more ecosystems than five |
| Reachability on dependency findings | From the call graph. Unreachable findings are downgraded to informational and kept, never dropped | No call-graph reachability verdict from your application code |
| Container images | OS packages extracted (apk, deb, and rpm where the system tool is available) and matched, with layer whiteouts applied | Flagship ground: wider distribution coverage, plus virtual machine images and clusters |
| Infrastructure as code and misconfiguration | Terraform, Kubernetes manifests, Compose files, Helm charts and Dockerfiles, checked for shape rather than followed for dataflow | Flagship ground: broader, and extensible with your own policies |
| Secrets | Yes, including the git history | Yes |
| Kubernetes cluster as a scan target | No. The scan reads the tree on your disk and the artifacts in it | Yes |
| SBOM and exploitability documents | CycloneDX and SPDX inventories, plus OpenVEX and CycloneDX VEX backed by reachability | SBOM generation and SBOM scanning, plus a licence scanner |
| Salesforce build review (Apex, Flow, org metadata) | A separate edition, Vulkro for Salesforce | Not a target |
| Runs with no network at all | Yes, with a signed machine-bound licence file and VULKRO_OFFLINE=1 | Yes, with the databases self-hosted or pre-fetched |
| 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.
Apex, Lightning components, Flow and org metadata are read by Vulkro for Salesforce, the same review pointed at a Salesforce build. The SBOM and exploitability documents in the table above are described in full on /sbom-and-vex.
06 / Running both
What it costs to keep the two side by side
Both emit SARIF and GitHub Code Scanning ingests either file, so the technical cost is small. The organisational cost is the part teams get wrong.
- 01
Give each class one owner
Dependency CVEs, secrets and Dockerfiles are found by both tools. Decide which report owns each class before you start, or the same package gets triaged twice and both queues get abandoned.
- 02
Gate on what you can act on today
An unfixable base-image CVE stopping every merge teaches a team to bypass the gate. Application findings with a path and a line are usually the ones a developer can close in the same pull request.
- 03
Keep the two reports separate in review
They answer different questions and they age differently: an image finding is fixed by a rebuild, an access-control finding is fixed by a change to the handler. Merging them into one number hides both.
- 04
If you must pick one, pick by exposure
A platform team shipping other people’s code should keep the artifact scanner. A product team shipping its own handlers is exposed where the artifact scanner is not looking.
# artifacts and configuration $ trivy fs --scanners vuln,misconfig,secret . --format sarif --output trivy.sarif # the application: routes, dataflow, and the dependency pass in the same run $ vulkro scan . --format sarif > vulkro.sarif # upload both to Code Scanning, and let one report own the dependency class
If you only ever want one binary in the pipeline, pick the one whose flagship ground matches the risk you are most exposed to. That is the whole decision, and it does not need a scoreboard.