Release Notes
Security
An outside security review of the tree read the source, the config, the history, the
dependencies and the CI, and found thirteen things worth fixing. This release closes all of
them. None was a remote code execution or a leak in the default setup, but two of them undercut
promises the docs were already making.
- The askpass helper now knows whether the stored secret is a login password or a key
passphrase, and only answers the matching prompt. Before, a server that askedPassword:
over keyboard-interactive could be handed a key passphrase, because the text of that prompt
is written by the server andPassword:is a perfectly ordinary shape. A key host now
answers only OpenSSH's ownEnter passphrase for key '<path>':, and only when the path is one
of the key files sshelf passed with-i. - Key hosts connect with
PreferredAuthentications=publickey(pluskeyboard-interactivefor
2FA hosts), so a server can no longer steer a key host into a password prompt. If a key host
of yours relied on falling back to a password, add the password as a second host or switch its
auth to password. - Jump hosts never see the askpass helper. With one jump host and a stored secret the hop runs
withBatchMode=yesand password and keyboard-interactive auth off, which is what the FAQ
always said jump hosts had to be. With two or more hops, ssh asks for the target's secret on
the terminal instead, and sshelf says so before it does. - The transfer screen's control socket moved from
/tmpinto a private directory under
$XDG_RUNTIME_DIR(or the data dir) with mode 0700, so another local user can't squat on the
path and stall or answer the connection. - Remote listings and mkdir over sftp have a timeout and an output cap, and closing the transfer
screen no longer waits forever on a stuck server. - Temporary files are created exclusively with random names, forward logs moved from
/tmpinto
the data directory with mode 0600, and the transfer log refuses to follow a symlink. sshelf list,sshelf import,sshelf doctorand the shell completions replace terminal
control characters in host and site fields before printing them.sshelf list --jsonis
unchanged. The add/edit form and the importers now refuse a name that carries one.- The 2FA code is masked while you type it, in the TUI and on the command line.
- sshelf no longer changes the permissions of a config directory it didn't create.
sshelf doctorwarns if that directory is world- or group-writable, or is not yours. - Downloads land under a temporary name and are installed without replacing an existing file.
Uploads are still checked against the last listing, which is refreshed right before a send;
the docs now say what that check does and does not promise. - Release workflows: every action is pinned to a commit, the version input can't reach a shell
unescaped, companion jobs build the exact commit the release built and refuse to publish if
the tag has moved, permissions are read-only except where a job uploads, and release artifacts
now carry build attestations.
Changed
Ctrl-yandsshelf print-commandresolve the host's stored secret first, so the command they
give you is the one sshelf would run, including theProxyCommanda jump host gets. The
commandfield ofsshelf list --jsonis unchanged: a listing has no business reading the
keyring once per host.
Install sshelf 0.14.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/max-rh/sshelf/releases/download/v0.14.0/sshelf-installer.sh | shInstall prebuilt binaries via Homebrew
brew install max-rh/tap/sshelfDownload sshelf 0.14.0
| File | Platform | Checksum |
|---|---|---|
| sshelf-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| sshelf-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| sshelf-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| sshelf-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
Verifying GitHub Artifact Attestations
The artifacts in this release have attestations generated with GitHub Artifact Attestations. These can be verified by using the GitHub CLI:
gh attestation verify <file-path of downloaded artifact> --repo max-rh/sshelfYou can also download the attestation from GitHub and verify against that directly:
gh attestation verify <file-path of downloaded artifact> --bundle <file-path of downloaded attestation>