Check your setup
The end-to-end tests check the leak claims of the threat model in virtual machines. Your machine, decoy, backend and desktop are different, so NAILS ships three tools to check them yourself before you rely on it:
nails checkruns on the decoy before you activate. It reports readiness to activate and changes nothing.nails verifylooks for known NAILS artifacts. A clean result is evidence, not proof.nails rehearseplants a canary in a hidden session and searches the raw decoy disk for it after the session ends.
verify and rehearse also list what they could not check.
Your first session shows where check and verify fit
in a session.
nails check
Section titled “nails check”Run it on the decoy, in a shell with history off, before you activate. It runs
the same pre-flight checks as activate, changes nothing and prints what
activation would do.
sudo /mnt/data/nails checkIt reports each check, the effective configuration, the decision for each decoy
filesystem and the decoy state the hidden session would inherit. When a check
fails, the hint under it names the fix, and check exits with code 4. If the
hidden volume is not mounted, the checks that need it are skipped with that
reason instead of failing too.
- The
platformrow names the host NAILS detected. A later Debian or Ubuntu release that NAILS has not been tested on gets a warning. The row fails on a host thatactivaterefuses, such as Fedora or Arch. - The inherited decoy state lists what needs review: autostart entries and user
services that you or third-party software added, lingering, display-manager
autologin and known trace writers such as sync, backup and messaging clients.
The desktop’s and the distribution’s own components are counted, not listed,
and
nails check --jsonlists every entry. Both the desktop components and the known trace writers are matched by name only. An autologin stays listed while the decoy has it, even after you turn it off for the hidden session. In the defaultshared-homemode, a line of its own says that the hidden session starts in the decoy home.
…Pre-flight checks: [PASS] hidden-volume: Hidden volume mounted at /mnt/data [PASS] backend-entries: No fstab or crypttab entry opens or mounts the volume at /mnt/data [PASS] session-state: on the plain decoy root [PASS] systemd-version: systemd 261 supports soft-reboot [PASS] soft-reboot-units: soft-reboot.target and systemd-soft-reboot.service are installed [PASS] decoy-root: the decoy root (ext4 on /dev/vda) can be mounted again for the way back… [PASS] upper-fs-capability: Hidden root at /mnt/data can host an overlayfs upper layer [PASS] backend-detect: Hidden root backend: ext4 on LUKS mapping dm-0 on block device vdb; no backend-specific hazards detected… [PASS] sleep-policy: host will not suspend an active session (HandleLidSwitch=lock, IdleAction=ignore) [PASS] decoy-persistence: decoy keeps no durable trace of the hidden session…Inherited decoy state: [INFO] shared-home: the hidden session starts in the decoy home, so the decoy's accounts, keys, browser profiles and shell history are live in it (persona.mode = "fresh-home" starts it in an empty home) [PASS] nothing to review [INFO] 4 components of the desktop or distribution not listed (--json lists every entry)
[PASS] Ready to activate (24 passed, 0 warnings, 0 failed)Captured on 2026-10-16 in the session-readme-captures NixOS VM test, which
runs sudo /mnt/data/nails check --overlay-only and fails if check prints a
warning. --overlay-only skips the checks for a hidden NixOS build. The capture
predates the platform row. Lines shown as … are left out, and the
full capture
is in the NAILS repository. The test VM is an amnesic decoy as the
decoy requirements
describe it, with a volatile journal, no swap and systemd-coredump set to keep
no core dump on the disk (Storage=none with ProcessSizeMax=0). A closed lid
locks the screen. Its kernel command line does not set init_on_free=1, though.
The memory-wipe row, one of the lines left out here, recommends adding it, as
the decoy requirements do. Prepare the decoy shows how to
set up yours.
nails verify
Section titled “nails verify”Run it inside the hidden session. It looks for known NAILS artifacts and never claims that a system is clean. A run with no findings says “No known artifacts found” and “This is not proof of absence”, then lists the areas it did not check. A clean result is evidence against known artifacts, not proof that the decoy is untouched.
sudo /mnt/data/nails verifysudo /mnt/data/nails verify --deep--deep adds homes, shell histories, temporary and log directories, and a
search of the systemd journal for the tool name, the configuration file name,
cryptsetup and the hidden volume’s path. sudo logs every command run with it,
so its records of your own commands match too, such as the unlock, the mount and
this verify run. verify names them as sudo’s records. While the journal is in
RAM they are notes, and so is every entry of the session’s own journal inside
the session, because the way back or a power-off removes them. When the journal
keeps files on disk, every entry is a warning.
Inside the session, what belongs to the session is not reported as residue. Its
runtime files in /run, the mounted hidden volume and its active state make one
note ([INFO]). A NAILS path that the hidden layer holds, such as the link
nails init stages on NixOS, is a note too. The hidden layer hides whatever the
decoy holds beneath such a path, so check the decoy itself offline, as described
below. The header counts warnings and critical findings, not notes.
The exit code is 0 when no known artifacts were found, 10 for warnings, 11
for critical findings, 1 when the scan could not run and 3 when the
configuration could not be loaded. The
exit code table on the Commands page lists every
code.
Scan an image of the decoy
Section titled “Scan an image of the decoy”To inspect the decoy itself, mount its image or partition read-only and scan it offline, from the hidden side:
sudo /mnt/data/nails verify --offline --root /mnt/decoyEvery path is then read under --root, and the live-only checks are skipped:
running processes, the kernel mount table, open block devices and platform
package drift. Mount the decoy with mount -o ro. A decoy partition you mount
by hand in the hidden session is outside the overlay and is written directly.
List setup traces an examiner looks for
Section titled “List setup traces an examiner looks for”--examiner adds the setup traces an examiner looks for, grouped by what an
examiner would conclude from them. --disk names the raw disk or image behind
the mounted root, so it can also look for LUKS headers and random-looking space.
sudo /mnt/data/nails verify --offline --root /mnt/decoy --examiner --disk /dev/sdXIt lists LUKS headers on partitions and in the gaps between them, random-looking unpartitioned space, files that look like encrypted containers, crypttab and fstab entries, LVM metadata archives, udisks2 state, encryption tools and their access times, and recent-files or history entries that name a container. It only reports, reads the disk read-only and never changes the exit code. A LUKS header for the decoy’s own full-disk encryption is expected. Only you can tell which of the other traces have a plausible explanation. Remove each one before you rely on the setup, or be ready to explain it.
Rehearse a session
Section titled “Rehearse a session”nails rehearse checks the leak claims on your machine, with your decoy,
backend and desktop. Rehearse before you rely on NAILS.
# 1. Inside an active hidden sessionsudo /mnt/data/nails rehearse plant# 2. End the sessionsudo /mnt/data/nails deactivate# 3. On the decoy, unlock and mount the hidden volume again, thensudo /mnt/data/nails rehearse scan# 4. Remove the rehearsal when you are donesudo /mnt/data/nails rehearse resetplantputs a random token where a session most often leaks: a file named after it in the hidden root and in your home, arecently-used.xbelbookmark, a system log line, a process command line and a desktop notification. Every file write is checked first to land in the upper layer on the hidden volume, and nothing is written to the decoy. The token stays on the hidden volume and is never printed, only a six-character fingerprint.scanreads every mounted decoy block device and active swap raw and read-only, without mounting anything. It searches allocated and unallocated space for the token, in ASCII and UTF-16LE. Exit code0means it was not found,11that it was, with the device and byte offset of each hit, and9that a device could not be scanned completely.- A channel the canary could not be planted in, such as a notification with no desktop session to show it, is listed with the result as not tested.
nails rehearseon its own shows where you are and the next step.
scan refuses to run in the session the canary was planted in, which plant
records by the session’s entry time. It runs on the decoy after a plain
deactivate, after a power-off or in a later session, on every systemd version.
--allow-same-boot overrides the refusal, but a scan in the planting session
proves little, because the session’s writes may not have reached the disk yet.
To rehearse the power-off exit instead, end the session with
deactivate --poweroff and boot the decoy again before the scan.
plant refuses on a hidden root that this computer’s own storage seems to hold,
which NAILS accepts only with --allow-decoy-storage, because a rehearsal on
that storage cannot pass.
A clean scan covers only what the host can read. It cannot see SSD cells the
drive has remapped or keeps in reserve, blocks discarded with TRIM, disks that
are not mounted, the encryption header area or firmware storage. The scan prints
this list with every result. To scan a disk that is not mounted, name it with
--device, which you can repeat. The scan then reads only the devices you name,
instead of the mounted devices and active swap. To scan a disk image, use
nails rehearse scan --offline --image <file>.