Skip to main content

Vulkro vs Bearer

Close on what they find, far apart on what you read.

Bearer and Vulkro found a similar share of the same corpus, so this page is not going to pretend detection is the story. What separates them is the volume around the answer and how long you wait for it: on that run Bearer reported 72 false positives to Vulkro’s 13, and took roughly 7.3 times as long. Bearer’s own strength is somewhere else entirely, and this page says where.

  • One corpus, one machine
  • Both scan locally
  • Recall within one row of each other
  • Every figure carries its date

01 / The short answer

Which one you should pick

Read this section and stop, if you like. Everything under it is the working.

Choose Bearer if

  • The deliverable is a privacy report. Classifying which sensitive data types flow where is Bearer’s primary output, not a side channel of a security scan. If your auditor is asking which systems touch personal or health data, Bearer is deeper at that than Vulkro’s PII and PHI detectors.
  • Your code is Ruby or PHP. Bearer reads both. Vulkro parses neither: those files are counted in the inventory and skipped, so a clean Vulkro result on a Rails or Laravel service means nothing at all.
  • Your review is periodic rather than per-commit. A scan measured at 360.1s over the corpus below is comfortable on a nightly or weekly schedule. The wall clock only becomes a problem when the scan has to sit in a pull request.
  • You need a scanner with no licence to negotiate. Bearer’s CLI is source-available under the Elastic License 2.0: free for in-house use, with a restriction on offering it as a hosted service to third parties. Vulkro is licensed per seat and issued directly by our team.

Choose Vulkro if

  • The output has to be a queue somebody clears. 47 catalogued bugs against 13 false positives is a list a team reads. 43 against 72 is a list a team learns to skim, and a skimmed list is an unread list.
  • It has to run on every push. 49.2s over the same corpus, roughly 7.3x faster on the same machine, and deterministic: the same commit scanned twice returns the same findings in the same order, so a failing gate means the code moved.
  • You want one pass over everything, not one pass over code. Dependency CVEs, secrets, infrastructure configuration and built container images come out of the same scan and the same report, with CVE matching done offline against a checksummed bundle on your own disk.
  • Your audit frame is exposure rather than data classification. Broken access control, injection, SSRF, mass assignment and the rest of the OWASP API surface, ranked by what the code exposes. Vulkro emits privacy findings too, but they are one axis rather than the organising principle.
  • The subject is a Salesforce build. Apex, Lightning components, Flow and org metadata are read by a separate edition, Vulkro for Salesforce: the same review, pointed at a Salesforce org instead of a service codebase.

These two answer different questions well enough that running both is a reasonable outcome. Section 06 says how, and what the second scan costs you in time.

02 / The architectural difference

Two tools with different first questions

Both read your source on your machine and neither uploads it. The split is not privacy posture, it is what each one asks the code before it reports anything.

Bearer asks what data this code touches. It classifies sensitive data types (personal, health, payment and the rest), follows where those values travel, and ranks by the sensitivity of what is at risk. The natural deliverable is a data-protection picture of a system: which components handle what, and where it crosses a boundary.

Vulkro asks what this code exposes. Every scan extracts the route inventory and builds the call graph first, then reports the paths where an untrusted value reached something that trusted it, and the routes missing an authorization check that their siblings have. The natural deliverable is a ranked defect list with a file and a line on every row.

Both are legitimate first questions, and neither report is a superset of the other. A team that needs to answer an auditor about personal data is not served by a list of injection sinks, and a team trying to close a release gate is not served by a data inventory. The useful way to choose is to name the artifact you actually have to produce.

The one place the difference stops being philosophical is volume. A report shaped for a periodic review can afford to be generous about what it surfaces, because a human is going to sit with it. A report that blocks a merge cannot, because every false alarm is paid for by the next engineer who stops reading. That is the whole of the argument in section 03.

console - findings4 findings
SeverityFindingCWERule
CRITSQL injection in order lookupcheckout.py:214CWE-89VULK-1042
Dataflow pathVULK-1042
  1. 01checkout.py:214request handlersource

    order_id read from request.args, no type or format check

  2. 02services/orders.py:88helper

    passed through lookup_order(order_id) unchanged

  3. 03db/query_builder.py:41query builder

    concatenated into the WHERE clause with an f-string

  4. 04db/session.py:57sinksink

    cursor.execute(sql) runs the assembled statement

4 hops resolved. No sanitiser between the source and the sink.

