- known_hosts: the @cert-authority pattern matcher was recursive and
backtracking; a pattern of a few hundred thousand stars overflowed the
connect thread's stack on every handshake and '*a*a*a…b' went
exponential. It is now the iterative two-pointer match, and patterns
over 1 KiB are refused on import and in Trust a CA.
- Agent-forward and remote-forward channels are only honoured on the
final hop: a jump host could previously open auth-agent channels and
reach remote-forward destinations on the client machine.
- Remote forwards with no bind address listen on the server's loopback
(as ssh -R does) instead of every interface.
- Keyboard-interactive gives up after 10 rounds; dials through jump hosts
and run_command have timeouts; the handshake timeout leaves room for
the host-key prompt so a slow reader isn't timed out mid-decision.
- Known hosts are looked up per key type, so an imported known_hosts with
ed25519 and RSA rows no longer produces a false 'key changed' warning.
- SFTP download suggests a sanitised base name in the save dialog.
- sync: timestamps and tombstones in the shared file are clipped to the
local clock, and an edit wins a tie with a deletion, so a forged
future-dated record can no longer override every later local change
(or keep deleting a re-created profile) for as long as the forged date.
- write_private: the temp file is created O_EXCL under a random name, so a
symlink pre-placed in a shared folder can't be followed or overwritten.
- Vault/keychain reads return Zeroizing<String>; has_sync_password is
cached for a few seconds instead of fetching the real value every frame.
- generate_ssh_key creates a missing ~/.ssh as 0700.
- Honest wording: encrypted exports and the sync file carry login-script
values; the audit entry, the Settings hint and the docs now say so.
An optional 'Nexus Terminal' printer (IronRDP's PostScript driver
announce) appears on the remote desktop; each job is written to
'Nexus print <time>.ps' in Downloads, with a toast saying where. Jobs
are capped at 256 MiB and empty jobs leave no file. The shared drive and
the printer now share one RDPDR backend (rdp_devices); the printer
works on every platform, the drive on Linux and macOS.
Tested with a unit test driving create/write/close; xrdp has no printer
redirection, so not exercised against a server.
A CLIPRDR channel with a text-only backend (CF_UNICODETEXT): text copied
on the remote desktop is fetched and goes through the app's remote-
clipboard preference like VNC and OSC 52; local text is offered to the
remote when the desktop gains focus, on Ctrl+V and with Paste Clipboard
(which no longer types the text). Backend callbacks run inside the
active stage, so they queue requests that the session loop sends.
Verified against xrdp: the remote X clipboard read back the offered
text, and a remote copy arrived through on_clipboard.
- Credential callbacks (SecretFn) now return Zeroizing<String>, as do the
session-only/pending caches they read and the RDP client's password,
so Nexus's own copies are wiped; a plain String copy is made only
where a library API needs one (SSH password auth, IRC, VNC, CredSSP).
- Release builds disable core dumps (RLIMIT_CORE 0) and, on Linux, mark
the process non-dumpable (PR_SET_DUMPABLE 0), which also blocks ptrace
attach and /proc/<pid>/mem reads by other processes of the same user.
Debug builds are unchanged so they stay debuggable. Verified on the
release binary: core limit 0, /proc/<pid>/{environ,mem} root-owned and
unreadable, local shells (including cwd capture) still work.
Closes the remaining parts of SEC-20261012-007 that the app controls;
egui's internal text buffers remain outside its reach.
The app now writes a diagnostic log to nexus.log in the data directory
(0600, rotated at 5 MiB): connection attempts and results, remote
closes, reconnect scheduling, host-key/certificate checks with the
policy applied, and credentials that couldn't be stored (kind only).
Credentials and terminal data are never logged. RUST_LOG sets the level
and also mirrors the log to stderr. The remaining eprintln! diagnostics
in storage and URL handling go through it too.