Network egress
This page lists every outbound network call the Vulkro scanner can make. It is the page to hand your security team. The short version:
- There is no content telemetry, no analytics, and no crash reporting anywhere in the binary. Vulkro never sends your code, file paths, or findings to us. The only usage data that ever leaves the machine is the account entitlement refresh, which carries exactly six fields: product, install id, version, operating system, timestamp, and a scan counter.
- Two calls are automatic (the once-a-day update-check ping, and the once-a-day entitlement refresh while you are signed in). Every other call happens only when you run a specific command or flag.
VULKRO_OFFLINE=1disables all of them. With it set, the scanner makes zero outbound connections; pair it with an installed license file, which satisfies the account requirement without any network access.
Egress inventory
| Call | Trigger | Destination | Payload | Default | VULKRO_OFFLINE=1 |
|---|---|---|---|---|---|
| Account sign-in | vulkro login (explicit) | The Vulkro license service | Sign-in exchange that returns a signed lease; never code, paths, or findings | Off (explicit command) | Refused; use a license file instead |
| Entitlement refresh | Background, about once a day while signed in | The Vulkro license service | Six usage fields: product, install id, version, OS, timestamp, scan counter | On when signed in | Disabled; an installed license file satisfies the account requirement |
| Update-check ping | Background thread on any command | dist.vulkro.com/releases/latest.json | GET; User-Agent: vulkro/<version>; no body | On (cached 24 h) | Disabled (no request) |
| Dependency CVE lookup | vulkro scan when a parsed manifest is found | api.osv.dev/v1/querybatch | POST JSON: {name, version, ecosystem} per dependency | On (scans with deps) | Disabled |
| CVE bundle download | vulkro update (no --bundle) | dist.vulkro.com/cve/... (override: VULKRO_CDN_BASE_URL) | GET; signature + sha256 verified before apply | Off (explicit) | Refused (exit 2) |
| Installer fetch | Interactive vulkro update after you confirm | dist.vulkro.com/install.sh | GET via curl | bash | Off (TTY + consent) | The update is refused first, so this never runs |
| Secret validation | vulkro scan --validate-secrets | Stripe, GitHub, SendGrid, Slack, OpenAI APIs | GET/POST with Authorization: Bearer <the discovered secret> | Off (opt-in) | Refused (exit 2) |
| Notifications | vulkro notify / vulkro scan --post-to <...> | Your webhook (Slack/Teams/Jira) or events.pagerduty.com | POST JSON scan summary (counts, top findings) | Off (opt-in) | notify refused (exit 2); --post-to skipped with a warning |
| Rule-pack registry | vulkro rules add / rules update | dist.vulkro.com/rules/... (override: VULKRO_RULES_REGISTRY_URL) | GET; sha256 verified | Off (explicit) | Refused (exit 2) |
| Active probe | vulkro probe --base-url <URL> | The target URL you supply | Crafted attack requests (see probe) | Off (explicit) | Refused (exit 2) |
| Test webhook | "Test webhook" button in vulkro serve | Your configured webhook URL | POST a fixed test payload | Off (manual click) | Refused (error in the UI) |
Notes:
- Destinations are fixed or yours. The
dist.vulkro.comcalls and the license-service calls are the only ones that reach Vulkro infrastructure, and all of them are off by default except the update-check ping and the entitlement refresh. The probe and webhook destinations are URLs you supply. - Signed and verified. Every artifact Vulkro downloads (CVE bundle, rule
packs) is signature- and/or sha256-verified against trust roots
pinned in the binary before it is used. Mirroring via
VULKRO_CDN_BASE_URLdoes not change the trust model.
Listeners (not egress)
These accept inbound connections on loopback; they do not send data out. They
are not gated by VULKRO_OFFLINE because their purpose is to serve a local UI.
vulkro servebinds127.0.0.1:8723(the desktop console).vulkro mcp serve --port <P>binds127.0.0.1:<port>(SSE transport; the default MCP transport is stdio, no socket).vulkro lspspeaks over stdio (no socket).
Verifying zero egress
VULKRO_OFFLINE=1 is the single switch. To prove it under OS-level network
blocking:
# Linux: run in a network namespace with no interfaces.
unshare -rn /bin/bash -c 'VULKRO_OFFLINE=1 vulkro scan .'
# macOS / any platform: observe syscalls and confirm no connect() to a
# non-loopback address.
sudo dtruss -t connect -f env VULKRO_OFFLINE=1 vulkro scan . # macOS
strace -f -e trace=connect env VULKRO_OFFLINE=1 vulkro scan . # Linux
The scan should complete normally and you should see no connect() to any
non-loopback address. If you observe one, it is a bug: please report it.
The egress inventory above is also enforced in our own CI: a source-level guard
test fails the build if any new code path makes an outbound call (reqwest, raw
TCP, or raw TLS) without being covered by a VULKRO_OFFLINE gate. The inventory
cannot silently grow.
Related
- Offline mode - the command-by-command behaviour table.
- Telemetry - the six heartbeat fields in detail.
- Accounts and licensing - sign-in and the lease.
- Bundle format and Signing & trust roots.