May 8, 2026·6 min read·7 visits
Unauthenticated remote attackers can crash Phoenix Framework nodes by sending an 8MB NDJSON payload consisting entirely of newline characters to the LongPoll endpoint, triggering memory exhaustion via eager string evaluation.
The Phoenix Framework contains a high-severity Denial of Service vulnerability in its LongPoll transport mechanism. The vulnerability is caused by unbounded memory allocation when processing Newline Delimited JSON (NDJSON) payloads. Unauthenticated attackers can trigger Out-Of-Memory conditions on the host BEAM node, terminating all active sessions by forcing the server to evaluate excessive newline characters.
The Phoenix Framework utilizes a LongPoll transport mechanism to allow clients to maintain stateful communication via sequential HTTP requests when WebSockets are unavailable. The target component for this vulnerability is Phoenix.Transports.LongPoll, which is responsible for parsing incoming client messages. These messages are frequently formatted as Newline Delimited JSON (NDJSON), allowing multiple JSON objects to be transmitted in a single HTTP request body.
The vulnerability is classified as CWE-770 (Allocation of Resources Without Limits or Throttling). The flaw resides in the publish/4 function, which processes the NDJSON payloads. The lack of resource limits on the server's parsing logic enables unauthenticated remote attackers to trigger excessive memory consumption on the host system.
Successful exploitation results in a complete Denial of Service (DoS) of the affected Elixir node. The Erlang virtual machine (BEAM) runs out of memory and crashes, terminating all active websocket and longpoll sessions hosted on that node. This interrupts service availability for all users connected to the affected instance.
The vulnerability stems from the eager memory allocation strategy used in the vulnerable codebase. When the server receives an NDJSON payload, it parses the HTTP body by splitting the entire string on newline characters using the String.split/2 function. This function eagerly materializes a complete list of all parsed tokens in memory before passing them to the next operation.
This behavior creates a significant memory amplification effect within the BEAM virtual machine. An attacker sending an 8 megabyte HTTP POST body consisting entirely of newline characters forces the server to generate approximately 8.4 million empty string segments. Each element in an Erlang list, known as a cons cell, requires 16 bytes on a 64-bit architecture.
Generating the initial list of 8.4 million segments requires roughly 134 megabytes of heap space. The code subsequently passes this list to Enum.map, which immediately allocates a second list of identical size, effectively doubling the memory pressure to over 268 megabytes per request. Concurrent requests compound this memory usage linearly until the BEAM node exhausts available system memory and the operating system terminates the process.
The vulnerable implementation of Phoenix.Transports.LongPoll.publish/4 processed NDJSON payloads using eager string operations. The code utilized String.split/2 and Enum.map/2, which forced the entire payload to be parsed and stored in memory before dispatching messages.
# VULNERABLE CODE
body
|> String.split(["\n", "\r\n"])
|> Enum.map(fn part ->
# Processes all parts in memory simultaneously
transport_dispatch(part)
end)The patch introduced in commit 1a67c61ff9ce0a7711662ac7354861917a7c80f7 replaces this eager evaluation with lazy stream processing. By changing String.split/2 to String.splitter/2, the application now returns an enumerable stream that processes each payload segment sequentially. The memory footprint remains constant regardless of the total payload size.
# PATCHED CODE
body
|> String.splitter(["\n", "\r\n"])
# |> Stream.take(@max_poll_batch_size) # Limit pending future enforcement
|> Enum.find(fn part ->
# Processes each part individually, preventing memory accumulation
transport_dispatch(part)
end)The Enum.map operation was replaced with Enum.find, which iterates through the stream and dispatches messages to the transport layer individually. This change eliminates the memory amplification vector associated with list materialization.
Exploitation requires the attacker to construct a valid session token, which the application provides without authentication. The attacker issues an HTTP GET request to the LongPoll socket URL (e.g., /live/longpoll), ensuring a valid Origin header is included. The server responds with a session token necessary for the subsequent payload delivery.
The attacker then sends an HTTP POST request to the LongPoll publish endpoint using the acquired token. The request must include the Content-Type: application/x-ndjson header to trigger the vulnerable parsing path. The attacker populates the request body with 8 megabytes of continuous newline characters, maximizing the default read_body limit.
Upon receiving the payload, the server attempts to parse the heavily padded NDJSON body. The eager string splitting creates millions of empty list segments, rapidly exhausting the heap limit of the processing process. The BEAM node subsequently crashes due to an Out-Of-Memory condition.
The primary consequence of this vulnerability is a complete loss of availability for the targeted service. Since Phoenix applications often manage stateful connections via WebSockets and LongPolls, a node crash terminates all established client connections simultaneously. The vulnerability maps directly to MITRE ATT&CK technique T1499 (Endpoint Denial of Service) and CAPEC-130 (Excessive Allocation).
The vulnerability is assigned a CVSS 4.0 base score of 8.7. The attack complexity is low, requires no special privileges, and involves no user interaction. The network-based attack vector allows external exploitation of exposed endpoints, making any unpatched, internet-facing Phoenix instance highly vulnerable to service disruption.
As of disclosure, the vulnerability has an EPSS score of 0.00045, placing it in the 13.78th percentile for exploit probability. Current threat intelligence indicates no active exploitation in the wild, and the vulnerability is absent from the CISA Known Exploited Vulnerabilities (KEV) catalog.
Administrators must upgrade their Phoenix Framework installations to version 1.7.22 or 1.8.6. These releases incorporate both the server-side lazy parsing patch and a client-side JavaScript update that chunks outbound LongPoll messages. Legitimate clients now enforce a constant limit of 100 messages per request batch via the MAX_LONGPOLL_BATCH_SIZE variable.
For applications where immediate patching is unfeasible, administrators can mitigate the vulnerability by disabling the LongPoll transport entirely. By setting longpoll: false in the Phoenix.Socket configuration, the application rejects LongPoll connections while preserving standard WebSocket functionality. This is particularly relevant for Phoenix LiveView applications which enable LongPoll by default.
Analysis of the patch reveals a secondary weakness related to message limits. While the out-of-memory condition is mitigated via lazy stream processing, the server implementation does not currently enforce a strict upper bound on the number of processed messages per request. The constant @max_poll_batch_size remains commented out in the Elixir source. An attacker sending many valid, small JSON objects could still induce high CPU utilization or congestion within the process mailbox.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Phoenix Framework Phoenix Framework | >= 1.7.0, < 1.7.22 | 1.7.22 |
Phoenix Framework Phoenix Framework | >= 1.8.0, < 1.8.6 | 1.8.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-770 |
| Attack Vector | Network |
| CVSS Base Score | 8.7 (High) |
| EPSS Score | 0.00045 |
| Impact | Denial of Service (Node Crash) |
| Exploit Status | Unexploited / PoC Only |
| CISA KEV | No |
The software allocates a reusable resource or group of resources on behalf of an actor without any limits or throttling on the number or size of the allocated resources.