You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[SFTP] Race Condition during Rekeying: "Message type 93 is not valid" or Connection Drop #1764
Description
We are encountering critical connection failures during SFTP uploads under high network throughput. The issue appears to be a race condition during the SSH Rekeying phase.
When the server triggers a Key Rotation (due to RekeyLimit), the client fails to pause the data stream immediately. Consequently, the client sends a SSH_MSG_CHANNEL_DATA packet while the server has entered the Key Exchange state and expects SSH_MSG_KEXINIT, leading to a protocol violation.
Exceptions & Stack Traces
We observe two different exceptions depending on the server software/configuration:
Renci.SshNet.Common.SshConnectionException: Message type 93 is not valid.
at Renci.SshNet.Session.WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout)
at Renci.SshNet.Session.WaitOnHandle(WaitHandle waitHandle)
at Renci.SshNet.Channels.Channel.SendData(Byte[] data)
at Renci.SshNet.Channels.Channel.SendMessage(Message message)
at Renci.SshNet.Channels.Channel.SendData(Byte[] buffer, Int32 offset, Int32 size)
at Renci.SshNet.Sftp.SftpSession.RequestWrite(Byte[] handle, UInt64 serverOffset, Byte[] data, Int32 offset, Int32 length, Action`1 writeStatusCallback)
Variant 2: Connection Drop (Server resets TCP connection)
Renci.SshNet.Common.SshConnectionException: Client not connected.
at Renci.SshNet.Common.AsyncResult.EndInvoke()
at Renci.SshNet.SftpClient.EndUploadFile(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location ---
at FtpUtils.FtpUtils.SftpTransferFileAsync(...)
Steps to Reproduce
Configure an SFTP server with a low RekeyLimit (e.g., RekeyLimit 500M 0).
Establish a high-speed connection (e.g., > 500 Mbps).
Upload a file significantly larger than the limit.
Result: Connection crashes exactly when the limit is reached.
Analysis
The library seems unable to handle the state transition to KeyExchange fast enough when the outgoing socket buffer is saturated with file data. Confirmed Workaround: The issue is resolved only by setting RekeyLimit none on the server side, which confirms the issue is isolated to the rekeying phase.
Additional Info
Reproducible on the latest revision 2025.1.0 as well as older versions.
Reproducible with both synchronous UploadFile and asynchronous UploadFileAsync / BeginUploadFile implementations.
Question
Is there any client-side configuration or internal buffer setting that could mitigate this race condition without changing the server config? Or any other trick. Thanks!
The only workaround here is to split the filestream into chunks and disconnect/reconnect on each chunk upload, which is less than the rekey limit on the server.
Hi, just acknowledging the issue. There is probably some missing handling or synchronisation around key re-exchange.
I don't have a lot of time or motivation to work on the library right now. I'll try and take a look over the next couple of weeks. (anyone else can also look)
Just to note, I don't think this is conclusion is entirely correct (or at least, not the full picture):
When the server triggers a Key Rotation (due to RekeyLimit), the client fails to pause the data stream immediately. Consequently, the client sends a SSH_MSG_CHANNEL_DATA packet while the server has entered the Key Exchange state and expects SSH_MSG_KEXINIT, leading to a protocol violation.
Note, however, that during a key re-exchange, after sending a
SSH_MSG_KEXINIT message, each party MUST be prepared to process an
arbitrary number of messages that may be in-flight before receiving a
SSH_MSG_KEXINIT message from the other party.
Unfortunately I'm unable to reproduce this, see draft PR #1774. I also tried doing multiple uploads in parallel and different RekeyLimit values and file sizes. I can see the key exchange happening in the debug logs, but it never fails. Maybe I' missing something?
Activity
baradzin commentedon Feb 4, 2026
Environment
baradzin commentedon Feb 10, 2026
The only workaround here is to split the filestream into chunks and disconnect/reconnect on each chunk upload, which is less than the rekey limit on the server.
Rob-Hague commentedon Feb 11, 2026
Hi, just acknowledging the issue. There is probably some missing handling or synchronisation around key re-exchange.
I don't have a lot of time or motivation to work on the library right now. I'll try and take a look over the next couple of weeks. (anyone else can also look)
Just to note, I don't think this is conclusion is entirely correct (or at least, not the full picture):
At the end of RFC 4253 section 7.1 it says:
Rob-Hague commentedon Feb 11, 2026
In the meantime it would be helpful if you can paste some logs at Trace level around the time of the re-exchange https://sshnet.github.io/SSH.NET/logging.html
Trying to repro Rekeying issue sshnet#1764
mus65 commentedon Mar 21, 2026
Unfortunately I'm unable to reproduce this, see draft PR #1774. I also tried doing multiple uploads in parallel and different RekeyLimit values and file sizes. I can see the key exchange happening in the debug logs, but it never fails. Maybe I' missing something?
radekvermirovsky commentedon Aug 27, 2026
@baradzin could you please confirm whether you were experiencing these errors against ProFTPD, a classic OpenSSH server, or something else? See #1823
Fix race between SendMessage and server-initiated key re-exchange
Accept and defer connection protocol messages received during a key r…