HIGHMissing authorization on invoice downloadroutes/invoice.ts:47CWE-639VULK-2117
HIGHSSRF via user-supplied URLproxy-handler.ts:23CWE-918VULK-1180
MEDHardcoded API token committed to the repositoryconfig/stripe.js:9CWE-798VULK-3304
The Vulkro deliverable: a ranked list where every row cites a file and a line, and the open row shows the resolved path from the request to the sink. Cross-file paths like this one are Python, JavaScript, TypeScript and Go; Java stops at the first file boundary.

03 / Measured

One corpus, one machine, one scoring script

This is the only comparative number on this page. Both tools ran through the same harness and were scored by the same rule, with Vulkro at the confidence floor we recommend in CI.

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

Vulkro and Bearer scored on the same corpus: catalogued bugs found and missed, false positives, precision, recall, F1 and whole-corpus wall clock.
ToolFound (of 83)MissedFalse positivesPrecisionRecallF1Runtime
Vulkro 0.18.047 of 8336130.780.570.6649.2s
Bearer 2.0.243 of 8340720.370.520.43360.1s
Every catalogued bug cites the project’s own vulnerability documentation, an in-source vulnerability marker, or a published CVE or GHSA pinned to the scanned commit, and was confirmed by reading the sink at that commit. Bugs the scanner misses stay in the corpus as false negatives.
  • Recall is the close row

    0.57 against 0.52, a gap of 0.05. Bearer found 43 of the 83 catalogued bugs and Vulkro found 47. Read this table as a difference in noise and time, not as a difference in detection, because detection is where the two tools are nearest.

  • What a false positive means here

    A finding that fired inside a catalogued file at no catalogued line. Findings in files the corpus does not catalogue are counted separately and left out of the metrics for both tools, so neither side is penalised for reporting things the corpus never labelled.

  • What the noise costs

    72 false positives against 43 true ones means most of what landed in the scored files was not a catalogued bug. That is 5.5x the false positives Vulkro produced on the same files. Precision is the row a triage rota feels every week, which is why the argument on this page is about the queue rather than the scoreboard.

  • What the table does not measure

    Nothing here scores either tool on a language Vulkro cannot parse. Bearer reads Ruby and PHP and Vulkro reads neither, so a codebase made mostly of those is a codebase this result does not describe. It also measures nothing about privacy classification, which is the output Bearer is actually built to produce.

  • Wall clock

    360.1s against 49.2s on the same machine, roughly 7.3x. In practice that is the difference between a check that runs on every push and a check that runs overnight, and those are two different products even when the findings overlap.

Our own misses are in the same scorecard: 36 of 83 catalogued bugs were not found in this run, listed by class, and they stay in the corpus rather than being retired. Where we lose, in our own words.

04 / Where Bearer wins

The things it does better, without the hedging

Precision is our row. It is not the only row, and a page that could not name the other tool's real advantages would be an advertisement rather than a comparison.

Privacy

Sensitive data classification is its flagship, and it is better at it

Bearer’s rule set is organised around what the code touches, over a large catalogue of sensitive data types, and its data-protection reporting is built as the primary deliverable rather than as a side output of a security scan. Vulkro emits PII and PHI findings and can render a records-of-processing report, but privacy is one axis among several here and the report is not shaped around a data catalogue.

Breadth

Ruby and PHP, which Vulkro does not parse

Two large ecosystems where Vulkro loads no grammar at all. Those files are counted and skipped, and the report says so rather than reporting a clean subtree. No depth argument repairs an absent parser, and Bearer’s published language list is wider than ours.

Recall

It is not far behind on finding real bugs

Recall 0.52 against 0.57 on the run above. That is the honest shape of the result: Bearer is not missing much more than we are. What separates the two columns is what arrives attached to the findings, and how long you wait for them.

Licensing

It can be adopted without a purchase decision

The CLI is source-available under the Elastic License 2.0: free for in-house use, with a restriction on offering it as a hosted service to third parties. If your constraint is that a tool has to be in the build this quarter without a procurement cycle, that is a real advantage and Vulkro does not match it.

Influence

It changed how we rank privacy findings

Shaping the severity of a PII or PHI finding by the data type it touches, rather than by a generic score, came out of reading Bearer’s approach to the problem. Saying so is more useful to a reader than pretending we arrived at it alone.

05 / Coverage

Capability, side by side

Not a measurement. The table in section 03 is the measured part of this page; this one states what each tool is shaped to do, and marks the cells we could not check ourselves.

