Changelog

What's changed.

All published releases — straight from GitHub. Full commit history on GitHub history.

  • CLI history: what was run over the CLI companion is now visible in the app. Every NeoSSHWinManager-cli.exe invocation against a saved connection is recorded and can be reviewed inside the GUI — both --exec calls (command, output, exit code) and interactive sessions (full screen transcript). A new "View CLI history" button in the connection details opens a dedicated panel (src/ui/clihistorypanel.py) listing entries newest first — a Session/Command badge, timestamp (start–end for sessions), the command line and its exit code, with the output collapsed until clicked so long histories stay scannable — plus "Download as .txt" for the complete history and "Clear history". UI strings ship in all six supported languages.
  • History entries are stored in a new encrypted clihistory table: command and output are encrypted with the same per-user key as connection passwords, never written in plaintext, and are capped at 500 entries per host (oldest pruned by insertion order) and 256 KB per entry to bound database growth. The CLI process never holds the GUI session's encryption key, so it hands the entry to the running GUI instance over the existing user-restricted IPC pipe (new clilog action, same access-key check and per-PID rate limit as cli_connect), which does the encrypting and storing.
  • Interactive session transcripts are rendered the way the screen actually looked rather than dumped as a raw byte stream: backspace and DEL now delete the character to the left instead of leaving \x08 litter in the log after a typo, and a bare carriage return repositions the cursor instead of being treated as a newline — so progress bars (pip, apt, curl, docker pull, npm) show their end state instead of one line per redraw. ANSI/VT100 escape sequences are stripped. Recording is strictly best-effort and fully exception-swallowed; it can never affect the SSH session, its exit code, or its runtime.
  • NEOSSHEXECTIMEOUT (seconds) sets an optional time limit for --exec; unset means no limit.
  • SSHFS drives no longer disappear because their long-running process lost or blocked on GUI-owned debug pipes. Mounts now run in foreground mode with parent-independent standard handles, retain their process handle, and require a free drive letter that becomes stably available.
  • Disconnect now finds the exact SSHFS process through the bundled psutil dependency instead of the deprecated WMIC command, treats an already absent drive as success, and cancels stale Explorer label updates that could create ghost-drive entries.
  • The CLI tool always exited with code 0, even when nothing worked. launchsshincurrentterminal() returned nothing and climain.py reported success unconditionally, so a failed connection, a rejected host key or a failed authentication was indistinguishable from a successful run — scripts calling the CLI could not detect failure at all. The function now returns an exit code, and --exec propagates the remote command's exit status (via recvexit_status()) instead of discarding it.
  • --exec output was lost whenever the caller redirected stdout. Output was written to the CONOUT$ console screen buffer through WriteFile, which is not the process's stdout: NeoSSHWinManager-cli.exe --connect-cli … --exec "…" > out.txt reported success and produced an empty file. Non-interactive mode now writes exclusively to the real process streams, and the interactive path falls back to them if no valid console handle exists instead of writing into the void.
  • --exec aborted after 30 seconds. The hardcoded timeout was too short for anything substantial (test runs, npm install, backups) and cut execution off mid-command; ssh itself imposes no such limit. There is no default limit anymore — see NEOSSHEXECTIMEOUT above.
  • --exec status messages ("Connecting to …") went to stdout and contaminated the command output that scripts parse; they now go to stderr, leaving stdout to the remote command alone. Execution errors with an empty str(e) — common for socket.timeout — no longer produce a bare "Error executing command:" with no cause, and a timeout now says so explicitly and points at NEOSSHEXECTIMEOUT.
  • The IPC listener silently dropped any request larger than 64 KB. A single ReadFile against a message-mode pipe signals an oversized message with ERRORMOREDATA rather than an error, so the GUI just saw a truncated payload fail to parse and handled no request at all. The listener now drains the full message (with a 2 MB ceiling) and the pipe buffers were raised to 1 MB — required for cli_log entries carrying command output, and a latent bug for any future large request.
