Table of Contents
- Module 1: The Erlang/OTP SSH Remote Code Execution Vulnerability
- Erlang and OTP Background
- Vulnerability Overview
- Root Cause: Pre-Authentication Protocol Parsing Flaw
- Why Pre-Authentication Access Matters
- Real-World Exposure and Affected Environments
- Lateral Movement and Pivot Risk
- Public Proof-of-Concept Availability
- Hands-On Exploitation Walkthrough
- CVSS Severity Breakdown
- Affected Versions and Patch Availability
- Immediate Remediation Steps
- Detection and Monitoring Guidance
- Broader Lessons: Runtime as Attack Surface
- Summary
Module 1: The Erlang/OTP SSH Remote Code Execution Vulnerability
Erlang and OTP Background
Erlang is a functional, dynamically typed programming language created at Ericsson in the late 1980s. It was designed from the outset to build highly available telecom switches, and its runtime model reflects that goal: lightweight processes, message passing, and “let it crash” fault isolation.
OTP (Open Telecom Platform) originally referred to a specific product built on top of Erlang, but the name is now used far more broadly. Today “OTP” encompasses the entire Erlang ecosystem: the language itself, plus a standard library and a set of design principles for building fault-tolerant systems. Under the OTP model, a crash in one component is isolated from the rest of the system and automatically restarted by a supervising process, rather than bringing down the whole application.
Because of this heritage, Erlang/OTP is rarely something engineering teams think about day-to-day, yet it quietly powers a significant amount of production infrastructure — often underneath application code rather than as a visible dependency.
flowchart TB
A[Erlang Language] -->|"functional, dynamically typed<br/>created at Ericsson, late 1980s"| B[OTP - Open Telecom Platform]
B --> C[Standard Library]
B --> D[Design Principles]
D --> E["Fault Isolation<br/>(crash in one component isolated)"]
D --> F["Automatic Restart<br/>('let it crash' supervision)"]
B --> G[Built-in SSH Daemon]
G -->|often bundled/enabled by default| H[Container Images / Platform Runtimes]
Vulnerability Overview
CVE-2025-32433 is a recently disclosed, critical remote code execution vulnerability affecting the SSH daemon that ships as part of Erlang/OTP. It carries a maximum CVSS score of 10.0, reflecting both the ease of exploitation and the severity of impact: an unauthenticated attacker with network access to the SSH port can achieve arbitrary code execution.
This is not a misconfiguration or an application-logic flaw. It lives in the SSH server implementation bundled with OTP itself — meaning any system that enables OTP’s SSH daemon is potentially affected, regardless of what application logic sits on top of it.
Root Cause: Pre-Authentication Protocol Parsing Flaw
The flaw occurs during the SSH handshake phase, specifically before authentication takes place. An attacker can send specially crafted SSH protocol messages that exploit how the server processes certain message fields.
Those fields are expected to follow a specific format, but the server does not validate them early enough in the handshake process. This allows unsafe memory operations to occur while processing attacker-controlled, untrusted input. In short, it is a parser trust issue: untrusted input is parsed too eagerly, before the server has confirmed the connecting client has any legitimate standing at all.
When an attacker structures that input in the right way, it triggers memory corruption — and from there, the door is open to remote code execution.
sequenceDiagram
participant Attacker
participant SSHDaemon as OTP SSH Daemon
participant Memory as Process Memory
Attacker->>SSHDaemon: Initiate SSH connection (pre-auth)
SSHDaemon->>SSHDaemon: Begin handshake / key exchange
Attacker->>SSHDaemon: Send crafted SSH message with malformed field
Note over SSHDaemon: Field format not validated<br/>before processing
SSHDaemon->>Memory: Unsafe memory operation on untrusted input
Memory-->>SSHDaemon: Memory corruption
SSHDaemon-->>Attacker: Arbitrary code execution achieved
Why Pre-Authentication Access Matters
Because the flaw is triggered before authentication, no valid credentials are required to exploit it. An attacker only needs network access to the exposed SSH port and a correctly structured payload — no privilege, session, or prior access is needed.
This makes the vulnerability reachable from anywhere the SSH daemon is exposed. In distributed Erlang systems, that daemon is frequently not protected by strict access controls, since it may be intended only for internal orchestration, clustering, or debugging rather than public exposure — yet it can still end up reachable.
This is a stark example of the need for rigorous input validation at protocol boundaries, especially in code paths that execute before any trust has been established with the remote party.
Real-World Exposure and Affected Environments
Because the Erlang/OTP runtime is engineered for “five nines” (99.999%) availability, it is commonly deployed precisely in environments where downtime is least acceptable. That includes:
- Telecom switches (Erlang’s original design target)
- Banking and e-commerce back ends
- Computer telephony gateways
- Real-time messaging services
Any system running OTP with its built-in SSH daemon enabled is in scope. This includes Erlang-powered XMPP servers such as ejabberd and MongooseIM, along with several distributed Elixir platforms (Elixir runs on the same BEAM/OTP runtime).
A key risk factor is that developers may not even realize they are running OTP’s SSH daemon. It can be bundled inside container images or deployed as part of a larger platform image, enabled by default for remote orchestration or debugging purposes, and never explicitly reviewed or locked down. In such cases, the system can end up exposed publicly without anyone realizing a vulnerable daemon is running.
mindmap
root((Erlang/OTP<br/>Exposure Surfaces))
Telecom
Switches
Signaling infrastructure
Financial / Retail
Banking back ends
E-commerce back ends
Real-time Communication
Computer telephony gateways
Messaging services
ejabberd (XMPP)
MongooseIM (XMPP)
Distributed Platforms
Elixir applications on BEAM/OTP
Hidden Exposure
Bundled in container images
Enabled by default for orchestration/debugging
Never explicitly reviewed
Lateral Movement and Pivot Risk
Exposure risk is not limited to systems reachable from the open internet. Even when the SSH port is not internet-facing, lateral movement inside an already-compromised network can take advantage of this vulnerability.
Once an attacker is inside a network, discovering exposed OTP SSH endpoints becomes an easy way to escalate privileges or move across systems — turning an internal, seemingly low-risk service into a pivot point for broader compromise.
flowchart LR
A[Attacker gains initial<br/>network foothold] --> B{Internal network<br/>scan}
B --> C[Discover OTP SSH<br/>endpoint on internal host]
C --> D[Exploit CVE-2025-32433<br/>pre-auth RCE]
D --> E[Code execution on<br/>internal Erlang/OTP host]
E --> F[Privilege escalation /<br/>lateral movement]
F --> G[Broader network compromise]
Public Proof-of-Concept Availability
A public proof-of-concept for this vulnerability has been published by security research firm Horizon3.ai, and it has been described as surprisingly easy to use. Public availability of a working exploit substantially raises the urgency of remediation, since capable exploitation no longer requires deep internal knowledge of the SSH protocol or OTP internals — a working script is enough.
Hands-On Exploitation Walkthrough
The following walkthrough illustrates the exploitation flow using a lab environment: a Docker container running an OTP SSH service is reachable at 172.18.0.2 on port 2222.
1. Service fingerprinting with Nmap
An Nmap service scan against the target reveals the SSH banner:
PORT STATE SERVICE VERSION
2222/tcp open ssh Erlang/OTP SSH (protocol 2.0)
| ssh-hostkey:
|_ SSH-2.0-Erlang/5.1.4.7
The Erlang/5.1.4.7 string identifies the SSH application version shipped inside OTP. In practice, any system advertising Erlang SSH version 5.x below 5.2.0 is vulnerable to CVE-2025-32433 — this target is a match.
2. Confirming the SSH service requires credentials
ssh root@172.18.0.2 -p 2222
# Prompted for a password — no interactive command execution
# should be possible without providing valid credentials.
At this stage, the service behaves as expected: connecting interactively still requires a password, and no commands can be executed without one.
3. Running the CVE-2025-32433 proof-of-concept
A public proof-of-concept script for CVE-2025-32433 was released shortly after the CVE was disclosed. It accepts the target address, the port the SSH daemon is listening on, and the command to execute on the target — all without needing any credentials:
python3 cve-2025-32433.py --target 172.18.0.2 --port 2222 \
--command "echo pwned > /lab.txt"
When testing against live or production systems, a relatively benign command should always be used first, to minimize the risk of unintended service disruption. In this walkthrough, the payload simply creates a file named lab.txt in the target’s root directory containing the value pwned.
4. Verifying code execution on the victim machine
Switching to the victim machine and inspecting the root directory confirms the exploit succeeded:
ls -la /
# lab.txt appears with a timestamp showing it was just created,
# owned by root
cat /lab.txt
# pwned
The file was created with root permissions, confirming unauthenticated, arbitrary command execution on the target — with no valid SSH credentials ever supplied. Beyond this proof-of-concept, the same technique can be extended to establish a full reverse shell to the victim machine, at which point defenders can practice the corresponding blue-team side of the exercise: hunting for indicators of compromise from the resulting activity.
sequenceDiagram
participant Tester as Security Tester (Kali)
participant Target as OTP SSH Daemon (172.18.0.2:2222)
participant FS as Target Filesystem
Tester->>Target: nmap -sV -p 2222 172.18.0.2
Target-->>Tester: Banner: SSH-2.0-Erlang/5.1.4.7 (vulnerable < 5.2.0)
Tester->>Target: ssh root@172.18.0.2 -p 2222
Target-->>Tester: Password prompt (no valid creds available)
Tester->>Target: Run CVE-2025-32433 PoC (target, port, command)
Target->>FS: Write /lab.txt containing "pwned" as root
Tester->>Target: Verify: cat /lab.txt
Target-->>Tester: "pwned" — confirmed unauthenticated RCE
CVSS Severity Breakdown
CVE-2025-32433 is rated at the maximum possible CVSS base score of 10.0 (Critical). The following table breaks down the standard CVSS v3.1 vector components consistent with a maximum-severity, unauthenticated, network-exploitable memory-corruption vulnerability of this kind, provided here as supplementary reference alongside the narrative discussion above:
| Metric | Value | Explanation |
|---|---|---|
| Attack Vector (AV) | Network (N) | Exploitable remotely over the network via the exposed SSH port |
| Attack Complexity (AC) | Low (L) | No special conditions beyond network reachability and a crafted payload |
| Privileges Required (PR) | None (N) | Triggered pre-authentication; no valid credentials needed |
| User Interaction (UI) | None (N) | Fully automated; no victim action required |
| Scope (S) | Changed (C) | Compromise of the SSH daemon leads to full host/process compromise beyond the vulnerable component |
| Confidentiality (C) | High (H) | Arbitrary code execution exposes all data accessible to the process |
| Integrity (I) | High (H) | Attacker can modify files/data with the daemon’s privileges |
| Availability (A) | High (H) | Attacker can disrupt or take down the service/host entirely |
| Base Score | 10.0 | Critical |
Affected Versions and Patch Availability
| OTP Release Line | Vulnerable Versions | Patched Version |
|---|---|---|
| OTP 27.x | Earlier than 27.3.3 | 27.3.3 |
| OTP 26.x | Earlier than 26.2.5.11 | 26.2.5.11 |
| OTP 25.x | Earlier than 25.3.2.20 | 25.3.2.20 |
Any deployment running an OTP version below the applicable patched release for its line is potentially vulnerable, assuming the built-in SSH daemon is enabled. Systems on a version at or above the patched release for their line are not affected by this specific flaw.
Immediate Remediation Steps
flowchart TD
A[Identify OTP version in use] --> B{Version below patched<br/>threshold for its release line?}
B -->|No| C[Not affected by CVE-2025-32433]
B -->|Yes| D{Is the OTP SSH daemon<br/>enabled?}
D -->|No| E[Lower immediate risk — still track<br/>version for future exposure]
D -->|Yes| F{Can the OTP version be<br/>patched now?}
F -->|Yes| G[Upgrade to 27.3.3 / 26.2.5.11 /<br/>25.3.2.20 or later]
F -->|No, not yet| H{Is the SSH daemon<br/>strictly required?}
H -->|No| I[Disable the OTP SSH daemon]
H -->|Yes, cannot disable| J[Restrict access at the firewall:<br/>block inbound connections to the<br/>SSH daemon's port from untrusted networks]
G --> K[Audit systems using Erlang indirectly,<br/>especially containers]
I --> K
J --> K
K --> L{Container/platform image<br/>bundles a vulnerable OTP runtime?}
L -->|Yes| M[Rebuild the image on a patched<br/>OTP base — an application-level<br/>patch alone will not help]
L -->|No| N[Confirm remediation complete]
The recommended remediation sequence is as follows:
- Identify affected systems. Determine whether any system is running an OTP version earlier than 27.3.3, 26.2.5.11, or 25.3.2.20 (whichever release line applies).
- Patch where possible. Upgrade to the patched release for the applicable OTP line as the primary fix.
- Disable the daemon if patching isn’t immediately possible. If the SSH daemon isn’t strictly needed, disable it entirely until the underlying OTP version can be upgraded.
- Restrict network access as a stopgap. Where the daemon can’t be disabled, restrict access at the firewall level — block inbound connections to the relevant port (commonly port 22, or whatever port the daemon is configured to listen on) from untrusted networks.
- Audit indirect Erlang usage, especially containers. Systems that use Erlang-powered components indirectly — for example, an Erlang-powered XMPP service — need their base container image rebuilt on a patched OTP release. An application-level patch will not help if the vulnerable SSH daemon is bundled inside the runtime underneath the application.
Detection and Monitoring Guidance
Even where remediation isn’t yet complete, log review can help identify active probing or exploitation attempts. Strange or malformed SSH handshake attempts — particularly connections that are dropped during early negotiation, before authentication would normally occur — are worth investigating further.
This won’t catch every attempt, but it can help identify scanning or exploitation activity in progress. Consider building automated monitoring rules that generate alerts for connections matching this pattern (malformed pre-auth handshake termination against the OTP SSH daemon), so that suspicious activity surfaces without requiring manual log review.
flowchart LR
A[Collect SSH daemon<br/>connection logs] --> B{Handshake dropped<br/>during early negotiation<br/>before authentication?}
B -->|Yes| C[Flag as suspicious /<br/>possible probing or exploitation]
B -->|No| D[Normal connection lifecycle]
C --> E[Automate alerting for this<br/>connection pattern]
E --> F[Investigate source IP,<br/>frequency, targeting pattern]
Broader Lessons: Runtime as Attack Surface
This vulnerability reinforces how much implicit trust is placed in infrastructure that engineering teams did not write and often do not actively monitor. Erlang’s runtime is robust and mature, but even well-established, long-lived systems can contain blind spots in how they handle untrusted input.
The fact that this flaw lives in the protocol layer of the SSH server — a component generally assumed to be hardened — is a wake-up call: language and platform runtimes must be treated as part of the application’s attack surface, not as an invisible foundation beneath it. If a system relies on something like OTP for internal messaging or coordination, that runtime is not a black box. Teams need to track its version, read its change logs, and know exactly what services it exposes.
Maturity of a runtime does not eliminate risk; it simply changes how that risk appears. Once a component is in production, “I didn’t know it was running” is not an acceptable posture — dependency visibility, including transitive and bundled runtime components, needs to be treated as an ongoing priority.
Summary
CVE-2025-32433 is a maximum-severity (CVSS 10.0), unauthenticated, pre-authentication remote code execution vulnerability in the SSH daemon bundled with Erlang/OTP. The flaw stems from insufficient validation of SSH protocol message fields during the handshake phase, before any client trust has been established, leading to unsafe memory operations, memory corruption, and ultimately arbitrary code execution — reachable by anyone who can send network traffic to the exposed SSH port, with no credentials required.
Because Erlang/OTP is engineered for extremely high availability, it is deeply embedded in telecom, financial, e-commerce, and real-time messaging infrastructure, as well as XMPP platforms like ejabberd and MongooseIM and distributed Elixir systems. It is frequently bundled inside container and platform images with its SSH daemon enabled by default, meaning organizations can be exposed without realizing it. A public proof-of-concept exists and has been demonstrated to be straightforward to use, and even internally-facing deployments carry meaningful lateral-movement risk.
Mitigation Checklist
- Inventory all systems and container images that run Erlang/OTP, including indirect/transitive usage (e.g., Erlang-powered XMPP or messaging components).
- Determine the OTP version in use on each system and compare against the patched thresholds (27.3.3, 26.2.5.11, 25.3.2.20).
- Patch to the appropriate fixed OTP release wherever possible — this is the primary remediation.
- Where immediate patching isn’t possible, disable the OTP SSH daemon if it isn’t strictly required.
- Where the daemon can’t be disabled, restrict inbound access to its port at the firewall/network layer.
- Rebuild container/platform images on a patched OTP base rather than relying on application-level patches alone.
- Review SSH daemon logs for malformed or early-dropped handshake attempts, and automate alerting for this pattern.
- Treat language/platform runtimes (not just application code) as part of the tracked attack surface — monitor versions and change logs going forward.
- Assume exposure until proven otherwise: if unsure whether Erlang/OTP with an exposed SSH daemon is running anywhere in the environment, investigate proactively rather than assuming it isn’t.
Search Terms
remote · execution · erlang · know · vulnerability · briefings · networking · systems · security · affected · availability · otp · pre-authentication