Vulnerabilities in LUKS2 disk encryption for confidential VMs
Trail of Bits is disclosing vulnerabilities in eight different confidential computing systems that use Linux Unified Key Setup version 2 (LUKS2) for disk encryption. Using these vulnerabilities, a malicious actor with access to storage disks can extract all confidential data stored on that disk and can modify the contents of the disk arbitrarily. The vulnerabilities are caused by malleable metadata headers that allow an attacker to trick a trusted execution environment guest into encrypting secret data with a null cipher. The following CVEs are associated with this disclosure:
This is a coordinated disclosure; we have notified the following projects, which remediated the issues prior to our publication.
- Oasis Protocol:
oasis-sdk(v0.7.2) - Phala Network:
dstack(v0.5.4) - Flashbots TDX:
tdx-init(v0.2.0) - Secret Network:
secret-vm-ops - Fortanix Salmiac:
salmiac - Edgeless Constellation:
constellation(v2.24.0) - Edgeless Contrast:
contrast(v1.12.1, v1.13.0) - Cosmian VM:
cosmian-vm
We notified the maintainers of cryptsetup, resulting in a partial mitigation introduced in cryptsetup v2.8.1.
We also notified the Confidential Containers project, who indicated that the relevant code, part of the guest-components repository, is not currently used in production.
Users of these confidential computing frameworks should update to the latest version. Consumers of remote attestation reports should disallow pre-patch versions in attestation reports.
Exploitation of this issue requires write access to encrypted disks. We do not have any indication that this issue has been exploited in the wild.
These systems all use trusted execution environments such as AMD SEV-SNP and Intel TDX to protect a confidential Linux VM from a potentially malicious host. Each relies on LUKS2 to protect disk volumes used to hold the VM’s persistent state. LUKS2 is a disk encryption format originally designed for at-rest encryption of PC and server hard disks. We found that LUKS is not always secure in settings where the disk is subject to modifications by an attacker.
Confidential VMs
The affected systems are Linux-based confidential virtual machines (CVMs). These are not interactive Linux boxes with user logins; they are specialized automated systems designed to handle secrets while running in an untrusted environment. Typical use cases are private AI inference, private blockchains, or multi-party data collaboration. Such a system should satisfy the following requirements:
- Confidentiality: The host OS should not be able to read memory or data inside the CVM.
- Integrity: The host OS should not be able to interfere with the logical operation of the CVM.
- Authenticity: A remote party should be able to verify that they are interacting with a genuine CVM running the expected program.
Remote users verify the authenticity of a CVM via a remote attestation process, in which the secure hardware generates a “quote” signed by a secret key provisioned by the hardware manufacturer. This quote contains measurements of the CVM configuration and code. If an attacker with access to the host machine can read secret data from the CVM or tamper with the code it runs, the security guarantees of the system are broken.
The confidential computing setting turns typical trust assumptions on their heads. Decades of work has gone into protecting host boxes from malicious VMs, but very few Linux utilities are designed to protect a VM from a malicious host. The issue described in this post is just one trap in a broader minefield of unsafe patterns that CVM-based systems must navigate. If your team is building a confidential computing solution and is concerned about unknown footguns, we are happy to offer a free office hours call with one of our engineers.
The LUKS2 on-disk format
A disk using the LUKS2 encryption format starts with a header, followed by the actual encrypted data. The header contains two identical copies of binary and JSON-formatted metadata sections, followed by some number of keyslots.
Each keyslot contains a copy of the volume key, encrypted with a single user password or token. The JSON metadata section defines which keyslots are enabled, what cipher is used to unlock each keyslot, and what cipher is used for the encrypted data segments.
Here is a typical JSON metadata object for a disk with a single keyslot. The keyslot uses Argon2id and AES-XTS to encrypt the volume key under a user password. The segment object defines the cipher used to encrypt the data volume. The digest object stores a hash of the volume key, which cryptsetup uses to check whether the correct passphrase was provided.

