Repository navigation
sshd leaks an LSA logon session (sshd_<pid> virtual account), lsass handles and nonpaged pool on every connection, never released until reboot #2476
Description
Prerequisites
- Write a descriptive title.
- Make sure you are able to repro it on the latest version
- Search the existing issues.
"OpenSSH for Windows" version
- 10.0.0.0 (
Microsoft.OpenSSH.Previewvia winget, OpenSSH_10.0p2), reproduced - 9.5.6.4 (inbox optional feature, OpenSSH_9.5p2), reproduced
Server OperatingSystem
Windows 11 Pro 25H2 (10.0.26200), default sshd_config
Client OperatingSystem
Any. Reproduced locally with ssh-keyscan (Windows); seen in the wild from a Linux monitoring tool (Termix host status check) and from OpenSSH 10.3p1 clients (Alpine/macOS).
What is failing
Every incoming connection that reaches key exchange leaks one LSA logon session (the VIRTUAL USERS\sshd_<pid> privilege-separation account, LogonType 5) plus ~3 handles in lsass.exe and ~50 KB of nonpaged pool. They are never released after the connection closes, whether it closes [preauth] or after a successful login. Only a reboot frees them.
Authenticated connections additionally leak a LogonType 3 (Network) session for the target user.
On a machine that is simply health-checked or polled over SSH, this grows without bound. In my case, after 6 days of uptime:
Win32_LogonSessioncount: 51,080 (normal: ~100). ~36k LogonType 5 (sshd_*virtual users, most with the account already deleted) and ~15k LogonType 3 (NTLM) for the user that logged inlsass.exehandles: 155,000 (normal: ~2,000)- Nonpaged pool: 4.2 GB, paged pool: 3.1 GB
- ~25 GB of RAM in use that does not belong to any process (47 GB machine, processes summing ~20 GB)
The traffic was a monitoring tool opening one connection every ~5 s. After reducing it, the leak continued at the rate of a TCP/SSH status check every ~33 s (connect → KEX → close [preauth]): +3,000 logon sessions in 2 days.
Note: a connection that only reads the server banner and closes does not leak. The leak starts once sshd spawns the per-connection (sshd-session/sshd_<pid> virtual account) child.
Steps to reproduce (elevated PowerShell)
$ks = "C:\Program Files\OpenSSH\ssh-keyscan.exe" # or any ssh-keyscan
$s0 = (Get-CimInstance Win32_LogonSession).Count
$h0 = (Get-Process lsass).Handles
$n0 = (Get-CimInstance Win32_PerfRawData_PerfOS_Memory).PoolNonpagedBytes
1..50 | % { & $ks -t ed25519 127.0.0.1 | Out-Null }
Start-Sleep 5
$s1 = (Get-CimInstance Win32_LogonSession).Count
$h1 = (Get-Process lsass).Handles
$n1 = (Get-CimInstance Win32_PerfRawData_PerfOS_Memory).PoolNonpagedBytes
"Logon sessions +$($s1-$s0) | lsass handles +$($h1-$h0) | nonpaged +$([math]::Round(($n1-$n0)/1MB,1)) MB"
# Leaked sessions: LogonType 5, Negotiate, most with no resolvable account
Get-CimInstance Win32_LogonSession | Group-Object LogonType, AuthenticationPackage | Select Count, NameExpected output
Logon sessions, lsass handles and nonpaged pool return to baseline once the connections are closed.
Actual output
OpenSSH_9.5p2 (inbox), 50 probes:
Logon sessions +51 | lsass handles +152 | nonpaged +2.5 MB
OpenSSH_10.0p2 (Preview, run as a separate LocalSystem service on port 2222), 50 probes, 21 completed (the rest were throttled by PerSourcePenalties):
Logon sessions +22 | lsass handles +60 | nonpaged +2.9 MB
i.e. one leaked logon session per completed connection. The values never go back down; Security log shows a 4624 (LogonType 5, VIRTUAL USERS\sshd_<pid>, process sshd.exe) for each connection with no matching 4634 logoff.
Impact
Any client that can reach port 22 can grow kernel memory and lsass without authenticating, so the server eventually runs out of memory. Monitoring/health checks and automation that open frequent short SSH connections (Ansible, uptime monitors, scripts not using ControlMaster) trigger it in normal use.
Workarounds I'm using: multiplex client connections (ControlMaster/ControlPersist), lower the frequency of health checks, reboot periodically.
Activity
pisarz77 commentedon Oct 27, 2026
Seeing a related but distinct symptom on Windows 11 26H1 build 28000.3231 (AMD64).
On that build with OpenSSH 9.5p2 and 10.4p1 (MSI), the LSA logon-session leak described above does not reproduce — 13 sessions and 1544 lsass handles two hours after boot, vs. your 51,080 sessions / 155,000 handles. So the logon-session/lsass part looks fixed (or not present) here.
However there's a separate, still-present kernel non-paged pool leak tagged
VadS, tied to the same trigger (per-connection sshd child process creation):Upgrading sshd from 9.5p2 to 10.4p1 roughly halves the per-session VadS growth, but doesn't eliminate it — sustained load still shows ~29 MB/h non-paged pool growth over a 3-day measurement (vs. ~95-100 MB/h before the upgrade). WPR/xperf pool tracing with stackwalk attributes the allocations to VAD creation on process/session creation, consistent with the mechanism you describe, just manifesting as pool growth rather than (or in addition to) the LSA session leak.
Ruled out on this box: OpenSSH version alone (helps but doesn't fix), Defender exclusions, Windows Firewall/BFE, VirtualBox drivers, PunkBuster, WSL interop/9P, Windows Search, third-party process spawners.
Happy to share a full WPR trace if useful — different code path than the lsass handle leak above, but same trigger class (per-connection sshd child spawn), so worth noting here in case it's the same underlying VAD-free bug surfacing differently across builds/versions.