Skip to main content

Offline and air-gapped

If the code cannot leave the building, neither should the scanner.

You already know the constraint, so this page is about whether this tool actually meets it. Static application security testing, dependency matching and vulnerability matching all run on the machine that holds the code. One switch hard-refuses every network call at the process boundary. Entitlement is online-first with roughly 14 days of offline grace, and a machine that will never see the network runs from an air-gap licence file we issue on request. The vulnerability archive is checksummed and can be carried in on a disk.

  • No source upload, ever
  • One switch closes the boundary
  • Air-gap licence file on request
  • Vulnerability data delivered offline

01 / What offline means here

Four claims, each one specific enough to be wrong

Every scanner in this category calls itself offline. These are the four things we mean by it, written so that a reader can catch us out if any of them is untrue.

No source upload, ever
The detection runs locally. There is no optional cloud feature that quietly sends code away for deeper analysis, and no tier that unlocks one. If there were, the rest of this page would be worthless.
One usage call, on by default, and you can read all of it
We will not write “no telemetry” here, because it would be untrue. A usage heartbeat is on by default and posts to our servers at most once a day. It carries eight fields at most: which product ran, an install id, the version, the operating system family, a timestamp, a count of how many scans ran, a device token while you are signed in, and a short list of the language names seen in the last scan. It never carries a path, a project name, a finding or a line of source. Setting VULKRO_OFFLINE or VULKRO_NO_HEARTBEAT reduces it to zero egress, and the next section prints the body field by field.
No account to scan, and Pro verified without your code
No account is needed to scan: one repository at a time, every language, every finding with its proof, for as long as you like. An account holds Pro, and the first verified device login starts a 14-day term of the full product. Entitlement is online-first: the signed lease refreshes on that same daily call and keeps working for roughly 14 days without one, and when it lapses the machine returns to Free rather than stopping. A machine that will never reach the network holds Pro through an air-gap licence file instead, bound to that machine and verified locally. That file is the escape hatch rather than the default, and we issue it on request at license@vulkro.com.
An enforceable air gap
One switch makes the process refuse every outbound call at the boundary rather than merely declining to make one. With an air-gap licence file installed, the review runs fully disconnected, and the vulnerability archive arrives by disk, internal mirror or your own feed.
trust boundaryone switch closes it

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
The usage and entitlement call: eight fields at most, at most once a day, and nothing derived from the contents of your code. Turn it off, or run from an air-gap licence file, and this line does not exist at all.
Never crosses
source code, file paths, file names, finding contents, project names, the hardware fingerprint
Everything the review needs stays on the machine that holds the code. One line leaves, it carries the usage and entitlement call, and one switch removes even that.

The vulnerability archive is distributed with a checksum and verified against it when it lands. That is a check on integrity in transit, and it is deliberately not described as a signature check, because those are different guarantees and only one of them is on offer. How the archive is built, how often it is refreshed and how to move it into a network with no route out are in the offline vulnerability matching guide, and the outbound inventory is itemised in the network reference.

02 / The one crossing

If one line leaves, you should be able to read it

A privacy claim that cannot be checked is a policy. This call is on by default. Here is the entire body of it, field by field, with what each field carries.

The eight fields are: the product that ran, an install id, the version, the operating system family, a timestamp, a count of scans since the last call, a device token while you are signed in, and a short sorted list of the language names seen in the last scan. Six of those are present on an anonymous run. The install id is minted at install and is not a hardware fingerprint, so it cannot be correlated with a machine you own elsewhere. The scan counter is how a per-seat licence is enforced without anybody looking at what was scanned. The language list is capped in length and is never a path or a filename.

What is not in the body: no source, no file paths, no file names, no project names, no findings, no repository or branch, and no hardware fingerprint. There is no field one of those could travel in.

Setting VULKRO_OFFLINE or VULKRO_NO_HEARTBEAT reduces this to zero egress. VULKRO_OFFLINE goes further and makes the process refuse every outbound call rather than skipping this one. On a machine running from an air-gap licence file there is no cadence, no call and no body at all, because the entitlement was verified locally from the file.

Entitlement check to Vulkroat most once a day
Field and example valueWhat it carries
"product": "vulkro",which binary made the call
"install_id": "3f9c1a7e-5b40-4c8d-9a21-7ce4d0b28f16",a random id minted at install, not a hardware fingerprint
"version": "0.21.0",the build that is running
"os": "macos",operating system family, not a machine name
"scans_since_last_heartbeat": 4,how many scans ran since the last call
"timestamp": "2026-08-15T09:41:02Z"when the call was made
The usage and entitlement call body on an anonymous run. Six fields, each one glossed, and the list of what never appears in it underneath. Signed in, the body adds a device token and a language list, for eight.

03 / The position

Paid, supported, and still runs on your machine

Plot this category on two axes, whether it runs where your code already is and whether anyone is accountable for it, and one of the four cells is nearly empty.

