CVE-2026-48855 Overview
CVE-2026-48855 is an information disclosure vulnerability in the Erlang/OTP ssh_sftpd module. The SSH_FXP_READLINK handler returns the raw result of file:read_link/2 to the client without invoking chroot_filename/2 to strip the backend root prefix. An authenticated SFTP client can create a symlink inside the chroot pointing to /, then read the link back to obtain the absolute backend root path, such as /data/sftp, instead of the chrooted value /. The flaw is tracked under [CWE-200] and resides in lib/ssh/src/ssh_sftpd.erl.
Critical Impact
An authenticated SFTP client can disclose the absolute filesystem path of the SFTP root directory and symlink targets within it, bypassing chroot path obfuscation.
Affected Products
- Erlang/OTP versions from OTP 17.0 before 29.0.2
- Erlang/OTP 28.5.0.x before 28.5.0.2
- Erlang/OTP 27.3.4.x before 27.3.4.13 (corresponding to ssh from 3.0.1 before 6.0.1, 5.5.2.1, and 5.2.11.8)
Discovery Timeline
- 2026-06-10 - CVE-2026-48855 published to NVD
- 2026-06-10 - Last updated in NVD database
Technical Details for CVE-2026-48855
Vulnerability Analysis
The Erlang/OTP ssh_sftpd module implements an SFTP server that confines clients to a configured root directory using a chroot abstraction at the protocol layer. Path responses sent back to clients are normally rewritten through chroot_filename/2, which strips the backend root prefix so clients only see paths relative to their chroot.
The SSH_FXP_READLINK handler skipped this rewrite. When a client requested the target of a symbolic link, the handler invoked file:read_link/2 and forwarded the resulting path directly to the client via ssh_xfer:xf_send_name. If the symlink resolved to an absolute path on the underlying filesystem, the client received that absolute path verbatim.
The disclosed information is limited to the absolute filesystem path of the SFTP root directory and any symlink targets within it. No file contents, credentials, or access to paths outside the chroot are obtainable through this issue alone. Authentication to the SFTP service is required for exploitation.
Root Cause
The root cause is a missing call to chroot_filename/2 in the SSH_FXP_READLINK response path inside lib/ssh/src/ssh_sftpd.erl. Every other path-returning handler normalized output through the chroot translation, but READLINK returned the raw backend filesystem path. The patch additionally canonicalizes the target via filename:absname/2 before applying chroot rewriting.
Attack Vector
An authenticated SFTP client creates a symlink inside the chrooted directory pointing to /. The ssh_sftpd server resolves the target to the absolute backend root and stores it on disk. The client then issues SSH_FXP_READLINK against the symlink. The server response leaks the absolute path of the SFTP root, for example /data/sftp, instead of the expected chrooted value /.
{Res, FS1} = FileMod:read_link(AbsPath, FS0),
case Res of
{ok, NewPath} ->
- ssh_xfer:xf_send_name(State#state.xf, ReqId, NewPath,
- #ssh_xfer_attr{type=regular});
+ AbsTarget = filename:absname(NewPath, filename:dirname(AbsPath)),
+ ChrootedPath = chroot_filename(canonicalize_filename(AbsTarget), State),
+ ssh_xfer:xf_send_name(State#state.xf, ReqId, ChrootedPath,
+ #ssh_xfer_attr{type=regular});
{error, Error} ->
ssh_xfer:xf_send_status(State#state.xf, ReqId,
ssh_xfer:encode_erlang_status(Error))
Source: GitHub Commit 8f4224a0 — the patch resolves the symlink target to an absolute path, then applies chroot_filename/2 to strip the backend root before sending the response.
Detection Methods for CVE-2026-48855
Indicators of Compromise
- SFTP audit logs showing authenticated users issuing SSH_FXP_SYMLINK operations that create links pointing to / or other absolute backend paths.
- Subsequent SSH_FXP_READLINK requests from the same session targeting newly created symlinks within the chroot.
- Reconnaissance patterns where a session creates a symlink, reads it back, then immediately deletes or alters it.
Detection Strategies
- Enable verbose SFTP protocol logging on Erlang/OTP ssh_sftpd deployments to capture SSH_FXP_SYMLINK and SSH_FXP_READLINK request pairs per session.
- Correlate authenticated SFTP sessions with anomalous symlink creation activity inside the chroot root directory.
- Compare installed Erlang/OTP versions against the fixed releases 29.0.2, 28.5.0.2, and 27.3.4.13 to identify exposed hosts.
Monitoring Recommendations
- Track ssh_sftpd process activity for unusual symlink creation rates within configured SFTP root directories.
- Alert on file events where a symlink inside the SFTP chroot resolves to a path at or near filesystem root.
- Inventory all hosts running ssh_sftpd and continuously assess them against the Erlang Security Advisory GHSA-pv7g-pjrq-x2fh.
How to Mitigate CVE-2026-48855
Immediate Actions Required
- Upgrade Erlang/OTP to version 29.0.2, 28.5.0.2, or 27.3.4.13 depending on the deployed release line.
- Audit existing SFTP root directories for symlinks that point to absolute backend paths and remove them.
- Restrict SFTP accounts to the minimum set required and rotate credentials for any account that may have probed paths via this issue.
Patch Information
The fix is delivered in Erlang/OTP 29.0.2, 28.5.0.2, and 27.3.4.13. The patch in lib/ssh/src/ssh_sftpd.erl canonicalizes the symlink target via filename:absname/2 and applies chroot_filename/2 before sending the response. See the GitHub Security Advisory GHSA-pv7g-pjrq-x2fh, the CNA advisory, and the OSV entry EEF-CVE-2026-48855 for full release details.
Workarounds
- Disable SFTP access for untrusted authenticated users until the patched Erlang/OTP release can be deployed.
- Remove or block creation of symbolic links inside SFTP chroot directories using filesystem-level controls where supported.
- Place the SFTP root at a path whose disclosure carries minimal sensitivity, reducing the value of any leaked absolute path.
# Verify the installed Erlang/OTP version against the fixed releases
erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell
# Inspect ssh application version (should be >= 6.0.1, 5.5.2.1, or 5.2.11.8)
erl -eval 'application:load(ssh), {ok, V} = application:get_key(ssh, vsn), io:format("ssh ~s~n", [V]), halt().' -noshell
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


