Mar 3, 2026·5 min read·1 visit
OpenClaw fails to sanitize newlines in generated systemd unit files. Attackers can inject malicious directives (e.g., `ExecStartPre`) via environment variables, achieving Local Command Execution (LCE) when the service starts.
A critical systemd unit injection vulnerability exists in OpenClaw versions prior to the February 20, 2026 patch. The vulnerability resides in the `buildSystemdUnit` function, which fails to properly sanitize newline characters in user-controlled inputs (such as environment variables) during the generation of systemd service files. This allows local attackers to inject arbitrary systemd directives, such as `ExecStartPre`, resulting in the execution of malicious commands with the privileges of the OpenClaw service (potentially root) upon service startup or restart.
The OpenClaw infrastructure tool contains a systemd unit injection vulnerability (CWE-93: Improper Neutralization of CRLF Sequences) in its daemon management component. OpenClaw dynamically generates systemd unit files (.service) to manage background processes. The vulnerability arises because the application constructs these files by concatenating user-supplied strings—specifically environment variable keys, values, and service descriptions—without adequate sanitization of control characters.
Systemd unit files rely on line-delimited syntax, where a newline character signifies the end of one directive and the start of another. By injecting carriage return (\r) or line feed (\n) characters into an input field, an attacker can prematurely terminate a legitimate configuration line and inject a new, arbitrary directive. This allows for the manipulation of the service's execution flow, environment, or security controls. The impact is critical: if an attacker successfully injects an ExecStart or ExecStartPre directive, they achieve arbitrary code execution whenever the service is managed by systemd.
The vulnerability stems from two distinct failures in src/daemon/systemd-unit.ts. First, the buildSystemdUnit function treats user inputs as trusted strings, directly interpolating them into the unit file template. There is no validation to ensure these inputs do not contain newline characters, which are semantically significant in the systemd configuration format.
Second, the helper function systemdEscapeArg, intended to sanitize arguments, utilized a flawed regular expression logic. The original implementation used the regex /[\\s"\\\\]/. In the specific JavaScript execution context used by OpenClaw, the double-escaped backslash sequence [\\s] was interpreted literally as a backslash followed by the letter 's', rather than the intended whitespace character class \s. Consequently, arguments containing spaces or tabs were not properly detected or escaped. This failure in the escaping logic, combined with the lack of CRLF neutralization, creates a robust vector for injection attacks where an attacker can bypass the intended structure of the service file.
The remediation addresses the improper sanitization by enforcing strict escaping of control characters and correcting the flawed regex. Below is an analysis of the vulnerable logic versus the patched implementation.
Vulnerable Code Logic (Conceptual): The original code likely concatenated the environment strings directly. Note the lack of newline filtering:
// src/daemon/systemd-unit.ts (Vulnerable)
function buildSystemdUnit(config) {
let unitContent = "[Service]\n";
// Input is interpolated directly. If envValue contains \n, it breaks the file structure.
unitContent += `Environment="${config.envKey}=${config.envValue}"\n`;
return unitContent;
}Patched Code Logic:
The fix, implemented in commit 61f646c41fb43cd87ed48f9125b4718a30d38e84, introduces proper escaping mechanisms. It likely validates that keys do not contain control characters and escapes values according to systemd syntax (using \x sequences or quoting) while correctly identifying whitespace.
// src/daemon/systemd-unit.ts (Fixed)
function systemdEscapeArg(arg: string) {
// Corrected regex to properly identify whitespace and special chars
// Prior regex `/[\\s"\\\\]/` was flawed; fixed version correctly targets whitespace
if (!/[\s"\\]/.test(arg)) return arg;
// Implementation of proper escaping logic
return "\"" + arg.replace(/(["\\])/g, "\\$1") + "\"";
}
// When building the unit, newlines are explicitly rejected or escaped> [!NOTE]
> The patch ensures that even if a user provides input like foo\nbar, it is treated as a literal string within a quoted value, preventing the parser from interpreting bar as a new directive.
Exploitation requires the attacker to influence the configuration or environment variables OpenClaw uses to generate the service file. This could occur via a malicious plugin, a compromised configuration file, or a low-privileged user interface that allows setting environment variables for the daemon.
Attack Scenario:
Environment directive in the generated unit file.INJECT with the value:
ok
ExecStartPre=/bin/bash -c 'echo pwned > /tmp/hacked'Environment=INJECT=ok
ExecStartPre=/bin/bash -c 'echo pwned > /tmp/hacked'Outcome:
Systemd parses Environment=INJECT=ok as a valid assignment. It then encounters ExecStartPre=... on a new line, treating it as a legitimate service instruction. When the service is next started or restarted (e.g., via systemctl start openclaw), systemd executes the injected command. Since systemd services often run with elevated privileges (root) or the specific user of the daemon, this results in Local Command Execution (LCE) with those privileges.
The impact of this vulnerability is rated High due to the potential for privilege escalation and persistence.
CVSS Vector Breakdown:
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
openclaw OpenClaw | < 2026.02.20 | 2026.02.20 (Commit 61f646c) |
| Attribute | Detail |
|---|---|
| CVSS v3.1 | 8.2 (High) |
| Attack Vector | Local (AV:L) |
| CWE ID | CWE-93 |
| CWE Name | Improper Neutralization of CRLF Sequences |
| Impact | Local Command Execution / Privilege Escalation |
| Patch Date | 2026-02-20 |
The software constructs a message or document using CRLF sequences but fails to neutralize the sequences, allowing attackers to inject arbitrary content.