Overview
How Voltro handles security — reporting a vulnerability, the supply-chain gates (dependency audit, inbound-license allowlist, SBOM), supported versions, and why self-hosting keeps your data yours.
Security is a first-class concern, not an afterthought. This page is the public summary of how we handle it; the machine-readable policy also ships as a SECURITY.md inside every @voltro/* package.
Reporting a vulnerability
Please report suspected vulnerabilities privately — never in public issues or channels.
- Email support@voltro.dev with the subject
SECURITY. - Include the affected package(s) and version(s), the impact, and a minimal reproduction if you have one.
You'll get an acknowledgement within 3 business days, an assessment once we've reproduced the issue, and a coordinated disclosure timeline agreed with you — with credit in the release notes if you'd like it. We don't run a paid bug-bounty program yet, but we genuinely value responsible disclosure.
Outbound HTTP is SSRF-guarded by default
The HttpClient your handlers yield* refuses internal targets:
- loopback, RFC-1918, CGNAT and link-local addresses — including the
169.254.169.254cloud-metadata endpoint - the hostnames
localhost,*.internal,*.local - any non-
http(s)scheme
Every redirect hop is revalidated, not just the URL you passed. A public URL
that 302s to the metadata endpoint is the actual attack; checking only the
initial target catches none of it.
This matters because a caller-supplied URL is ordinary product surface — a
scraper, a webhook-registration form, an importer, a "test this connection"
button. Those reach HttpClient with whatever the user typed.
Allowing a target on purpose
// app.config.ts
export default defineApiConfig({
http: { allowHosts: ['*.svc.cluster.local', 'billing.internal'] },
})An entry may be an exact host, a *.suffix wildcard (which does not match the
apex — one that did would silently widen your exception), or host:port when only
one port should be reachable.
There is no boolean off-switch, deliberately: "we call one internal service" and "we do not check URLs" are different postures, and a boolean cannot tell them apart six months later.
In tests, allow the stub — don't mock the guard
Use the same allowHosts to reach a local stub server (['127.0.0.1:8787']).
That keeps the test on the real guarded code path with a narrow exception. Mocking
the guard away instead means the production path is never exercised — which is
exactly how this framework's own webhook delivery once ended up behind a
NODE_ENV check.
What this does NOT cover
DNS is not resolved. A public hostname that resolves to a private address (DNS rebinding) still passes. That vector needs network-layer egress control; it is stated here rather than silently implied.
Supply-chain assurance
Every release passes automated supply-chain gates in CI before a single package is published:
- Dependency audit. The production dependency graph is audited on every build (
pnpm audit --prod); a HIGH or CRITICAL advisory fails the release. Known-but-unfixed-upstream transitives are pinned deliberately, not waved through. - Inbound-license allowlist. Every third-party runtime dependency's license is checked against an allowlist — a disallowed license fails the release. The aggregated attributions ship as
THIRD-PARTY-NOTICES.mdin each package. - SBOM. A CycloneDX Software Bill of Materials of the third-party runtime graph is generated for, and attached to, each release. If your procurement or security team needs it, request it at support@voltro.dev.
- Release integrity. Publishing is gated behind organization 2FA and a narrowly-scoped, short-lived automation token, and is all-or-nothing (two-phase) so consumers never see a half-published release.
Supported versions
Voltro is pre-1.0 and ships in lockstep — all @voltro/* packages share one version. Only the latest published release receives security fixes. Pin exact versions in production and upgrade promptly.
Your data stays yours
Voltro is self-hosted: it runs next to your database, with your connection string, your backups, and your access controls. When you self-host, the framework never proxies your data through Voltro infrastructure — there is no phone-home and no hosted control plane in the request path; the runtime is a library that lives in your own deployment.
Managed Voltro Cloud is coming as a separate, opt-in deploy target. Choosing it means running your workload on Voltro-operated infrastructure under its own data-processing terms — a deliberate choice, not the default. Self-hosting remains the default and keeps the guarantees above.