Mar 3, 2026·6 min read·19 visits
OpenClaw versions before 2026.1.29 are vulnerable to arbitrary file reads. Attackers can create malicious symbolic links in an agent's workspace (e.g., naming a link 'avatar.png' that points to '/etc/passwd'). The system follows these links during avatar resolution, exposing sensitive host files.
A symbolic link traversal vulnerability exists in the OpenClaw AI assistant platform, specifically within the agent avatar resolution logic. This flaw allows attackers with write access to an agent's workspace to create symbolic links pointing to arbitrary files on the host filesystem. When the gateway attempts to serve or process the agent's avatar, it follows the symbolic link and discloses the target file's contents, bypassing workspace isolation boundaries. The vulnerability also includes a Time-of-Check Time-of-Use (TOCTOU) race condition.
The vulnerability affects the OpenClaw gateway, a component responsible for managing AI agent sessions and serving user interface assets. OpenClaw assigns a local workspace directory to each agent where it can store files, including identity assets like avatars. The flaw resides in how the gateway resolves and serves these avatar images.
Specifically, the resolveIdentityAvatarUrl function and the avatar-serving endpoints failed to properly validate the destination of symbolic links. While the application verified that the requested file path string was nominally within the workspace directory, it did not resolve symbolic links before reading the file content. This allowed the filesystem APIs to transparently follow links pointing outside the restricted workspace root.
This is a classic Link Following vulnerability (CWE-59) combined with Improper Limitation of a Pathname to a Restricted Directory (CWE-22). It permits an attacker who can influence workspace content to read any file the OpenClaw process has permission to access, compromising the confidentiality of the host system.
The root cause is twofold: reliance on path string validation instead of canonical path validation, and the presence of a Time-of-Check Time-of-Use (TOCTOU) race condition.
1. Inadequate Path Validation:
The original implementation used path.resolve to normalize the requested file path and checked if the resulting string started with the workspace root path. However, standard path resolution logic in Node.js does not expand symbolic links. If an attacker created a link at /workspace/avatar.png pointing to /etc/passwd, the path string /workspace/avatar.png would arguably pass the containment check. When fs.readFileSync was subsequently called, the operating system resolved the link and returned the contents of /etc/passwd.
2. TOCTOU Race Condition:
The code performed a check using fs.statSync to verify file properties (such as size) before calling fs.readFileSync. These are distinct system calls. In the window between stat and read, an attacker could swap a valid image file with a symbolic link. The initial check would validate the safe file, but the read operation would target the malicious link, bypassing security controls.
The remediation involved shifting from path-based operations to file descriptor (FD) operations to eliminate race conditions and enforcing canonical path checks.
Vulnerable Logic (Conceptual):
// src/gateway/session-utils.ts (Pre-patch)
const avatarPath = path.join(workspaceRoot, 'avatar.png');
if (isPathWithinRoot(avatarPath, workspaceRoot)) {
// VULNERABLE: fs.stat followed by fs.readFile creates a race condition
// and fs.readFile follows symlinks by default.
const stats = fs.statSync(avatarPath);
if (stats.size < MAX_SIZE) {
const data = fs.readFileSync(avatarPath); // Follows symlink!
return createDataUrl(data);
}
}Patched Logic:
The fix introduces strict identity verification. The code now opens the file first to obtain a file descriptor, then performs checks on that specific descriptor. It also compares the file's identity (inode and device ID) from lstat (link-aware) and fstat (descriptor-aware) to ensure no swapping occurred.
// src/gateway/session-utils.ts (Patched)
import * as fs from 'fs';
// 1. Resolve the canonical path of the root to prevent traversal via root parents
const realRoot = fs.realpathSync(workspaceRoot);
// 2. Open file with O_NOFOLLOW to fail if the immediate path component is a link
// (Note: Node.js fs.openSync flags depend on platform, but logic enforces no-follow semantics)
const fd = fs.openSync(avatarPath, 'r');
try {
// 3. Verify file identity to prevent TOCTOU
const linkStats = fs.lstatSync(avatarPath);
const fdStats = fs.fstatSync(fd);
if (linkStats.ino !== fdStats.ino || linkStats.dev !== fdStats.dev) {
throw new Error('File identity mismatch (possible symlink swap)');
}
// 4. Verify canonical path containment
const realPath = fs.realpathSync(avatarPath);
if (!realPath.startsWith(realRoot)) {
throw new Error('Path traversal detected');
}
// 5. Safe read using the verified file descriptor
const buffer = Buffer.alloc(fdStats.size);
fs.readSync(fd, buffer, 0, fdStats.size, 0);
} finally {
fs.closeSync(fd);
}To exploit this vulnerability, an attacker must have the ability to create files within the agent's workspace. This is often achievable if the agent exposes file upload capabilities or if the attacker has compromised a lower-privileged component with workspace access.
Step 1: Workspace Access
The attacker gains access to the agent's workspace directory, typically located at ~/.openclaw/workspace/.
Step 2: Malicious Symlink Creation
The attacker deletes the legitimate avatar.png and replaces it with a symbolic link pointing to a sensitive system file.
# Target the system password file
ln -sf /etc/passwd ~/.openclaw/workspace/avatar.pngStep 3: Trigger Resolution
The attacker triggers an avatar refresh or navigates to the control interface where the avatar is displayed. The OpenClaw gateway receives a request to /avatar/{agentId} or calls resolveIdentityAvatarUrl internally.
Step 4: Data Exfiltration
The server reads the target of the symlink (/etc/passwd). If the endpoint returns a data URL, the attacker receives a Base64 string:
data:image/png;base64,cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaAo...
Decoding this string reveals the content of the compromised file.
This vulnerability poses a confidentiality risk. While it does not directly allow arbitrary code execution, the ability to read arbitrary files can lead to complete system compromise depending on the files accessible to the OpenClaw process.
Critical Assets at Risk:
config.json or .env files could expose API keys, database credentials, or third-party service tokens./etc/passwd (user enumeration) or SSH keys (if permissions allow) could facilitate lateral movement.The severity is mitigated by file permissions; the attacker can only read files that the user running the OpenClaw process can read. If OpenClaw runs as root (against best practices), the impact is critical. If it runs as a dedicated low-privilege user, the impact is limited to that user's access scope.
The vulnerability is fixed in OpenClaw version 2026.1.29. All users should upgrade immediately.
Primary Fix:
Upgrade to the patched version which implements fs.openSync with file descriptor checks and strict canonical path verification (fs.realpathSync) to prevent symlink traversal.
Defensive Configuration:
# Example audit command
find /path/to/openclaw/workspaces -type l -lsCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenClaw OpenClaw | < 2026.1.29 | 2026.1.29 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-59 (Link Following) |
| Attack Vector | Local / Remote (via Workspace) |
| CVSS Score | 6.6 (Medium) |
| Impact | Confidentiality Loss (Arbitrary File Read) |
| Exploit Status | PoC Available |
| Platform | Node.js / TypeScript |
Improper Link Resolution Before File Access ('Link Following')
A state persistence vulnerability exists in Tornado's CurlAsyncHTTPClient component where pooled pycurl.Curl handles are reused across asynchronous requests without a complete state reset. Consequently, sensitive per-request configurations, such as client TLS certificates or proxy basic authentication credentials, persist on the shared handle. This behavior leads to subsequent requests leaking these credentials to unauthorized remote servers.
CVE-2026-48748 is a denial-of-service vulnerability in Netty's HTTP/3 codec (netty-codec-http3) occurring when QPACK dynamic tables are enabled but the blocked streams limit is not explicitly configured. A bug in limit checking and a memory leak in stream tracking allow unauthenticated remote attackers to exhaust the JVM heap memory and crash the server.
CVE-2026-50009 is a cryptographic design vulnerability in the Netty network application framework. Prior to version 4.2.15.Final, the framework's QUIC protocol implementation fails to cryptographically segregate the generated Connection IDs and the associated Stateless Reset Tokens. An on-path network attacker who sniffs traffic during a Connection ID rotation can extract secret token material from cleartext headers, enabling them to inject spoofed reset packets and terminate active connections.
A critical hostname verification bypass vulnerability exists in the Netty network application framework when configured as a TLS client. When a developer registers a custom plain X509TrustManager, Netty wraps it inside an X509TrustManagerWrapper to adapt it to the X509ExtendedTrustManager API. However, this wrapper discards the SSLEngine context, bypassing critical hostname checks. Because the wrapper is identified as an X509ExtendedTrustManager, standard cryptographic engines and Netty's OpenSSL wrappers do not re-wrap it, failing to execute any hostname validation. Consequently, clients silently accept certificates for any host, enabling unauthenticated Man-in-the-Middle (MitM) attacks.
An uncontrolled resource pre-allocation flaw in the Netty Redis codec module allows remote unauthenticated attackers to cause a denial of service (OutOfMemoryError) by sending a crafted Redis Serialization Protocol (RESP) array header.
CVE-2026-50020 is a medium-severity HTTP Request Smuggling/Response Smuggling vulnerability (CWE-444) within the Netty asynchronous network application framework. The flaw resides in Netty's HTTP codec implementation, specifically the HttpObjectDecoder class, which silently consumes arbitrary ISO control bytes preceding the first request line.