Erlang/OTP SSH Pre-Auth RCE
- Product
- Erlang/OTP OTP ssh application
- CVE
- CVE-2025-32433
- Disclosed
- 2025-04-16
- CVSS
- 10
- Auth
- pre-auth
- CISA KEV
- yes
- Affected
- Erlang/OTP before OTP-27.3.3, OTP-26.2.5.11 and OTP-25.3.2.20 when the built-in SSH server is used (many Cisco, Ericsson and IoT products embed it).
- Fixed
- OTP-27.3.3, OTP-26.2.5.11, OTP-25.3.2.20.
Summary
The Erlang/OTP SSH server would process SSH connection-protocol messages, including 'exec' channel requests, before the client had authenticated. Anyone who can reach the port can run arbitrary commands, and a PoC was public within a day.
Root cause
The ssh_connection state machine did not reject connection-protocol messages (message numbers >= 80, e.g. SSH_MSG_CHANNEL_OPEN and SSH_MSG_CHANNEL_REQUEST 'exec') received before user authentication had completed. The exec request is evaluated as Erlang code by the daemon, typically running as root.
Impact
Unauthenticated remote code execution with the privileges of the SSH daemon (often root) on any system embedding the Erlang SSH server.
Public PoC
# No key exchange is completed and no userauth is sent:
# banner -> KEXINIT -> CHANNEL_OPEN -> CHANNEL_REQUEST 'exec'
s.sendall(b"SSH-2.0-OpenSSH_8.9\r\n")
banner = s.recv(1024)
s.sendall(pad_packet(build_kexinit()))
s.sendall(pad_packet(build_channel_open())) # SSH_MSG_CHANNEL_OPEN 'session'
# 'exec' payload is Erlang code, evaluated pre-auth
chan_req = build_channel_request(
command='file:write_file("/lab.txt", <<"pwned">>).'
)
s.sendall(pad_packet(chan_req))Source: ProDefense (Platform Security) - CVE-2025-32433 PoC
Detection
Banner check for 'SSH-2.0-Erlang/x.y' on exposed ports; nuclei template CVE-2025-32433. IDS rules flag SSH_MSG_CHANNEL_OPEN/REQUEST before USERAUTH_SUCCESS.
Mitigation
Upgrade OTP; otherwise disable the SSH server or restrict access via firewall.