Repository navigation
fix: hand the enrollment token to the sudo re-exec in a file, not argv - #40
Merged
Merged
Conversation
Run without root, the installer re-executed itself as sudo LATTICE_NODE_TOKEN=<token> ... sh install.sh, and sudo stays alive for the whole install, so any local user could read the token in ps for as long as it ran. The token now goes to the root child in a file only the invoking user can read: mktemp makes it 0600 in TMPDIR, sudo receives only its path in LATTICE_NODE_TOKEN_FILE, and the child reads it and removes it at once. The parent no longer execs sudo, so it removes the file too when sudo returns, fails or is interrupted. A file works whatever sudoers keeps or resets of the environment, which --preserve-env does not. The child reads only a file the re-exec could have made: a regular file, not a symlink, mode 0600 with no ACL, owned by SUDO_UID (or by root without sudo). Anything else dies before any download. Tested: test-install-integrity.sh records the fake sudo's command line and fails when the token is on it (it fails so on the previous installer), checks that the token reaches the service definition and that no token file outlives an install or a failed sudo, and refuses a symlinked, a 0644 and a foreign-owned token file; under macOS sh, dash, Debian bookworm and Alpine 3.20. check-release-workflow.sh passes.
From the security review of the file handover. The token file now sits in a 0700 directory that mktemp -d makes, written under umask 077, so nobody else can swap it between the root child's checks and its read, even where TMPDIR lacks the sticky bit. The child checks the directory (mode 0700, owned by SUDO_UID) and the file (regular, one link, mode 0600, the same owner), says so plainly when a default ACL on TMPDIR is the cause, removes only the file and then the directory if it is empty, and never removes a path it was handed. The parent's traps exit with 129, 130 and 143 for HUP, INT and TERM. Tested: test-install-integrity.sh also refuses a hard-linked token file and one in a world-readable directory; under macOS sh, dash, Debian bookworm and Alpine 3.20. check-release-workflow.sh passes.
…en directory From the re-check of the private-directory handover. In a TMPDIR every user can write to without the sticky bit, another user can rename the token directory away and plant one of their own between the root child's checks and its read. The installer now refuses such a TMPDIR before running sudo, following a symlinked TMPDIR to the directory it names. The comment says what the private directory does close: the file cannot be replaced or linked. A default ACL on TMPDIR, inherited by the token directory, now gets the ACL message at the directory check as well. Tested: test-install-integrity.sh refuses a 0777 TMPDIR before sudo runs and before any token file is written; under macOS sh, dash, Debian bookworm and Alpine 3.20. check-release-workflow.sh passes.
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Keeps the enrollment token off sudo's command line. Base:
integrationat 75e54b2. Not merged, tagged or released. lattice-server #212 (LatticeNet/lattice-server#212) vendors this head.The problem
Run without root, the installer re-executed itself as
exec sudo LATTICE_NODE_TOKEN=<token> ... sh install.sh. sudo stays alive for the whole install, so any local user could read the token inpsfor as long as it ran. sudo also writes its command line to its log (auth.log or journald, or a sudo logfile), where the old form leftLATTICE_NODE_TOKEN=<token>.The fix
The token goes to the root child in a file. The non-root parent:
mktemp -dunderTMPDIR;tokeninto it underumask 077;LATTICE_NODE_TOKEN_FILE.The parent no longer execs sudo. It removes the directory when sudo returns, fails or is interrupted (EXIT, plus HUP, INT and TERM with 129, 130 and 143). It refuses a
TMPDIRevery user can write to without the sticky bit, before sudo runs, following a symlinkedTMPDIRto its target. A file works whatever sudoers keeps or resets of the environment, which--preserve-envdoes not.The root child reads only a file the re-exec could have made:
SUDO_UID(0 without sudo);Anything else dies before any download. The child reads the token into a variable, removes the file, and removes the directory only if that leaves it empty. It never removes a path it was handed.
Tests
scripts/test-install-integrity.shrecords the fake sudo's command line and fails when the token appears on it. Against the installer at 75e54b2 it fails with exactly that message. It also checks:TMPDIRis refused before sudo runs and before any file is written.Local, all pass:
sh scripts/test-install-integrity.shandsh scripts/check-release-workflow.shunder macOS/bin/shand dash, and indebian:bookworm(dash) andalpine:3.20(busybox ash) as uid 1000.Review
security-reviewer on 5cea729: no Critical or High. The token no longer reaches argv on any installer path. A third user polling
psevery 2 ms during a sudo install never saw it.Fixed in d5d79c8 and f7deddc, from its Lows:
TMPDIRwritable by every user without the sticky bit is refused);Not changed here:
env LATTICE_NODE_TOKEN=... ./lattice-agent-install.shshows the token inenv's argv for about a millisecond, and it lands in shell history and in any wrapper's argv (ssh host '<cmd>', cloud-init). The fix needs a product decision: a single-use enrollment code exchanged by the installer, or a separate no-echo prompt. It is reported to the operator.kill -9of the parent during the password prompt leaves the token file behind, now inside a 0700 directory.Re-checks of d5d79c8 and f7deddc: nothing at Critical, High or Medium. The reviewer ran the installer through sudo on debian:bookworm with several
TMPDIRs:/tmp;Left as is, on the reviewer's advice: a group-writable
TMPDIRwithout the sticky bit is accepted. It needs the user to choose such a directory, and its worst effect is a wrong token sent to the real server.