StenVault
Back to blog
cvefApril 18, 2026 · 7 min read

CVEF v1.4: surviving the v1.3 downgrade attack

G
Gefson Costa
cvef

Every encrypted file format has to answer a quiet question: what stops an attacker from editing the parts that aren't secret? StenVault's file format, CVEF, learned the answer the hard way — and v1.4 is the fix.

A CVEF file is a small header, a block of JSON metadata, and the encrypted payload. The metadata declares the cryptographic suite: the algorithm, the wrapped file key, and — from v1.3 — a hybrid signature (Ed25519 + ML-DSA-65) that proves who sealed the file.

The gap: metadata nobody authenticated

Through v1.3, that JSON metadata was neither encrypted nor authenticated. The AES-256-GCM tag covered the payload, not the header around it. For most fields this fails safely — change the wrapped key and decryption simply produces garbage and aborts. One field did not fail safely: the version.

Signatures in CVEF are metadata-only — they aren't needed to decrypt the file. So an attacker with write access to a stored file could take a signed v1.3 file, strip the `signatureParams` field and change `version` from `1.3` to `1.2`. The result is a perfectly valid v1.2 file. It decrypts correctly. And it carries no signature — with no way for the recipient to know one was ever there.

This is the classic downgrade shape: don't break the crypto, just talk the reader down into a weaker mode. It's the same family as TLS signature-stripping, and it quietly undoes the non-repudiation that v1.3 signatures were meant to provide.

The fix: bind the version into the ciphertext

v1.4 closes the gap by authenticating the metadata itself. The serialized header — including the version and the signature parameters — is fed into the AEAD as Additional Authenticated Data (AAD). The GCM tag now covers both the payload and the metadata that describes it.

AES-256-GCM(
  key:        fileKey,
  iv:         iv,
  plaintext:  fileBytes,
  aad:        canonical(metadata)   ← new in v1.4
)

Flip a single byte of the header — downgrade the version, drop the signature, swap an algorithm name — and the tag no longer verifies. Decryption aborts before any plaintext is produced. The downgrade isn't detected after the fact; it is structurally impossible to pass off as valid.

It's the same defense Age (HMAC over the header), JWE (protected header as AAD) and COSE all use: binding the description of the ciphertext to the ciphertext is the only way to make tampering with it fail.

Backward compatibility, without the foot-gun

CVEF is versioned for exactly this reason. New files are written as v1.4; the reader still accepts v1.2, v1.3 and v1.4 so existing vaults keep opening. What it will not do is silently accept a v1.3 file whose signature has been peeled away — the AAD binding makes the version part of the proof, not a hint the reader has to trust.

Good cryptography is rarely about a cleverer algorithm. More often it's about leaving no unauthenticated surface for an attacker to lean on. v1.4 removes the last one CVEF had.

Want the full cryptographic detail?Read the security page

Try StenVault free

Zero-knowledge encrypted cloud storage with post-quantum protection. 5 GB free, no credit card.

No credit card · 5 GB free forever