File Size
NeoSSHWinManager.exe 180.7 MB
NeoSSHWinManager-Setup-1.5.5.exe 210.5 MB
NeoSSHWinManager-cli.exe 29.7 MB
  • Use of the update function is now part of opt-in telemetry. Users who have consented to telemetry transmit additional information regarding whether they use the update function, how they access it, and whether an update was actually performed: updatecheck (with source=startup|settings and result=available|uptodate|failed), updateaction (which button was pressed: Download, Browser, Later, Install Now, Enable/Disable for next startup), updatedownload (ok|failed), and updateresult. Each event also includes the currently running version. No new personal data is collected; the events act as counters without any identifying markers, and the entire transmission remains subject to the telemetry_enabled setting.
  • It is not possible to determine whether an update was actually successful while the process is underway: the installer provides no feedback and only executes after the application has closed. Therefore, launchpendinginstaller() creates a file named updateattempt.json alongside the pending update marker. Upon the next startup, the running version is compared with the recorded target version: the result is installed if they match, and notinstalled if the installation was aborted or failed. Entries older than one week are discarded without analysis rather than being included in the statistics for the wrong day.
  • Auto-update now installs via the Windows installer instead of swapping the exe. The update check downloads the release's Setup.exe (never the portable exe again) into %APPDATA%\SSHWinManager\updates and remembers it in pending_update.json. If the update is armed, the next program start hands over to a helper script that waits for the app to exit, runs the installer, and starts the app again afterwards — whether the installer completed or was cancelled. This guarantees the update is actually applied and keeps the installed copy's registry entries, shortcuts and uninstall information in sync.
  • Releases now ship a sha256sums.txt asset, so the SHA-256 verification the updater has always attempted actually runs — a downloaded installer whose hash does not match is discarded instead of installed.
  • The update dialog now offers "Install update at next program start" (a checkbox that can be toggled at any time) and "Restart and install now". A running update check also reports an installer that was already downloaded earlier, so a declined update can be armed later without downloading again — including when the app is offline and the GitHub check fails.
  • Auto-update silently did nothing; the old version kept starting. The settings screens called installonexit() immediately after the download finished, not on exit: the generated batch script waited 3 seconds and then tried to del the running executable, which Windows refuses. The subsequent move failed too, so the old exe was simply restarted. Every step was unchecked and its output discarded, so nothing was logged or shown. On top of that, an installed copy usually lives in a directory the user may not write to at all, and the path validation used to reject perfectly normal paths (anything containing (, ) or ~, e.g. C:\Program Files (x86)\…) without any user-visible error. The whole exe-swap mechanism is gone — see above.
  • The update check picked the portable NeoSSHWinManager.exe release asset, so even a successful swap left an installed copy registered under the old version. It now looks for the Setup asset and falls back to the release page in the browser if a release does not ship one.
File Size
NeoSSHWinManager.exe 180.5 MB
NeoSSHWinManager-Setup-1.5.4.exe 210.1 MB
NeoSSHWinManager-cli.exe 29.5 MB
  • Startup crash on broken/orphaned ACLs: setsecure_permissions() no longer crashes the app when the DACL itself can't be read (e.g. leftover broken permissions from an older install) — degrades to a logged warning instead, matching how the write step already behaved.
  • Pro activation always failed with a network error: the validation endpoint pointed at the apex domain, which redirects to www. and silently drops the POST body along the way. Now points at www. directly.