Capability comparison between Vulkro and Bearer, with unassessed cells marked as such.
CapabilityVulkroBearer
Languages read for code analysisPython, JavaScript, TypeScript, Go, Java. Everything else is counted and skipped.A wider published list that includes Ruby and PHP.
What the report is organised aroundExposure: routes, authorization, injection, SSRF, mass assignment, supply chain.Sensitive data: which data types the code touches, and where they flow.
Cross-file dataflowOn by default, up to four hops, for Python, JavaScript, TypeScript and Go. Java taint is same-file only.Dataflow is central to its design. We did not measure its cross-file depth, so this page does not rate it.
Route and endpoint inventoryBuilt on every scan before any rule runs, which is what gives the authorization checks something to check against.Not assessed.
Privacy and data-protection reportingPII and PHI detectors, plus records-of-processing output formats. One axis, not the organising principle.The flagship. A large sensitive-data catalogue with data-protection reports as the primary deliverable.
Dependency CVE matching in the same passYes, against a bundle on your disk. The bundle is checksummed and matching makes no network call.Not assessed. The benchmark above scored application-code findings only.
Secrets, infrastructure config and built container imagesAll three in the same scan: provider secret rules, a configuration pass over Terraform, Kubernetes, Compose and Helm, and package databases extracted from image layers.Not assessed.
Where the scan runsYour machine, at every tier. VULKRO_OFFLINE=1 enforces it at the process boundary.Its CLI runs locally too. This is a tie, and manufacturing a difference here would be dishonest.
Repeat runsDeterministic: same tree, same binary, same findings in the same order, asserted by tests in the build.Not assessed.
Machine-readable outputSARIF among 24 formats.SARIF.
Salesforce (Apex, Flow, org metadata)A separate edition, Vulkro for Salesforce, reads Apex, Lightning components, Flow and org metadata, and audits live org posture.Apex is not in its published language list.
Capability comparison, not a measurement, and no figure in it comes from the benchmark. The Vulkro column is stated from the shipped binary. The Bearer column is our reading of its published documentation; where we could not check something ourselves, the cell says it was not assessed rather than guessing, and where the two tools are equal the cell says that too.
VULKRO_SCA_REACHABLE=1 vulkro scan .offline bundle
  • 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.

5 manifest formats are parsed (npm, PyPI, Go modules, crates.io, Maven). The default published bundle currently ships npm and PyPI; the wider bundle covers the rest. Bundles are checksummed, and matching happens with no network call.

One row of the table above, in detail: dependency CVEs matched offline in the same scan as the code findings, each carrying the manifest it was resolved from. The reachability verdict shown here comes from the forward-closure gate, which is opt-in.

Read the two columns as different products rather than as a winner and a runner-up. Bearer answers a data question with more depth than we do; Vulkro answers an exposure question and brings the dependency, secret and configuration passes with it. The full language depth chart.

06 / Running both, or moving across

The cadence argument, and the diff that settles it

Both tools emit SARIF, so comparing them on your own tree is an afternoon rather than a project. There is no rule library to port in either direction.

# same tree, same commit, two reports
$ vulkro scan . --format sarif > vulkro.sarif
$ bearer scan . --output bearer.sarif --report security

# budget for the second run: it is the slow one on the corpus we measured
Run both over the same commit and diff the reports in a SARIF viewer. GitHub Code Scanning ingests either file. The interesting rows are the ones only one tool reported.

Switching costs almost nothing here, which is unusual. Neither tool asks you to author a rule library, so there is no investment stranded on either side: what you lose by leaving Bearer is the data classification, and what you lose by leaving Vulkro is the traced paths and the passes bundled with them. Both are capability losses rather than sunk-cost losses.

Which is why running both is a sensible outcome, and the cadence is what makes it workable. Put Vulkro in the pull request, where 49.2s over a whole corpus and a deterministic verdict are the properties that matter, and run Bearer on the schedule your privacy review actually operates on. Trying to fit the slower scan into every push is what makes teams turn a scanner off, and a scanner that has been turned off finds nothing.

Testing that costs nothing but the afternoon: your first CLI sign-in starts a 14-day trial of the full product, no card, and every scan in it runs on your own machine. Licences are issued per seat directly by our team after that.

See alsoVulkro vs SemgrepVulkro vs SnykVulkro vs TrivyCompare the editionsThe result and its boundary