LUKS, ma—No keys
By default, LUKS2 uses AES-XTS encryption, a standard mode for size-preserving encryption. What other modes might be supported? As of cryptsetup version 2.8.0, the following header would be accepted.
The cipher_null-ecb algorithm does nothing. It ignores its key and returns data unchanged. In particular, it simply ignores its key and acts as the identity function on the data. Any attacker can change the cipher, fiddle with some digests, and hand the resulting disk to an unsuspecting CVM; the CVM will then use the disk as if it were securely encrypted, reading configuration data from and writing secrets to the completely unencrypted volume.
When a null cipher is used to encrypt a keyslot, that keyslot can be successfully opened with any passphrase. In this case, the attacker does not need any information about the CVM’s encryption keys to produce a malicious disk.
We disclosed this issue to the cryptsetup maintainers, who warned that LUKS is not intended to provide integrity in this setting and asserted that the presence of null ciphers is important for backward compatibility. In cryptsetup 2.8.1 and higher, null ciphers are now rejected as keyslot ciphers when used with a nonempty password.
Null ciphers remain in cryptsetup 2.8.1 as a valid option for volume keys. In order to exploit this weakness, an attacker simply needs to observe the header from some encrypted disk formatted using the target CVM’s passphrase. When the volume encryption is set to cipher_null-ecb and the keyslot cipher is left untouched, a CVM will be able to unlock the keyslot using its passphrase and start using the unencrypted volume without error.
Validating LUKS metadata
For any confidential computing application, it is imperative to fully validate the LUKS header before use. Luckily, cryptsetup provides a detached-header mode, which allows the disk header to be read from a tmpfs file rather than the untrusted disk, as in this example:
cryptsetup open --header /tmp/luks_header /dev/vdbUse of detached-header mode is critical in all remediation options, in order to prevent time-of-check to time-of-use attacks.
Beyond the issue with null ciphers, LUKS metadata processing is a complex and potentially dangerous process. For example, CVE-2021-4122 used a similar issue to silently decrypt the whole disk as part of an automatic recovery process.
There are three potential ways to validate the header, once it resides in protected memory.
- Use a MAC to ensure that the header has not been modified after initial creation.
- Validate the header parameters to ensure only secure values are used.
- Include the header as a measurement in TPM or remote KMS attestations.
We recommend the first option where possible; by computing a MAC over the full header, applications can be sure that the header is entirely unmodified by malicious actors. See Flashbots’ implementation of this fix in tdx-init as an example of the technique.
If backward compatibility is required, applications may parse the JSON metadata section and validate all relevant fields, as in this example:
#!/bin/bash
set -e
# Store header in confidential RAM fs
cryptsetup luksHeaderBackup --header-backup-file /tmp/luks_header $BLOCK_DEVICE;
# Dump JSON metadata header to a file
cryptsetup luksDump --type luks2 --dump-json-metadata /tmp/luks_header > header.json
# Validate the header
python validate.py header.json
# Open the cryptfs using key.txt
cryptsetup open --type luks2 --header /tmp/luks_header $BLOCK_DEVICE --key-file=key.txtHere is an example validation script:
from json import load
import sys
with open(sys.argv[1], "r") as f:
header = load(f)
if len(header["keyslots"]) != 1:
raise ValueError("Expected 1 keyslot")
if header["keyslots"]["0"]["type"] != "luks2":
raise ValueError("Expected luks2 keyslot")
if header["keyslots"]["0"]["area"]["encryption"] != "aes-xts-plain64":
raise ValueError("Expected aes-xts-plain64 encryption")
if header["keyslots"]["0"]["kdf"]["type"] != "argon2id":
raise ValueError("Expected argon2id kdf")
if len(header["tokens"]) != 0:
raise ValueError("Expected 0 tokens")
if len(header["segments"]) != 1:
raise ValueError("Expected 1 segment")
if header["segments"]["0"]["type"] != "crypt":
raise ValueError("Expected crypt segment")
if header["segments"]["0"]["encryption"] != "aes-xts-plain64":
raise ValueError("Expected aes-xts-plain64 encryption")
if "flags" in header["segments"]["0"] and header["segments"]["0"]["flags"]:
raise ValueError("Segment contains unexpected flags")Finally, one may measure the header data, with any random salts and digests removed, into the attestation state. This measurement is incorporated into any TPM sealing PCRs or attestations sent to a KMS. In this model, LUKS header configuration becomes part of the CVM identity and allows remote verifiers to set arbitrary policies with respect to what configurations are allowed to receive decryption keys.
Coordinated disclosure
Disclosures were sent according to the following timeline:
- Oct 8, 2025: Discovered an instance of this pattern during a security review
- Oct 12, 2025: Disclosed to Cosmian VM
- Oct 14, 2025: Disclosed to Flashbots
- Oct 15, 2025: Disclosed to upstream
cryptsetup(#954) - Oct 15, 2025: Disclosed to Oasis Protocol via Immunefi
- Oct 18, 2025: Disclosed to Edgeless, Dstack, Confidential Containers, Fortanix, and Secret Network
- Oct 19, 2025: Partial patch disabling
cipher_nullin keyslots released incryptsetup2.8.1
As of October 30, 2025, we are aware of the following patches in response to these disclosures:
- Flashbots
tdx-initwas patched using MAC-based verification. - Edgeless Constellation was patched using header JSON validation.
- Oasis ROFL was patched using header JSON validation.
- Dstack was patched using header JSON validation.
- Fortanix Salmiac was patched using MAC-based verification.
- Cosmian VM was patched using header JSON validation.
- Secret Network was patched using header JSON validation.
The Confidential Containers team noted that the persistent storage feature is still in development and the feedback will be incorporated as the implementation matures.
We would like to thank Oasis Network for awarding a bug bounty for this disclosure via Immunefi. Thank you to Applied Blockchain, Flashbots, Edgeless Systems, Dstack, Fortanix, Confidential Containers, Cosmian, and Secret Network for coordinating with us on this disclosure.
