Feb 18, 2026·5 min read·1 visit
OpenClaw < 2026.2.14 used a 'search and destroy' method to clean up stale agents, matching processes by name rather than ID. On shared servers, this meant it could kill unrelated processes belonging to other users if they shared similar command-line arguments. The fix implements strict Parent PID (PPID) verification.
A process safety vulnerability in the OpenClaw Personal AI Assistant allowed the CLI runner to terminate arbitrary processes on the local system. By relying on loose regex matching of command-line arguments without verifying process lineage (PPID) or ownership, OpenClaw could accidentally execute a Denial of Service (DoS) against other users on shared environments.
In the world of autonomous agents, managing subprocesses is like herding cats. You spawn them, they do work, and sometimes they refuse to leave. OpenClaw, a personal AI assistant, includes a 'cleanup' routine designed to sweep up these stale agent sessions—zombie processes left behind after a crash or a suspension.
Ideally, a cleanup routine is a scalpel: it identifies the specific resources it owns and carefully disposes of them. OpenClaw, unfortunately, brought a chainsaw. The affected component, specifically the CLI runner, was tasked with killing 'resume' processes and other agent executors. However, in its zeal to keep the system clean, it skipped a fundamental rule of operating systems: verify before you vilify.
The vulnerability isn't a complex memory corruption or a buffer overflow. It's a logic flaw in how the application identifies 'what to kill'. By trusting the output of a system-wide process list (ps) and filtering it with a regular expression, OpenClaw created a scenario where any process looking vaguely like an OpenClaw agent could be summarily executed via SIGKILL.
The core issue lies in src/agents/cli-runner/helpers.ts. When the CLI wanted to terminate a session, it didn't track the PIDs it spawned. Instead, it queried the operating system for all running processes and filtered the list for strings that looked like its own command-line arguments, such as codex exec resume {sessionId}.
This is CWE-283: Improper Control of a Resource Based on its Identifier. The code assumed that if a process was named codex exec, it must belong to the current OpenClaw instance. It completely ignored the Parent Process ID (PPID) and the user ID (UID) of the process owner.
On a single-user laptop, this is annoying but mostly harmless. On a multi-tenant server (like a shared development box or a university shell server), it's a disaster. If User A runs OpenClaw, and User B is running a script that happens to have codex in the argument list, User A's instance will effectively murder User B's process. Even worse, it used SIGKILL (-9) immediately, giving the victim process zero chance to save data or clean up its own resources.
Let's look at the logic that caused the problem. The vulnerability stems from a naive implementation of process discovery. The original code looked something like this (simplified for clarity):
// VULNERABLE CODE (Conceptual)
const cleanupStaleProcesses = (sessionId) => {
// 1. Get ALL processes
const output = execSync('ps aux').toString();
// 2. Filter by simple string matching
const lines = output.split('\n');
lines.forEach(line => {
if (line.includes(`codex exec resume ${sessionId}`)) {
const pid = extractPid(line);
// 3. The Kill Shot (No questions asked)
process.kill(pid, 'SIGKILL');
}
});
};There are three fatal errors here:
ps aux lists everyone's processes, not just the user's.SIGKILL.The fix, introduced in version 2026.2.14, changes the game entirely. It queries specifically for the PPID and verifies lineage:
// PATCHED CODE (Conceptual)
const cleanupChildren = () => {
const myPid = process.pid;
// 1. Get PID, PPID, and Args specifically
const output = execSync('ps -axww -o pid,ppid,args').toString();
parseOutput(output).forEach(proc => {
// 2. CRITICAL: Check if WE are the parent
if (proc.ppid === myPid && isAgentProcess(proc.args)) {
try {
// 3. Be polite first
process.kill(proc.pid, 'SIGTERM');
} catch (e) {
// Fallback only if necessary
process.kill(proc.pid, 'SIGKILL');
}
}
});
};Exploiting this on a shared system is trivially easy and can be done accidentally. Since the attacker acts as the 'cleaner', they don't need elevated privileges—they just need to run the vulnerable software.
Imagine a shared Linux server used by a dev team.
codex-data-migration.py and runs it with python codex-data-migration.py --resume-from-checkpoint.cleanup().Alice's OpenClaw runs ps and scans for codex and resume. It sees Bob's process:
root 1234 python codex-data-migration.py --resume-from-checkpoint
The regex matches codex and resume. OpenClaw assumes this is a stale agent executor belonging to Alice.
OpenClaw sends kill -9 1234. Bob's migration dies instantly. No database connections are closed. No state is saved. Bob yells across the office asking who touched the server.
The mitigation in version 2026.2.14 is robust because it shifts the source of truth from syntax (what the command looks like) to lineage (who started the command).
Key changes in the patch:
proc.ppid === process.pid. OpenClaw will only kill processes that it personally spawned. It can no longer reach across user boundaries or even unrelated processes owned by the same user.SIGTERM first allows the child process to handle the signal and clean up its own resources (close file handles, etc.) before being forced to exit.codex doesn't match codexx.> [!NOTE]
> Researcher Note: There is a theoretical TOCTOU (Time-of-Check Time-of-Use) race condition where a PID could be recycled between the ps check and the kill command. However, given the speed of execution and the specific PPID check, exploiting this window is highly impractical.
CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:N/VC:N/VI:N/VA:N/SC:N/SI:N/SA:H| Product | Affected Versions | Fixed Version |
|---|---|---|
openclaw OpenClaw | < 2026.2.14 | 2026.2.14 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-283 |
| Attack Vector | Local (AV:L) |
| CVSS v4.0 | 4.3 (Medium) |
| Privileges Required | Low (PR:L) |
| Impact | Denial of Service (DoS) |
| Exploit Maturity | Proof-of-Concept |
The product does not properly verify that a resource identifier, such as a Process ID (PID), is associated with a resource that is valid for the operation.