Release signing & verification
OpaqueVault binaries on releases.opaquevault.com are signed with minisign using an Ed25519 key. This page documents the trust model, the key, and the manual verification path.
Why this matters
Section titled “Why this matters”Every curl -fsSL get.opaquevault.com | sh install puts a binary on your $PATH. If an attacker can make you install a malicious binary that pretends to be ov, they own:
- Your master password (typed into a fake prompt)
- Your KEK (derived from the master password)
- Every secret in your vault
We take that seriously, so the install path has two verification steps:
- SHA-256 checksum of the tarball, validated against
ov_<version>_checksums.txtpublished in R2 alongside the binary. This step always runs. - Ed25519 signature on
ov_<version>_checksums.txtitself, validated against a public key embedded in the install script (NOT downloaded from R2). This step runs only whenminisignis on your$PATH. If it is not, the installer prints aWARNING: signature verification SKIPPEDnotice and continues with step 1 alone.
minisign is not preinstalled on macOS or on mainstream Linux distributions, so by default, most curl | sh installs get step 1 only. That matters because the two steps defend against different things:
- Step 1 (SHA-256) catches a corrupted download or a tarball tampered with in transit or at the CDN edge, because the checksums file is fetched separately from the tarball.
- Step 2 (signature) is the only step that defends against compromise of the R2 bucket itself. An attacker who controls
releases.opaquevault.comcan rewrite both the binary and the checksums file so that step 1 passes. Forging the Ed25519 signature would also require compromising the Cloudflare Worker that serves the install script — a separate trust root holding the embedded public key. Withoutminisign, this defense is not applied.
To get both steps, install minisign before running the installer:
brew install minisign # macOSsudo apt install minisign # Debian/UbuntuTo make the installer refuse to proceed unless both steps can run, set OV_REQUIRE_SIGNATURE=1 (see Forcing signature verification below). We recommend this for CI and production install paths.
When minisign is installed, both steps must pass: an invalid signature or a missing .minisig is a hard error, regardless of OV_REQUIRE_SIGNATURE.
The public key
Section titled “The public key”untrusted comment: minisign public key F89BAB08772C1C0BRWQLHCx3CKub+D3Wnc1zX/YBVr1fJD5SrK08d2xp4XoTQipbFET8V0fUAvailable at:
https://opaquevault.com/.well-known/ov-release.pub(this site)workers/get/ov-release.pubin the public repo- Embedded as
RELEASE_PUBLIC_KEYinworkers/get/worker.js
All three sources must agree. If you ever see them disagree, stop installing and report at [email protected].
Key ID: F89BAB08772C1C0B
Algorithm: Ed25519 (see “Why Ed25519, not ML-DSA?” below)
Generated: 2026-05-02
Verifying a release manually
Section titled “Verifying a release manually”Install minisign locally:
brew install minisign # macOSsudo apt install minisign # Debian/Ubuntuscoop install minisign # WindowsThen download the artifact, the checksums file, and the signature:
VERSION=v0.9.5VERSION_NO_V=${VERSION#v}
curl -fsSL -O https://opaquevault.com/.well-known/ov-release.pubcurl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_${VERSION_NO_V}_checksums.txtcurl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_${VERSION_NO_V}_checksums.txt.minisigcurl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_darwin_arm64.tar.gzVerify the signature on the checksums file:
minisign -V -p ov-release.pub -m ov_${VERSION_NO_V}_checksums.txtExpected output:
Signature and comment signature verifiedTrusted comment: ...Then verify the tarball matches the signed checksums:
shasum -a 256 -c ov_${VERSION_NO_V}_checksums.txt --ignore-missingExpected:
ov_darwin_arm64.tar.gz: OKBoth checks must pass. This manual path runs both steps — unlike the default curl | sh path, which skips the signature step when minisign is absent.
Forcing signature verification on curl | sh
Section titled “Forcing signature verification on curl | sh”By default the install script falls back to SHA-256-only verification if minisign is not installed, printing a warning so the one-liner still works for users who have not set up minisign yet. As described above, that fallback does not defend against R2 bucket compromise. For production and CI install paths, set OV_REQUIRE_SIGNATURE=1 to fail closed instead:
OV_REQUIRE_SIGNATURE=1 curl -fsSL https://get.opaquevault.com | shThis refuses to proceed if minisign is not on $PATH. Pair it with the brew install minisign / sudo apt install minisign one-liner above so the install succeeds with both steps verified.
Note the precise scope of that fallback: it applies only when the minisign binary is absent. If minisign is installed, the install always fails closed — an invalid signature and a missing signature are both hard errors, regardless of OV_REQUIRE_SIGNATURE. Every release published to R2 (v0.11.0 onward) ships a .minisig, so a signature that cannot be downloaded indicates origin tampering or a network fault, never an unsigned release. The installer does not downgrade to SHA-256-only in that case, because the checksums.txt it would fall back to is served from the same origin an attacker would already control.
Why Ed25519, not ML-DSA?
Section titled “Why Ed25519, not ML-DSA?”OpaqueVault’s transport encryption uses a hybrid post-quantum scheme (X25519 + ML-KEM-768) because of the harvest-now-decrypt-later threat: an attacker can capture today’s ciphertext, store it, and decrypt it once a cryptographically relevant quantum computer exists.
Code signing has no such exposure. A signature forged in 2032 does not retroactively compromise installs from 2026 — only contemporaneous installs can be attacked, and we will have rotated to a PQC scheme well before contemporaneous CRQC attacks are feasible. NIST’s CNSA 2.0 timeline puts signature migration in the 2033–2035 window for this reason.
The mainstream code-signing ecosystem (Sigstore, Apple notarization, package managers) is currently mid-migration to ML-DSA. Sigstore’s tracking issue (sigstore/fulcio#2191) is open as of 2026-Q2; cosign does not yet ship ML-DSA support. Shipping Ed25519 today aligns with the entire ecosystem.
We will migrate this signing key to ML-DSA (or a hybrid Ed25519 + ML-DSA scheme) when stable Sigstore tooling ships ML-DSA support. The migration is graceful: we publish a new public key, update the embedded constant in worker.js, and start signing new releases with both keys for a transition period.
Reporting issues
Section titled “Reporting issues”If you find a release where:
- The minisign signature on
checksums.txtdoes not verify against the public key on this page, OR - The public key on this page differs from
workers/get/ov-release.pubin git, OR - The public key embedded in
worker.jsdiffers from either of the above
…stop installing immediately and email [email protected] with the version number and which check failed. See /.well-known/security.txt for our full disclosure policy.