Signing & trust roots
Every CVE bundle, every rule pack, and every compliance framework that Vulkro consumes is signed with Ed25519 and verified against a list of trusted public keys baked into the binary at build time.
The trust list
A small list of Ed25519 verifying keys is baked into the Vulkro binary at build time. A bundle whose signature doesn't verify against any of those keys is refused. Vulkro will not fall back to "trust on first use" or "warn but allow".
Adding a runtime trust root
For organisations that mirror Vulkro and re-sign internally:
vulkro update --bundle ./internal.vkbundle --trust-key ~/.vulkro/internal.pub
--trust-key is repeatable; each path can be either 32 raw bytes or a
64-char hex string. Runtime keys are added to the baked-in list - they
don't replace it.
Key rotation
When the maintainer rotates the production signing key, the procedure is:
- Release N - generate a new key. The new release's binary trusts both the old and the new keys. Old bundles still verify; new bundles verify against the new key.
- Release N+1 - bundles are signed only with the new key.
- Release N+2 (typically several months later) - the old key is removed from the trust list. Customers running release N or earlier are still on a working binary; they just can't apply bundles signed by the new key alone.
This gives existing installs a documented upgrade window before old-key signatures stop verifying.
Where the signing key lives
The production signing key never leaves the maintainer's machine. The bundle build pipeline is:
- Maintainer's machine: an internal bundler aggregates OSV + NVD + KEV
- EPSS into a
.vkbundle.
- EPSS into a
- Maintainer's machine:
vulkro update --createsigns it with the key from$VULKRO_SIGNING_KEY. - Maintainer's machine: the signed bundle is uploaded to the Vulkro CDN and the public manifest is refreshed.
- Customers fetch the bundle from the CDN and verify against the trust list baked into their installed binary.
If the key is ever compromised the rotation procedure above is the recovery path. There is no revocation list - that's deliberately out of scope, since revocation only matters when there's a third party we can inform, and the trust list is in the binary itself.