All news

NAILS v0.3.0-rc.3: one design for NixOS, Debian and Ubuntu

release

NAILS v0.3.0-rc.3 was published on October 20, 2026. It is a release candidate of NAILS 0.3 and the first 0.3 build on GitHub Releases. NAILS 0.3 replaces the per-directory overlays of earlier releases with one overlay over the whole decoy root, entered and left with a soft-reboot. Debian 13, Ubuntu 24.04 and Ubuntu 26.04 join NixOS as decoys.

Older posts and articles about NAILS describe 0.1 or 0.2. Those releases ran on NixOS only, overlaid directories such as /etc, /home and /var of the running decoy, and read a YAML configuration. NAILS 0.3 works differently, and a setup made for 0.2 must be converted before you run 0.3. The sections below cover what changed.

NAILS is alpha software. Interfaces and operator workflows can still change between alpha releases. Use it only after testing your exact hardware, storage backend, activation path and recovery procedure.

What a release candidate is

The release process defines it: “X.Y.Z is a stable release and X.Y.Z-rc.N a release candidate, published as a prerelease.” Once published, a release, its files and its tag never change. A problem found in a release candidate is fixed in a new -rc.N, or in the next patch version.

0.3.0-rc.1 and 0.3.0-rc.2 were tagged but never published. The release run of rc.1 stopped at the SBOM attestation. The GitHub releases feed also lists tags that never got a release, because it shows a version as soon as its tag is pushed. A version is out once GitHub Releases lists it with its files.

The latest stable release is still v0.2.0, the earlier design for NixOS only. The docs on this site do not apply to it.

One overlay over the whole root

Earlier releases overlaid the running decoy directory by directory. The decoy kept running across activation, so every process that existed before had to be found and restarted or killed. A writer the scan missed, such as a service in its own mount namespace or a periodic writer that held no file open during the scan, went on writing to the decoy, and nothing reported it.

In 0.3, nails activate builds one OverlayFS overlay over the whole decoy root at /run/nextroot, with the decoy root as its read-only lower layer and its upper layer on your hidden volume. It then enters the overlay with systemctl soft-reboot: systemd stops every decoy program, switches root into the overlay and starts a fresh userspace there. Every process of the hidden session starts inside the overlay, so there is nothing to find, restart or kill, and what the session writes through the decoy’s mounted filesystems lands in the upper layer. The few writes that go around the mount layer, such as EFI variables or a disk the session mounts itself, are listed as residual channels in the threat model.

nails deactivate soft-reboots back into the plain decoy and closes the hidden volume on the way. nails emergency does the same at once, or powers the machine off. Nothing that starts the hidden session is installed on the decoy: no boot entry, initrd change, unit or binary. The nails binary stays on the hidden volume, and you run it by its full path.

The design has costs. Both transitions log you out, because the desktop itself runs inside the overlay. Kernel and service-manager state is not reset. The boot ID, the uptime, the kernel ring buffer, the soft-reboot counter of systemd 256 and newer, and the network state the hidden session set up carry over until the machine powers off. The decoy’s NetworkManager also records a link it adopts on the decoy disk as soon as the decoy starts. Take down the connections you brought up and delete the links you created before you deactivate, or end with nails deactivate --poweroff. A soft-reboot keeps RAM too, so power off after a session when that matters.

The decoy needs systemd 254 or newer. How it works walks through the session, and the architecture overview explains why it takes the whole root.

What NAILS does and does not do

As before, NAILS encrypts nothing itself. The hidden volume, and its deniability, come from the storage backend you choose, for example a VeraCrypt hidden volume. NAILS adds nothing to the backend’s claim. What it does is narrow what an offline examination of the decoy can find. It is built for one adversary: someone who gets offline access to the disks after the fact and may make you unlock the decoy once.

0.3 adds tools to check your own setup. nails check reports whether the machine is ready to activate and changes nothing. nails rehearse plants a random canary in a hidden session, then searches the raw decoy disk for it. nails verify can now also scan an image of the decoy offline for known artifacts. A clean nails verify is evidence, not proof. Check your setup shows how to use these tools.

NAILS does not protect against anyone with access to the running machine, against memory forensics or cold-boot attacks, against network and remote records, or against compelled disclosure of the hidden volume. The threat model sets out the adversary, the assumptions, the residual channels and the other limits.

Debian and Ubuntu decoys

On NixOS, a declarative hidden configuration is built and entered in the same step. Debian 13, Ubuntu 24.04 and Ubuntu 26.04 run the same session, with whatever the hidden /etc holds. A later Debian or Ubuntu release, such as Ubuntu 26.10, still runs, but init, check and activate warn that NAILS has not been tested on it. nails check names the detected host in its platform row. Derivatives whose ID_LIKE names debian or ubuntu are accepted provisionally.

Debian 12 and Ubuntu 22.04 are refused, because their systemd is too old for a soft-reboot. Fedora and Arch are refused too. Support for them is planned, as the roadmap says. Automated tests run the session in NixOS, Debian 13 and Ubuntu 24.04 virtual machines. Requirements lists the supported platforms and the refused setups.

A known issue on Ubuntu 26.04

