Skip to content

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.

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:

  1. SHA-256 checksum of the tarball, validated against ov_<version>_checksums.txt published in R2 alongside the binary. This step always runs.
  2. Ed25519 signature on ov_<version>_checksums.txt itself, validated against a public key embedded in the install script (NOT downloaded from R2). This step runs only when minisign is on your $PATH. If it is not, the installer prints a WARNING: signature verification SKIPPED notice 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.com can 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. Without minisign, this defense is not applied.

To get both steps, install minisign before running the installer:

Terminal window
brew install minisign # macOS
sudo apt install minisign # Debian/Ubuntu

To 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.

untrusted comment: minisign public key F89BAB08772C1C0B
RWQLHCx3CKub+D3Wnc1zX/YBVr1fJD5SrK08d2xp4XoTQipbFET8V0fU

Available at:

  • https://opaquevault.com/.well-known/ov-release.pub (this site)
  • workers/get/ov-release.pub in the public repo
  • Embedded as RELEASE_PUBLIC_KEY in workers/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

Install minisign locally:

Terminal window
brew install minisign # macOS
sudo apt install minisign # Debian/Ubuntu
scoop install minisign # Windows

Then download the artifact, the checksums file, and the signature:

Terminal window
VERSION=v0.9.5
VERSION_NO_V=${VERSION#v}
curl -fsSL -O https://opaquevault.com/.well-known/ov-release.pub
curl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_${VERSION_NO_V}_checksums.txt
curl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_${VERSION_NO_V}_checksums.txt.minisig
curl -fsSL -O https://releases.opaquevault.com/${VERSION}/ov_darwin_arm64.tar.gz

Verify the signature on the checksums file:

Terminal window
minisign -V -p ov-release.pub -m ov_${VERSION_NO_V}_checksums.txt

Expected output:

Signature and comment signature verified
Trusted comment: ...

Then verify the tarball matches the signed checksums:

Terminal window
shasum -a 256 -c ov_${VERSION_NO_V}_checksums.txt --ignore-missing

Expected:

ov_darwin_arm64.tar.gz: OK

Both 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:

Terminal window
OV_REQUIRE_SIGNATURE=1 curl -fsSL https://get.opaquevault.com | sh

This 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.

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.

If you find a release where:

  • The minisign signature on checksums.txt does not verify against the public key on this page, OR
  • The public key on this page differs from workers/get/ov-release.pub in git, OR
  • The public key embedded in worker.js differs 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.