Repository navigation
LUKS header TOCTOU between validation and luksOpen #555
Description
The disk setup logic in dstack/dstack-util/src/system_setup.rs checks whether a LUKS header exists and then separately opens the device, creating a TOCTOU window where the header state could change between the check and the open.
Root Cause
The LUKS2 disk encryption setup follows a validate-then-use pattern with a time gap between the two operations:
- The LUKS header is backed up to tmpfs
- The header is validated (checking for null cipher — CVE-2025-59054 mitigation)
cryptsetup luksOpenis called on the original device (not the validated copy)
Between steps 2 and 3, the on-disk header could be modified by a malicious host operator (who has direct access to the block device), replacing the validated header with a malicious one (e.g., null cipher).
Attack Path
- CVM starts disk encryption setup
- dstack backs up the LUKS header and validates it (no null cipher)
- Malicious host operator modifies the on-disk LUKS header between validation and
luksOpen cryptsetup luksOpenuses the modified (malicious) header- The attacker could set a null cipher, causing data to be written unencrypted despite passing validation
Impact
Potential bypass of the CVE-2025-59054 null cipher check. A sophisticated host operator with precise timing could substitute a malicious LUKS header after validation but before use. The practical exploitability depends on the timing window and the host's ability to modify the block device while the CVM is accessing it.
Suggested Fix
Use the validated header copy for luksOpen instead of the original device:
// Use --header flag to specify the validated header
cryptsetup luksOpen --header /tmp/validated-header.bin /dev/vdb encryptedOr perform validation and open atomically using the backed-up header.
Note: This issue was created automatically. The vulnerability report was generated by Claude and has not been verified by a human.
Activity
kvinwang commentedon Mar 26, 2026
Thanks for the detailed report.
We double-checked the current implementation in
dstack-util/src/system_setup.rs. The flow today is:cryptsetup luksHeaderBackupcopies the LUKS2 header into a file on a private tmpfs mount (/tmp/dstack-luks-header/luks-header).validate_luks2_headersreads and validates that tmpfs copy.cryptsetup luksOpenis invoked with--header $in_mem_hdr, so the validated header copy (not the on-disk header) is used.Because both validation and
luksOpenoperate on the same tmpfs-backed header file, there is no window where a modified on-disk header would be used after validation. In other words, the TOCTOU described in this issue does not apply to the current code.There is still a single point where we trust
cryptsetup luksHeaderBackupto faithfully copy the header into tmpfs, but that is the same trust boundary we already rely on for the rest of the LUKS workflow.Given the above, we are going to leave the current implementation as-is. If you see a different practical attack path in the existing code, we are happy to take another look.
h4x3rotab commentedon Jun 30, 2026
Maintainer triage update: this is recorded in the public security report table: https://github.com/Dstack-TEE/dstack/blob/master/docs/security/public-security-reports.md#public-reports-and-findings
Disposition: not a production vulnerability. The setup code validates and opens the same in-memory LUKS header. No code fix is planned for this report under the documented production threat model.
Closing as not planned.