On Ubuntu 26.04, chrony (time sync) and CUPS (printing) fail after the switch into the hidden session. AppArmor blocks their messages to systemd and to the journal, whose sockets were set up before the switch. Other services that AppArmor confines may fail the same way. In the hidden session the clock is not synchronized and printing times out. After the way back, the decoy lists chrony as failed until its next full reboot, which hints that a soft-reboot happened. Reboot fully after a session to clear it. The fault lies outside NAILS: a plain systemctl soft-reboot into another root, without NAILS, breaks chrony the same way.

Upgrading from 0.2

0.3 breaks compatibility with the state, configuration and command line of 0.2, and there are no compatibility shims. Upgrade only while NAILS is inactive: end a 0.2 session with its own nails deactivate, or reboot, before you replace the binary.

The configuration moves from config/nails.yaml to a strict config/nails.toml next to the binary. 0.3 never reads the YAML file and does not warn about it, so an unconverted setup runs with the defaults. Convert each key by hand. nails init writes a documented template, and nails config show --example prints every key.

The other changes, in short:

  • The hidden volume must be storage of its own. NAILS refuses a folder, a subvolume or bind mount of a filesystem the decoy uses, a volume in the decoy’s volume group, an image file on a decoy filesystem, and overlay, FUSE, network and ZFS filesystems.
  • The decoy root must be on a block device, with ext4, xfs, btrfs or f2fs. An overlay root, a ZFS root and a tmpfs root, such as nixos-impermanence on /, are refused. A /var or /home on its own tmpfs, wiped at boot, is fine.
  • A new layout. The hidden root’s layers live under <hidden-root>/root/, and the uppers of the 0.2 overlays are not read. Move what you need into a hidden session, then delete them.
  • NixOS flake decoys. A decoy whose /etc/nixos is a flake needs a self-contained hidden flake.
  • Commands and scripts. activate and deactivate now ask for confirmation, so scripts, keybindings and units that run them need -y. Several flags were renamed or removed, and the exit codes, the JSON output and the state file changed. Delete a state.json that 0.2 wrote, from a clean inactive system.

The upgrade notes in the changelog cover each of these in full, and the changelog’s Removed section lists every dropped key, flag and command. Upgrading from 0.2 in the install guide sums them up.

Verifying a release without a GitHub account

This is the first release with Sigstore bundles. It carries its three attestations as provenance.sigstore.json, sbom.sigstore.json and vex.sigstore.json. You check them against the downloaded files with cosign 3.1.3 or later, or 2.6.5 or later on the older 2.x line. The check asks GitHub for nothing, so you need no GitHub account. By default cosign fetches Sigstore’s public keys when it runs. On a computer without a network connection, you give it the keys as a file instead. The release workflow runs the same check before it drafts a release. A release run now boots every NixOS VM test on the tagged commit, apart from the informational performance tests.

Never download or verify NAILS on the decoy. A copy of nails on the decoy disk, even a deleted one, can be recovered and identifies the tool. For a first installation, use a live environment that keeps nothing, or another machine. First install from Tails walks through it with Tails. For an update, download from inside a hidden session. The download page has the files and the commands.

Security fixes in rc.3

Besides the Sigstore bundles, the security section of the rc.3 notes lists two fixes.

  • Login and boot records. The way back no longer leaves a login or boot record on the decoy that an ordinary power cycle never writes. On Debian with wtmpdb, the boot row was named soft-reboot. On systemd 255 and earlier, as on Ubuntu 24.04, the classic wtmp boot record carried the decoy’s first boot time. Now the decoy’s login and boot records read as one clean power cycle. A weaker tell remains, which a later release will address: the process numbers of the getty and login records written after the way back continue from the decoy’s boot.
  • Decoy swap and mounts. Some /etc/fstab entries name a device by a tag whose value holds a character that udev encodes, such as a space, or is in single quotes. Others use a path with a . component, such as /mnt/./backup. For such an entry, NAILS masked a unit name that systemd never generates and left the real unit free, so the hidden session could swap onto a decoy disk or mount a decoy filesystem. NAILS now masks the unit under the name systemd gives it.

Until you run a build with the first fix, end Debian 13 and Ubuntu 24.04 sessions with nails deactivate --poweroff, or nails emergency --poweroff. A power-off has no way back, so none of these login or boot records are written.

NAILS now keeps the hidden layers of a decoy filesystem overlaid at a mount point with a . component under the name of its unit, such as <hidden-root>/root/mounts/mnt-backup for /mnt/./backup, where 0.3.0-rc.2 used mnt-.-backup. If an earlier build left such a directory, rename it while NAILS is inactive, or the hidden files in it stay out of view.

Security support

On the day of this release, the security policy says that only the most recent 0.2.x release carries security fixes. A problem in a release candidate is fixed in a new -rc.N, because a published release never changes. A fix reaches you as a new release, so the releases feed is enough to hear of it. Follow it inside a hidden session or on another device, never on the decoy. To report a vulnerability, use the private channels on the security page.

Read more

  • The NAILS docs walk through setup and use in task order.
  • Download has the release the docs describe and the steps to verify it.
  • The changelog has every change. The notes of rc.3 on GitHub are its changelog section, so they hold only what changed since rc.2. The 0.3.0-rc.2 section holds the rest of the changes since 0.2, the upgrade notes among them.
  • The FAQ answers common questions, and the comparison page shows how NAILS differs from other tools.

Release notes for v0.3.0-rc.3 on GitHub