The shape of the category: where the free offline tools sit, where the paid cloud products sit, and the cell in between.
Who is behind itRuns on your machine, one binaryRuns in somebody else’s cloud
Free, community supportedSeveral genuinely good command-line scanners live here. You get the tool, a forum, and whatever accuracy claim the project makes about itself.The free tiers of the hosted platforms, which is the same trade as the paid cell to the right with a lower ceiling.
Paid, with a vendor accountableVulkro. A supported product that runs entirely on your machine as one binary, with a published measurement method behind the accuracy claim.Almost everything else that a company pays for in this category. You connect a repository, code or snippets leave the building, and telemetry comes with it.
No vendor is named here on purpose. The quadrant describes the shape of the category. The measured figures and the method behind them are published in the benchmark documentation.

The free offline tools are real and some of them are good. The trade is that you get community support and an accuracy claim the project makes about itself. The paid products are almost all hosted, which means connecting a repository and accepting that code, or fragments of it, leaves the building. If your constraint is that it must not, then the paid cloud column is not a decision you get to make.

What the middle cell is supposed to give you is both: somebody accountable for the product, and a scan that never leaves the machine. That is the position this product occupies, and the only way to make it credible is to publish how the accuracy is measured rather than asking you to take the architecture as evidence of quality.

04 / One binary

The surface that usually takes three or four tools

A disconnected environment is the worst place to be running four separate tools, each with its own update path and its own data feed.

Values are followed across file boundaries in Python, JavaScript, TypeScript and Go. In Java the trace stops at the first file boundary, so a Java result on the same codebase is narrower than a Python or Go one. C, C++ and PHP are read one function at a time. Those, plus Salesforce Apex in the Salesforce build, are the whole list: there is no Ruby, C# or Kotlin parser. The per-language depth is set out on what the scanner covers and in the supported detection reference, because a language you rely on being absent is something you should learn here rather than after installing.

05 / Measured, not asserted

Offline is the architecture. This is the accuracy

The result below comes from a test built out of real applications with real, publicly documented vulnerabilities in them, at the strict setting we recommend for a gate.

Measured againstvulkro 0.25.3, measured 2026-09-08

Real vulnerabilities found and missed, and false alarms raised, on a test built from real applications.
What was measuredResult
Real vulnerabilities found33 of 83
Real vulnerabilities missed50
False alarms raised20
Every vulnerability in this test is a real, publicly documented bug in a real application, confirmed by reading the code at that exact version. The ones Vulkro cannot find stay in the test rather than being removed.

The detection engine is closed, and that is the licensed product. What is published instead is the thing that decides whether the claim is worth anything: the way accuracy is measured, the provenance of every vulnerability in the test, and the ones the review fails to find. You can check the catch rate and the false-alarm rate without anybody handing over the rule engine, which is the honest version of this trade rather than an invitation to read the source.

Note what the middle row costs us to publish. A vulnerability the review cannot find stays in the test rather than being removed from it, so every figure above is lower than it would be if we curated the test to flatter the result.

06 / Honest scope

What running offline does not buy you

Offline solves exactly one problem, and it is worth being precise about which one.

Offline is an architecture, not an accuracy claim
Running on your machine says nothing about how much the review finds. That is a separate argument, made with a measurement, and it is made further up this page rather than implied by the word offline.
Nothing is executed or probed
This is a read of your code and your configuration. It does not attack a running system, and it is not a substitute for someone paid to try.
Coverage is uneven by language, and published as such
Code analysis covers Python, JavaScript, TypeScript, Go and Java with cross-file data flow (Java stops at the first file boundary), plus C, C++ and PHP read one function at a time, plus Salesforce Apex in the Salesforce build. There is no Ruby, no C# and no Kotlin parser, so a project in any of those gets dependency matching from its manifest and nothing else. That list is written here rather than left to be discovered after installing.
The data is as current as your last delivery
A disconnected machine cannot refresh anything on its own. The vulnerability archive is as current as the copy somebody carried in, which is a property of the constraint rather than a shortcoming of the tool.

5 manifest and lockfile formats are read (npm, PyPI, Go modules, crates.io, Maven), but the published archive does not currently carry all 5: the default one ships npm and Python packages, and the wider archive adds Go modules, crates.io and Maven. The archive is distributed with a checksum and verified against it on arrival, which is an integrity check and not a signature check. On a disconnected machine, confirm which ecosystems the copy you carried in actually covers before reading an empty result as a clean one.

Everything here runs on the same engine

Vulkro reviews your codebase and Vulkro for Salesforce reviews your Salesforce build. Vulkro Red is the other half of the team: it takes what the review found and works out what an attacker would actually do with it.

The reviewVulkro

Reviews your code

Goes through every line of your codebase before a release, the way a senior engineer would if they had the time, and tells you what a customer could exploit.

You get: what to fix, and a pass or fail on the releaseWhat it checks
 Vulkro for Salesforce

Reviews your Salesforce build

The same review for the part of your business that runs on Salesforce, including the settings in the org itself, and what the AppExchange security review will ask you for.

You get: a straight answer on whether you are ready to submitVulkro for Salesforce
The red teamVulkro RedComing soon

Attacks what they found

Takes the review and works out what an attacker would actually do with it: which small problems chain together into a real break-in, and which ones are noise.

You get: the attack, step by step, before someone else runs itHow it works

One engine behind all three, so the red team works from what the review already foundIt all runs on your machine. Your code never leaves it.