Telemetry and the install heartbeat
Vulkro scans run entirely on your machine: your code, your findings, and your scan history never leave it. The binary sends only two things on its own: a best-effort usage heartbeat and, when the machine is signed in to an account, a lease refresh. This page documents exactly what each contains and how to turn them off.
These are the only automatic outbound calls in the binary. The scanner
does not check for updates while it works. Every other call Vulkro can make
is one you start yourself: vulkro login, vulkro update, vulkro triage, vulkro probe --base-url, vulkro rules add / rules update,
--post-to, --validate-secrets, vulkro publish (see
below), an opt-in live CVE lookup
(VULKRO_CVE_LIVE=1), and the installer.
This page covers the scanners on your machine. Vulkro Cloud, the hosted service, scans your Salesforce orgs and code repositories on our infrastructure; what it reads, writes back and stores is set out on Vulkro Cloud data processing.
The heartbeat
Vulkro sends a heartbeat at most once every six hours, and at most once an
hour after a scan (debounced by a timestamp file under ~/.vulkro). It
runs on a background thread, never blocks or delays a scan, never changes
the exit code, and fails silently if the network is unavailable. It exists
so we can count active installs and retention.
What triggers it
The heartbeat is fired by the account check, so it can run on any command
that goes through that check: vulkro scan, serve, discover, prove,
mcp, inspect, report, formats, respond, lsp, cra-bundle, and
the rest of the scanning surface. It fires at most once every six hours
across all of them (at most hourly after a scan), not once per command.
The local and recovery commands skip the account check entirely and therefore never send it:
machine-id, buy, activate, license-status, login, logout,
account, usage, init, install-hook, guard, gate, intel,
bench, scan-port, slopcheck, and explain --risk-model.
So vulkro gate and vulkro guard (the hook and pre-commit path) make no
outbound request at all, whatever your environment.
The heartbeat fields
The heartbeat is content-free by design. Its core is seven usage keys:
| Field | What it is |
|---|---|
| product | Which Vulkro binary sent it. |
| install_id | A random id minted once and stored in ~/.vulkro/install_id. Anonymous; not your machine fingerprint. |
| version | The scanner version. |
| os | An OS string. |
| license_state | The licence state this installation sees, as a short code (for example trial_active, licensed, license_expired or none). |
| timestamp | When the heartbeat was sent. |
| scans_since_last_heartbeat | One aggregate integer: scans since the last heartbeat. |
Only when they apply, it also carries:
| Field | When | What it is |
|---|---|---|
| languages | After a scan | A short, comma-separated set of the lowercased language slugs the scan detected (for example go,java,javascript), deduplicated and capped. Language names only, never a file path, filename, source code, or a per-language count. |
| features | After you ran commands | The names of the Vulkro commands you ran since the last heartbeat, and of any Pro feature you were offered (for example scan,serve), deduplicated and capped. Never their arguments, paths or output. |
| editor, editor_version | When the VS Code extension or a compatible editor started the scan | The editor's name from a fixed list (for example vscode) and the extension's version. |
| device_token | While this machine is signed in | See below. |
It never sends your machine_id, any file path, any project or repository
name, or any finding body. Your scan history stays on your machine;
vulkro usage reads it locally and never triggers the
heartbeat.
When you are signed in
If you have paired this machine with an account (see
Accounts and licensing), the heartbeat
additionally carries your device token (never the machine_id) so the
server can refresh your subscription lease. When you are not signed in,
the body is the anonymous fields above and carries no device token.
The lease refresh
A signed-in machine holds a signed lease that says what it is entitled to.
To keep it current, the binary asks the account server
(app.vulkro.com/api/v1/auth/device/refresh) for a fresh lease when you
sign in, alongside each heartbeat, and when a command finds the cached
lease in its grace period or expired. That call sends only the device
token: no code, no paths, no findings, and no machine_id. The heartbeat
response can also carry a fresh lease.
A refreshed lease is verified against Vulkro's signing key and applied
silently. If the server reports the licence revoked or expired, nothing is
stored and the cached lease simply lapses at its signed expiry, after which
the scanner returns to Free and keeps scanning. vulkro logout stops the
refresh, and VULKRO_NO_HEARTBEAT=1 or VULKRO_OFFLINE=1 blocks it (the
lease then lapses at its signed expiry). An offline licence file (.lic)
never needs a refresh.
vulkro publish
vulkro publish (and vulkro-sf publish) uploads a snapshot of one
repository to an organisation server. It is the one scanner command that
sends information about your code, and it runs only when you start it:
nothing calls it for you. Run vulkro publish --terms to read the
publishing terms and vulkro publish --preview to print the exact payload
without sending anything. What a snapshot contains and how it is handled is
set out on
Organisation dashboard data processing.
Publishing does not turn on live CVE lookups. For a team that wants shared
results, Vulkro Cloud is the hosted option.
Turning it off
| Variable | Effect |
|---|---|
VULKRO_NO_HEARTBEAT=1 | Disable the heartbeat and the lease refresh (any non-empty value). vulkro login still works, but a signed-in lease is no longer renewed and lapses at its signed expiry. |
VULKRO_OFFLINE=1 | The air-gap switch. Disables the heartbeat and the lease refresh along with every other outbound network call, guaranteeing zero egress. Use an offline licence file for Pro on such a machine. |
VULKRO_HEARTBEAT_URL | Override the heartbeat endpoint (defaults to https://api.vulkro.com/v1/heartbeat). Useful for self-hosting or testing. |
The release-feed version check
Vulkro used to ask the release feed for the latest version on every
invocation and print a one-line "update available" notice at the end of
the command. That check has been removed. A plain vulkro scan makes
no release-feed request and can print no update notice.
The version check now runs in exactly one place: when you run vulkro update, which is an explicit user action. There it is
forced (it ignores the 24-hour cache) and, if a newer binary exists, it
offers to install it.
| Variable | Effect |
|---|---|
VULKRO_NO_UPDATE_CHECK=1 | Still supported, and still suppresses the version check. Because nothing else checks any more, this now only affects vulkro update; --no-version-check on that command does the same thing. |
VULKRO_OFFLINE=1 | Disables it along with every other outbound call. |
The release feed itself is unchanged and still published: install.sh
reads it to resolve which binary "latest" means. Only the binary's
automatic call to it is gone.
Related
vulkro usage- your local scan-history report (no network).- Accounts and licensing - the lease refresh.
- Offline mode - running with zero egress.
- Network reference - every endpoint Vulkro can call.
- Privacy Policy - every network call, for the product as a whole.
- Vulkro Cloud data processing - the hosted service.