CVE-2026-54886
Executive Summary
CVE-2026-54886 is a denial-of-service vulnerability in the SFTP server component (ssh_sftpd) of Erlang OTP's SSH implementation. An authenticated attacker can send SSH_MSG_CHANNEL_EXTENDED_DATA messages with a non-zero type code and a payload at or below the SFTP packet size limit, triggering an infinite tail-recursive loop in the handle_data/4 function. The affected channel process becomes permanently unresponsive, consumes a full CPU time share, and accumulates unbounded message queue memory. While each stuck channel is contained by BEAM's scheduler preemption (preventing node-wide starvation), opening many channels amplifies the CPU and memory impact. The vulnerability is rated Medium severity (CVSS 5.3) and requires only low-privilege authentication on the SFTP service. No official patch has been confirmed across all affected branch commits, though a single source (OSV) claims a fix exists.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in the ssh_sftpd.erl module, specifically in the handle_data/4 function responsible for processing incoming channel data on an SFTP session. The function contains a catch-all clause designed to accept channel data regardless of its type code.
In the SSH protocol, channel data is transmitted via two message types:
SSH_MSG_CHANNEL_DATA(type 0) — standard data used by SFTP for all protocol operations.SSH_MSG_CHANNEL_EXTENDED_DATA(non-zero type codes) — extended data with adata_type_codefield indicating the data's extended type (e.g., stderr on a shell channel).
The SFTP protocol specification (RFC 4253 / SFTP draft) exclusively uses normal channel data (type 0). Extended data carries no semantic meaning for SFTP operations. However, the SSH transport layer permits any authenticated channel participant to send SSH_MSG_CHANNEL_EXTENDED_DATA on an open channel — the protocol does not restrict which message types apply to which subsystem.
The flaw manifests in the catch-all clause of handle_data/4. When the following conditions are simultaneously met:
- Channel data is received with a non-zero type code (
SSH_MSG_CHANNEL_EXTENDED_DATA). - The pending buffer is empty.
- The payload size is at or below the SFTP packet size limit.
The clause tail-calls itself with identical arguments — no data is consumed, no state is advanced, and no exit condition is evaluated. This creates an infinite tail-recursive loop.
Because Erlang uses tail-call optimization, this loop does not grow the call stack, avoiding a stack overflow, but it does prevent the process from ever processing another message. The message queue for that channel continues to grow unboundedly as the SSH connection layer keeps delivering messages. BEAM's reduction-based scheduler gives the stuck process its full time slot continuously, and while other processes on the node remain responsive (preemption still works), each stuck channel consumes 100% of a scheduler thread's time and accumulates memory proportional to incoming traffic.
In the Erlang/OTP implementation, the SSH daemon creates a separate process per channel. This means the infinite loop is contained within the channel process — it does not crash the entire SSH daemon or the BEAM VM. However, an attacker can open multiple channels (bounded by the max_channels option, which defaults to unlimited in some configurations) to amplify the impact.
The attack surface is the SFTP subsystem of the SSH daemon. Any reachable SSH server with the SFTP subsystem enabled is exposed. Authentication (any valid user account) is required, but no special privileges beyond SFTP access are needed.
Exploitation Scenarios
Prerequisites: The target must run Erlang OTP with an SSH daemon exposing the SFTP subsystem. The attacker needs valid credentials for an SSH account (any privilege level).
Step-by-step attack chain:
Reconnaissance: Perform a service scan targeting port 22 (or a custom SSH port). Connect and request the SFTP subsystem to confirm it is enabled. Example with
ssh -s user@target sftp. The SSH bannerSSH-2.0-Erlangis indicative of the backend.Session Establishment: Open an authenticated SSH connection using valid credentials. This can be a low-privilege account — any user permitted to use SFTP is sufficient.
Channel Creation: Open a session channel and request the SFTP subsystem (
subsystemrequest with name"sftp"). The server responds withSSH_MSG_CHANNEL_SUCCESSand the SFTP session becomes active.Weaponization — Triggering the Loop: Using a raw SSH protocol client (e.g.,
paramikowith low-level packet injection, or a custom script usingcryptographyandasyncio), craft and send anSSH_MSG_CHANNEL_EXTENDED_DATApacket targeting the SFTP channel:- Header: byte
\x94(SSH_MSG_CHANNEL_EXTENDED_DATA msg ID 94). recipient_channel: the SFTP channel number.data_type_code: any non-zero value (e.g.,1for stderr).data: any non-empty payload with a byte length at or below the configured SFTP packet size limit (default 32,768 bytes). Even a single byte suffices.
Repeat the packet multiple times to ensure one arrives while the pending buffer is empty and before any normal SFTP data is processed.
- Header: byte
Payload/Execution: Each such packet received when the pending buffer is empty causes
handle_data/4to enter the catch-all clause. Since the clause tail-calls itself with identical arguments, the process spins forever. There is no payload needed beyond the malformed extended data — the vulnerability IS the payload.Post-exploitation Impact: The SFTP channel becomes permanently unresponsive. The associated BEAM process consumes a full scheduler slot. The attacker can open additional channels (bounded only by
max_channelsif set) and repeat the trigger on each. With N open channels, N scheduler threads are pinned at 100% CPU. Memory usage grows as each channel's message queue accumulates unprocessed incoming packets. The SSH daemon remains alive, and other services on the same BEAM node (if co-located) remain functional but experience latency and resource contention. The denial-of-service persists until the SSH daemon or the entire BEAM VM is restarted.
Amplification strategy: An attacker script can automate the process: open M connections × N channels per connection, send the trigger on each channel, and hold the connections open. This maximizes resource consumption.
Impact Assessment
Business impact: The vulnerability enables a low-privilege authenticated denial-of-service against the SFTP service. Any organization exposing an Erlang OTP SSH/SFTP server to untrusted networks is at risk. Since the flaw requires authentication, the primary threat model is insider abuse or compromise of a low-privilege account.
Affected systems: Erlang OTP SSH daemons with the built-in SFTP subsystem (ssh_sftp). Common deployments include:
- Network equipment management interfaces (routers, switches, firewalls) using Erlang-based management planes.
- Enterprise applications embedding the OTP SSH server for file transfer automation.
- IoT and embedded devices running Erlang/OTP for connectivity layers.
- Message queuing systems (e.g., RabbitMQ — while its core is Erlang, the SSH daemon is not typically exposed, but custom deployments may enable it).
Blast radius: Contained per-process. Each stuck channel pins one scheduler thread and accumulates memory. A determined attacker can exhaust available CPU, causing service degradation or total unresponsiveness of the host (if CPU is fully consumed). The CVSS vector (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L) reflects this: Low availability impact because other processes on the node remain preemptible; Unchanged scope because the BEAM VM itself does not crash. However, the availability subscore of Low understates real-world impact when multiple channels are opened — the combined CPU exhaustion can approach total host denial.
Confidentiality and integrity: Not affected. The vulnerability is purely a liveness failure.
Detection Guidance
Sigma Rule
title: CVE-2026-54886 - Erlang OTP SFTP Infinite Loop Attempt
id: 8f6b974e-12b8-4d9c-9f5d-77d9f0a4b3d1
status: experimental
description: Detects SSH_MSG_CHANNEL_EXTENDED_DATA packets sent to the SFTP subsystem which can trigger an infinite loop in Erlang OTP ssh_sftpd.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-54886
author: ValtersIT Threat Intel
date: 2026/06/01
logsource:
category: network_connection
product: ssh
detection:
selection_ssh_sftp:
ssh.channel.request|contains: 'sftp'
selection_extended_data:
ssh.message_type: 'SSH_MSG_CHANNEL_EXTENDED_DATA'
ssh.recipient_channel_type: 'session'
condition: selection_ssh_sftp and selection_extended_data
timeframe: 60s
level: medium
falsepositives:
- Non-conforming SSH clients sending stderr on channel 0
- Legitimate use of extended data on channel 0 by custom clients (rare)
fields:
- src.ip
- dst.ip
- ssh.username
tags:
- attack.t1190
- cve.2026-54886
- cwe.400
YARA Rule
rule CVE_2026_54886_Erlang_SFTP_ExtendedData
{
meta:
author = "ValtersIT Threat Intel"
description = "Detects SSH_MSG_CHANNEL_EXTENDED_DATA packets targeting the SFTP subsystem of Erlang OTP servers"
cve = "CVE-2026-54886"
cwe = "CWE-400"
severity = "medium"
strings:
$ssh_ext_data = { 5e } // SSH_MSG_CHANNEL_EXTENDED_DATA = 94 (0x5e)
$sftp_subsys = "sftp" ascii
condition:
$ssh_ext_data and $sftp_subsys
}
Suricata IDS Rule
alert ip any any -> any 22 (msg:"ET EXPLOIT Erlang OTP SFTP Infinite Loop Attempt (CVE-2026-54886)"; flow:to_server,established; content:"|5e|"; depth:1; content:"sftp"; within:100; metadata:policy balanced-ips drop, service ssh; reference:url,https://nvd.nist.gov/vuln/detail/CVE-2026-54886; classtype:attempted-dos; sid:2026054886; rev:1;)
Note: This rule assumes SSH connection tracking with protocol inspection. Adjust port and content offsets to match your SSH logging/protocol parser. For deeper packet inspection, use ssh protocol keyword in Suricata 6+:
alert ssh any any -> any 22 (msg:"ET EXPLOIT SSH Extended Data to SFTP Channel (CVE-2026-54886)"; ssh:extended_data; content:"sftp"; nocase; flow:established,to_server; reference:url,https://nvd.nist.gov/vuln/detail/CVE-2026-54886; classtype:attempted-dos; sid:2026054887; rev:1;)
Elastic Detection
sequence by source.ip, destination.ip with maxspan=60s
[ network where event.category == "network" and network.protocol == "ssh"
and process.name == "sshd" and network.direction == "ingress"
and ssh.method == "sftp" ]
[ network where event.category == "network" and network.protocol == "ssh"
and ssh.channel_data_type_code == "extended"
and ssh.channel_number == 0
and network.direction == "ingress" ]
This EQL rule assumes SSH protocol fields are parsed into ECS-like fields (ssh.method, ssh.channel_data_type_code, ssh.channel_number). Adjust field names based on your SSH integration (e.g., Zeek, Suricata, Packetbeat).
Splunk SPL Query
index=network sourcetype=suricata OR sourcetype=zeek_conn
| search proto="ssh" OR app_proto="ssh"
| rex field=args "sftp"
| where match(_raw, "SSH_MSG_CHANNEL_EXTENDED_DATA")
| stats count by src_ip, dest_ip, ssh_user, dest_port
| where count > 5
| sort - count
| table _time, src_ip, dest_ip, ssh_user, dest_port, count
Adjust sourcetype and field names to match your SSH log ingestion. The threshold count > 5 filters legitimate rare extended-data usage from repeated malicious triggers.
Wazuh OSSEC Rule
<group name="ssh,sftp,cve-2026-54886,">
<rule id="767678" level="10">
<if_sid>1005480</if_sid>
<match>SSH_MSG_CHANNEL_EXTENDED_DATA</match>
<description>Erlang OTP SFTP: SSH_MSG_CHANNEL_EXTENDED_DATA received on SFTP channel - potential CVE-2026-54886 infinite loop attempt</description>
<group>attack.t1190,cwe.400,</group>
<mitre>
<tactic id="TA0001" name="Initial Access"/>
<technique id="T1190" name="Exploit Public-Facing Application"/>
</mitre>
<info type="cve">CVE-2026-54886</info>
<frequency>5</frequency>
<timeframe>60</timeframe>
</rule>
<rule id="767679" level="12" frequency="5" timeframe="60">
<if_sid>1005481</if_sid>
<same_source_ip/>
<description>Repeated CVE-2026-54886 exploit attempts from same source IP - likely active attack</description>
<group>attack.t1190,cwe.400,</group>
</rule>
</group>
Mitigation & Patch Guidance
Immediate mitigations (no patch required):
- Limit channels per connection: Set the SSH daemon option
{max_channels, N}where N is a small finite value (e.g., 10). This limits how many stuck channel processes a single attacker can create per connection. - Limit concurrent sessions: Set
{max_sessions, M}in the daemon options to cap total simultaneous SSH connections, preventing mass exploitation across many connections. - Network ACLs: Restrict the SFTP port (typically 22) to trusted IP ranges only. Do not expose the SFTP service to untrusted networks.
- External process monitoring: Deploy a watchdog script that periodically checks for ssh_sftpd processes with abnormally high reduction counts (using
erlang:statistics(reductions)or process_info) and growing message queues (process_info(Pid, message_queue_len)). Kill and restart stuck processes automatically.
Patch/upgrade steps:
- Check your Erlang/OTP version:
erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' - Subscribe to the Erlang/OTP security advisories and the OTP GitHub repository for the official fix.
- Once a patched version is released, upgrade to the latest stable OTP release. If a backport is available from your Linux distribution (Debian/Ubuntu/RHEL), apply it immediately.
- After upgrade, verify the fix by regression-testing SFTP connectivity.
Long-term hardening:
- Enable fail2ban or equivalent to auto-ban IPs that exhibit abnormal SSH traffic patterns (rapid channel opens, malformed packets).
- Use SSH key-based authentication exclusively and disable password authentication, reducing the likelihood of credential compromise that enables this attack.
- Deploy an intrusion prevention system (IPS) inline to block repeat offenders detected by the Suricata rules above.
- Segregate the SFTP service — if possible, run the Erlang OTP SSH daemon on a dedicated host or container isolated from critical application services.
- Contribute to the OSS-Fuzz effort for Erlang/OTP to encourage protocol fuzzing that could expose similar flaws in other protocol handlers.
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-54886
- OSV Advisory (patch claim source): https://osv.dev/vulnerability/CVE-2026-54886
- Erlang/OTP Official Site (security announcements): https://www.erlang.org/security
- Erlang/OTP GitHub Repository (SSH module): https://github.com/erlang/otp/tree/master/lib/ssh
- RFC 4254 - SSH Connection Protocol (channel/extended data spec): https://datatracker.ietf.org/doc/html/rfc4254
Threat actor activity: No known threat actor campaigns or exploit-in-the-wild evidence exist for this CVE as of the report date. The CVE is not listed in the CISA Known Exploited Vulnerabilities catalog. The EPSS score of 0.00331 (25.6th percentile) indicates low current exploitation likelihood, but the availability of a public PoC demonstration and the low complexity of trigger craft make this a viable target for opportunistic attacks against exposed Erlang OTP SFTP servers.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.