Feb 21, 2026·5 min read·5 visits
The OpenClaw ACP bridge didn't check input size before concatenation. A rogue local extension could send a massive payload, crashing the assistant via OOM or locking it in a stale state. Fixed in v2026.2.19.
OpenClaw, a personal AI assistant often integrated into IDEs via the Agent Control Protocol (ACP), suffered from a classic uncontrolled resource consumption vulnerability. By feeding the local `stdio` bridge a massive prompt payload, an attacker could force the Node.js process to allocate oversized strings, leading to memory exhaustion and a Denial of Service (DoS). The vulnerability also exposed a logic flaw where failed validation left the agent in a 'zombie' state, unable to process further requests.
We live in the age of the AI Assistant. They write our code, refactor our mess, and occasionally hallucinate libraries that don't exist. OpenClaw is one of these helpful digital butlers, designed to integrate deeply with your development environment. To do this, it uses something called the Agent Control Protocol (ACP) bridge.
Think of the ACP bridge as a pipe connecting your IDE (like VS Code or IntelliJ) to the OpenClaw brain. It usually runs over standard input/output (stdio), listening for JSON messages that tell the AI what to do. "Here is my code," the IDE says. "Fix it," the user commands.
But here is the problem with bridges: if you don't put up a weight limit sign, someone is going to try to drive a freight train across it. In OpenClaw's case, the developers built a bridge that would happily accept a prompt of infinite size, try to memorize it all at once, and inevitably collapse under the weight of its own hubris.
The vulnerability lies in how OpenClaw processed incoming prompts in src/acp/event-mapper.ts. The system expects a PromptRequest containing an array of content blocks. The function extractTextFromPrompt was tasked with taking these blocks and stitching them together into a single string for the Large Language Model (LLM) to chew on.
In the vulnerable versions (2026.2.17 and below), the code looked something like this:
join('\n') them all together.Notice what's missing? Restraint.
There was no check to see if the resulting string would fit in memory. There was no check to see if the user (or a rogue plugin) was sending 4GB of the letter 'A'. The code simply assumed that everyone plays nice. In the world of security, assuming benevolence is the first step toward a CVE ID.
Furthermore, there was a secondary logic bug in src/acp/translator.ts. The system would mark the session as "Active" before it finished validating the message. If the message eventually crashed the validator or failed a late check, the session remained stuck in an "Active" state—a zombie process refusing to die or work.
Let's look at the fix. The developers realized they needed to put the sophisticated "stop eating when you are full" logic into the code. They introduced a MAX_PROMPT_BYTES constant set to 2 MiB.
Here is the essence of the patch in extractTextFromPrompt. Note the manual byte counting:
// The Fix: Iterate and validate
let totalBytes = 0;
const parts: string[] = [];
for (const block of prompt) {
const blockBytes = Buffer.byteLength(block.text, "utf-8");
// Check if adding this block explodes the limit
if (totalBytes + blockBytes > maxBytes) {
throw new Error(`Prompt exceeds maximum allowed size...`);
}
totalBytes += blockBytes;
parts.push(block.text);
}> [!NOTE]
> Funny story: The first attempt at patching this actually missed something. They counted the bytes of the text blocks but forgot that join('\n') adds a newline character between them! A classic off-by-one error. They had to push a second commit just to count the newline bytes.
They also reordered the state management in translator.ts. Now, validation happens before the session is marked as active. It's a simple change—moving a line of code up—but it prevents the agent from getting stuck in a stale state if the input is bad.
Exploiting this is trivially annoying. Since the vector is local stdio, you usually need to be running a malicious extension or have a compromised process on the machine. But if you do, you can silence the AI assistant permanently for that session.
The Attack Chain:
stdio stream.prompt array containing 10,000 blocks, each containing a 10KB string of garbage data.join operation.If you hit the memory limit, the process crashes (OOM). If you stay just under the limit but make it huge, the Garbage Collector (GC) goes into panic mode, pausing the application and making the interface unresponsive. It's a Denial of Service (DoS) that doesn't require a network connection, just a heavy hand on the keyboard.
The remediation is straightforward: Update OpenClaw to version 2026.2.19 or later.
The patch introduces hard limits (2MB per prompt) which, quite frankly, should be enough for anyone. If your prompt is larger than 2MB, you aren't asking an AI for help; you're trying to paste the entire Linux kernel into a chat window. Stop it.
For developers integrating with OpenClaw: ensure your ACP client handles error messages gracefully. When the bridge rejects a payload for being too fat, it now throws a specific error. Catch it, and tell the user to summarize their code before sending it.
CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenClaw OpenClaw | <= 2026.2.17 | 2026.2.19 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Local (AV:L) |
| CVSS 4.0 | 4.8 (Medium) |
| Impact | Denial of Service (DoS) |
| Component | ACP Bridge (stdio) |
| Exploit Status | PoC Available |
The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.