File Size
NeoSSHWinManager.exe 180.5 MB
NeoSSHWinManager-Setup-1.5.2.exe 210 MB
NeoSSHWinManager-cli.exe 29.5 MB
  • Windows installer (installer/NeoSSHWinManager.iss, built with Inno Setup 6): a proper Setup.exe alongside the existing standalone executables, with a setup wizard offering desktop shortcut and "start with Windows" tasks, an optional CLI component (NeoSSHWinManager-cli.exe can be excluded via a Compact install), and an app-preferences page to pre-select the application's language and dark/light theme before first launch. The installer's own UI is available in English, German, Spanish, Russian and Dutch. Preferences chosen in the wizard are written to install_prefs.json and applied by AuthManager.register() when the first local user account is created, instead of the hardcoded en/dark defaults.
  • CLI companion executable restored: NeoSSHWinManager-cli.exe (console subsystem, climain.py) is back in the build (NeoSSHWinManager-cli.spec, builddual.ps1) after being dropped from distribution in 1.5.1. Lets a saved connection with CLI access enabled be reached non-interactively via NeoSSHWinManager-cli.exe --connect-cli <access_key> [--exec "command"] while the main GUI is running and logged in. The GUI's own build stays a standalone onefile executable, unaffected.
  • FTP and FTPS support: Connections now carry a protocol (SFTP / FTPS / FTP). The file browser speaks all three — the new src/ftp_client.py implements FTP over ftplib with explicit TLS (AUTH TLS, port 21), implicit TLS (port 990) and plain unencrypted FTP, MLSD listings with a LIST fallback for older servers, passive/active mode, progress-reporting up- and downloads and automatic re-login after an idle timeout.
  • Add/Edit form gained a protocol selector plus FTP options (implicit TLS, passive mode, certificate verification); the port follows the protocol default (22 / 21 / 990) unless a custom port was entered, and SSH-only fields (key file, drive letter, CLI access, PuTTY key) are hidden for FTP connections.
  • Plain-FTP connections can be handed to the on-board Windows Explorer FTP client from the card context menu (the password stays out of the URL — Explorer asks for it).
  • FTP/FTPS connections cannot be mounted as a drive and have no SSH terminal: their card shows a protocol badge and opens the file browser, and mount/terminal/system-info actions report that they are unavailable instead of failing later.
  • Database migrations now run each ALTER TABLE independently, so one column that SQLite refuses (e.g. adding a UNIQUE column to an old table) no longer silently skips every migration after it.
  • SSHFS write corruption: Files could end up as pure NUL bytes after writing/overwriting through a mounted drive. Caused by FileInfoTimeout=-1, which turns on WinFsp's write-back file data caching; a hard-killed sshfs.exe (e.g. on unmount) could drop not-yet-flushed pages and leave the server-side zero-fill in place. Mounts now use a finite FileInfoTimeout, synchronous SFTP writes (sshfssync) and disabled read-ahead (noreadahead) instead.
  • New folders/files invisible until refresh: sshfs.exe carries its own directory-entry cache (dircache/dcachedir_timeout, default 20s) entirely separate from — and underneath — the WinFsp-side cache timeouts this app already sets, so the existing "disable directory cache" setting never fully applied. Mounts now also tune the sshfs-side cache (fully disabled when that setting is on, tightened to match otherwise).
  • "New Folder"/new file silently duplicated 4x in Explorer: on a mounted drive, creating an item in Windows Explorer could appear to fail (no rename prompt) and then show up to 4 times after a manual refresh. Root cause is an upstream WinFsp/Windows security-token mismatch (TokenUser vs TokenOwner) that only affects the built-in Administrator account when UAC Admin Approval Mode is disabled for it (Windows' default for that account) — not fixable from the app's mount options. Documented for anyone else hitting it: enable "User Account Control: Admin Approval Mode for the Built-in Administrator account" (secpol.msc or FilterAdministratorToken=1) and log back in.
  • Startup crash after fixing the account-token issue above: files created earlier under the affected account end up owned by the BUILTIN\Administrators group instead of the user; once that account's token no longer carries the group, the app's own permission-hardening (SetFileSecurity) started failing with access denied and crashing startup. That call is now best-effort (logs a warning instead of crashing), and the app now detects this exact ownership mismatch on its own at startup and offers a one-time, UAC-elevated automatic repair (src/permission_repair.py) — so anyone hitting this after an update or reinstall gets a guided fix instead of a crash.
  • CLI access key could never match, for any connection: getbyclikey() re-encrypted the incoming key with a fresh random AES-GCM IV and compared the result against the stored ciphertext — which uses a different random IV from when the key was originally saved, so the comparison could never succeed even for the correct key. Lookup now uses a deterministic cliaccesskeyhash (SHA-256 of the plaintext key) instead; existing connections get this hash backfilled automatically on next login.
  • CLI SSH connections always rejected: launchsshincurrentterminal() (used by --connect-cli) set a RejectPolicy host-key policy but never actually loaded knownhosts into paramiko first, so every connection was rejected as "unknown host" regardless of what was already trusted on disk. Now loads the same knownhosts file the rest of the app uses before checking the policy.
  • Embedded terminal froze the whole window while connecting: opening an SSH session in the integrated xterm.js terminal (terminalclient setting = "xterm") called TerminalBridgeServer.createsession_token() — which runs a blocking paramiko.SSHClient.connect() — directly on the Qt main thread. A slow or unresponsive host could freeze the entire UI for the length of paramiko's auth timeout (30s by default) on top of the connect timeout. Connection setup now runs in a background TerminalConnectWorker (src/ui/worker.py), matching the existing MountWorker/UnmountWorker pattern; the tab is only created once the SSH session is actually up.
  • CLI access over --connect-cli now also works for password-authenticated connections: the local IPC response includes the password (previously withheld per an earlier finding). The pipe was already restricted to the current user's SID (makepipesecurityattributes), the 64-byte access key itself is a strong bearer secret, and requests are already rate-limited per PID — sending the password over this already-restricted channel was the missing piece for a CLI feature whose whole purpose is unattended access to saved connections, not an added exposure.
File Size
NeoSSHWinManager.exe 180.5 MB
NeoSSHWinManager-Setup-1.5.2.exe 210 MB
NeoSSHWinManager-cli.exe 29.5 MB
  • Integrated in-app terminal: New xterm.js-based SSH terminal embedded directly in the app (via QWebEngineView/QWebChannel, bridged to a local WebSocket server), selectable in Settings alongside the existing external SSH/PuTTY launchers. Supports multiple concurrent sessions per connection with a tab bar, background persistence when switching panels, and a reconnect button after disconnect.
  • Native SFTP browser: New file-browser window (src/ui/sftp_browser.py) reachable from the connection card once a host is mounted — directory navigation, upload/download with progress, rename, delete and new-folder, all run off the UI thread via dedicated worker threads.
  • Pro license system: Machine-fingerprint based activation (src/pro_manager.py) with an offline, HMAC-verified license check and a new "Pro License" section in Settings. The free tier is capped at 3 concurrent integrated-terminal sessions; exceeding it surfaces an upgrade prompt.
  • Connection templates & duplicate-name detection: Add/Edit dialog gained a template dropdown (save/apply/delete) and now blocks duplicate connection/template names, auto-suggesting a unique alternative.
  • Connection card context menu: Right-click menu for mount/unmount, open in Explorer, open SFTP browser, and connect via OpenSSH/PuTTY/integrated terminal.
  • Logout confirmation dialog: Choose between staying logged in, quitting while keeping drives mounted, or quitting and unmounting everything.
  • Startup prerequisite check: Blocks launch with download links if WinFsp and/or SSHFS-Win are not installed.
  • Settings: New terminal-backend selector (SSH/PuTTY/integrated xterm) and a toggle to disable SSHFS attribute/directory caching for hosts where stale cache data is an issue.
  • New GitHub Actions release-build workflow and a nightly version/push helper script for the release process.
  • The connection card's SSH button now opens the integrated terminal when that backend is selected in Settings, falling back to the external client otherwise; "open mounted path" now opens the new SFTP browser instead of the system file explorer directly.
  • Title bar redesigned with a unified look matching the selected Dark/Light theme; accent color updated app-wide (#00b4d8 → #0077b6).
  • SSHFS mounts now set explicit WinFsp attribute/directory/volume-info cache timeouts (tightened further when caching is disabled), and unmounting escalates to force-killing a stuck sshfs.exe process after a 10s grace period.
  • Password-based SSH_ASKPASS hardening (one-time IPC token instead of plaintext env var) now applies starting at security level 1 instead of requiring level 2, for both the native SSH launcher and PuTTY.
  • System tray "Quit" now routes through the same mount-cleanup/logout confirmation flow as the main window instead of calling QApplication.quit() directly.
  • Frameless window resize-cursor handling now works correctly when the mouse is over child widgets, not just the window frame itself.
  • Build: CLI companion executable dropped from build_dual.ps1 (GUI-only distribution going forward); PyInstaller build now strips symbols and excludes unused stdlib modules (tkinter, unittest, pytest, etc.) to reduce executable size.
  • getuserby_username no longer selects sensitive columns (password hash/salt, encrypted key) it doesn't need, reducing accidental exposure of credential material in memory.
  • Admin-only account operations (password reset, delete user, list users) now enforce authorization at the auth_manager layer instead of relying solely on UI-level gating.
  • Login lockout timers switched from monotonic to wall-clock time so a lockout can no longer be bypassed by restarting the app.
  • The updater validates executable/update file paths before embedding them in its self-replace script, and now verifies a SHA-256 checksum of the downloaded update before applying it (falls back to a warning if the release provides no checksum).
  • Telemetry action parameters are now URL-encoded before being sent, closing a parameter-injection edge case in the query string.
  • Terminal and SFTP sessions use single-use, expiring session tokens, wipe passwords from memory immediately after use, and bind the local bridge server to loopback only; both features share the same TOFU host-key verification and confirmation dialog used elsewhere in the app.
  • Second app launch now correctly restores/focuses the main window even when it was hidden to the system tray, instead of doing nothing.
File Size
NeoSSHWinManager.exe 173.2 MB
  • Connection groups/tags and reusable templates across the data model, database migration, add/edit flows and translations
  • Bulk mount/dismount actions and a group filter in the main connection header
  • Dedicated profile panel for end users to review their account and change their password
  • Manual GitHub update checks with download progress and an install-on-exit flow
  • Telemetry opt-in prompt, persisted telemetry settings and asynchronous telemetry submission
  • Reworked the main window, settings screen and right-panel forms for the 1.5.0 release layout
  • Connection cards now show group pills and compact host details with the drive letter in the subtitle
  • Add/Edit connection flows now support templates explicitly and surface group metadata in the UI
  • Replaced many native message boxes with a themed custom dialog for warnings, confirmations and success messages
  • Pinned core Python dependency versions for the 1.5.0 release environment
  • Updated visible application version strings in the main window, about dialog and single-instance mutex
  • Reduced debug logging of sensitive command-line arguments in the PuTTY launcher
  • Hardened in-memory handling of temporary password tokens used by SSH ASKPASS
  • Hardened SSH_ASKPASS password exchange by replacing plaintext environment transfer with one-time IPC tokens
  • Relaxed first-contact host-key handling to OpenSSH accept-new for SSH and sysinfo flows while keeping changed-host failures
  • Increased minimum password length from 6 to 8 characters in registration and user-management flows
  • Restricted crash report file permissions so stack traces are no longer world-readable
  • Masked PuTTY password arguments in debug logs to prevent credential leakage
  • Added password fallback when a stored SSH key fails but a password is still available for the same connection
  • Unified destructive confirmation prompts and dirty-form handling through the styled dialog layer
  • Corrected multiple German translation strings and save-label spellings used in the 1.5.0 UI
File Size
NeoSSHWinManager.exe 46 MB
NeoSSHWinManager-cli.exe 28.2 MB
  • Crash when clicking a mounted host (NameError: conn_id not defined in info panel lambdas)
  • Copy button in error dialogs not working
  • Loading state not clearing when ask-password dialog is cancelled
  • Edit mode: section headers too bold compared to info panel
  • Edit mode: password dots disproportionately large
  • Info panel: drive badge replaced with folder SVG icon, only visible when host is mounted
  • Edit mode now matches info panel field order, container structure and section labels
  • Status badge (connected/disconnected pill) shown at top of edit mode for visual continuity
  • Save button: floppy disk icon replaces checkmark
  • Light mode: save button gets subtle green background; delete icon solid red for better contrast
File Size
NeoSSHWinManager.exe 45.7 MB
NeoSSHWinManager-cli.exe 27.8 MB
  • Comprehensive Security Audit: Hardened credential storage, session handling, encryption routines and key derivation across authmanager, crypto, database, sshlauncher and sshfs_controller
  • CWE-312 · Connection Metadata Encryption: Host, username, connection name and remote path are now encrypted with AES-256-GCM before being stored in the database. Existing entries are migrated automatically on first login.
  • CWE-732 · Windows ACL hardened: win32security is now a hard module-level import — a missing pywin32 installation raises an explicit ImportError on startup rather than leaving the database file world-readable.
  • CWE-307 · Brute-Force Protection: Login attempts are now rate-limited per username. After 5 consecutive failures the account is locked for 30 seconds; each subsequent block escalates (10 attempts → 10 min, 5 → 1 h, and further).
  • CWE-362 · Session Race Condition fixed: Session.currentuser is protected by a threading.RLock; enc_key updates after password changes are performed atomically.
  • CWE-591 · Memory-Lock failures now visible: mlockmemory() / munlockmemory() now emit a WARNING log entry on failure instead of returning False silently.
  • CWE-214 · CLI Key via stdin: --connect-cli - reads the access key from stdin, preventing exposure in process listings and shell history.
  • CWE-78 · Shell Injection Prevention: Removed unsafe shell interpolation in sshlauncher; added issafelabel() in sshfscontroller. SSH terminal now launched via cmd.exe + CREATENEW_CONSOLE instead of shell=True.
  • CLI Keys Migration: Plaintext CLI-access-keys are automatically encrypted on first login after the update.
  • SSHASKPASS for Password Auth: Passwords are passed via the SSHASKPASS mechanism — never exposed in the process list.
  • Connection Name Validation: Names containing shell metacharacters are rejected before database insertion.
  • MITM Fix (v1.3.1 omission corrected): StrictHostKeyChecking=yes was already applied in v1.3.1 but not documented. Installations running v1.3.0 or earlier are vulnerable — upgrade immediately.
  • PuTTY PPK Integration: Auto-detection and configurable PPK key path for PuTTY-based connections
  • Native SSH Terminal Improvements: Overhauled terminal launch logic for both PuTTY and native OpenSSH
  • SysInfo available with key or password: System information is retrieved whenever an SSH key or stored password is configured — the security level setting no longer gates sysinfo access.
  • SysInfo Auth Overlay: A clear overlay is shown when neither key nor password is configured, instead of a generic error.
  • Login Lockout Countdown: After a tier-boundary lockout, the login form shows a live countdown with human-readable time remaining.
  • Login Button gated on input: The Sign-in button is disabled until both username and password (≥ 1 char each) are filled.
  • About Dialog Redesign: Card layout with grouped clickable link buttons for project, documentation, GitHub and author links
  • Sidebar About Button: Persistent About button in the sidebar
  • SSHFS Mass Disconnect Bug: Fixed a race condition in sshfs_controller that caused all mounted drives to disconnect simultaneously
  • Drive Unmount Crash: Prevented a crash when a drive was unmounted while the UI still held a reference to it (#1)
  • QMessageBox Dark Mode: Corrected background color of message boxes in dark mode (#3)
  • F2 Crash on Non-Standard Widgets: Prevented crash when pressing F2 on non-standard widgets (#4)
  • Form Scroll Behavior: Fixed scrolling in Add/Edit connection dialog on smaller screens
  • Crash Report Path: Crash reports are now written to %APPDATA%\SSHWinManager\crash_report.txt
  • Worker Thread Error Propagation: Mount/unmount worker threads now catch exceptions and emit a MountResult error instead of crashing silently
File Size
NeoSSHWinManager.exe 45.7 MB
NeoSSHWinManager-cli.exe 27.9 MB
  • Agent CLI key is now directly visible in the connection editor instead of being masked.
  • Added two visible SVG actions for the CLI key: copy and regenerate.
  • Added check-icon feedback after copying the key.
  • Bumped desktop app and website metadata to 1.3.1.
File Size
NeoSSHWinManager.exe 42.9 MB
NeoSSHWinManager-cli.exe 27.8 MB
  • Full-screen Settings and User Management panels via QStackedWidget
  • Sidebar navigation with active-state highlighting
  • [i] button exclusively opens SSH live system-info panel
  • Edit button always visible, disabled when connection is mounted
  • Primary buttons: gradient #00b4d8 to #0077b6, black text
  • Title bar colour adapts to active theme via DwmSetWindowAttribute (Windows 11+)
  • Checkbox checked indicator: 14x14px, white checkmark on red background
  • Panel headers: 52px height, kicker labels removed, titles vertically centred
  • List-style layout with 4px colour-coded progress bars for CPU/RAM/Disk
  • Full static website in website/ (landing, features, docs, changelog, download)
  • Interactive browser simulation (website/app.html) in pure HTML/CSS/JS
  • No installation needed, deployable via GitHub Pages
  • Removed legacy credential_store.py
  • AppUserModelID prefix changed from dennis. to neo.
  • Version bump to 1.3.0
File Size
NeoSSHWinManager.exe 42.9 MB
NeoSSHWinManager-cli.exe 27.8 MB
  • Add persisted light/dark theme support.
  • Add ask-each-time authentication mode for connections.
  • Improve connection card click behavior for mounting.
  • Fix application icons for login and main windows.
  • Bump application and Windows metadata to 1.2.0.
File Size
NeoSSHWinManager.exe 42.7 MB
NeoSSHWinManager-cli.exe 27.7 MB