Skip to content

GHSA-7xr2-q9vf-x4r5 CVE-2026-35632

OpenClaw: Symlink Traversal via IDENTITY.md appendFile in agents.create/update (Incomplete Fix for CVE-2026-32013)

High npm
Severity
0.0 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.42%
Chance of exploitation in the next 30 days. Higher than 35.92% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-61 UNIX Symbolic Link (Symlink) Following
Fix
None yet
No fixed version published

Description

Summary

The patch for CVE-2026-32013 introduced symlink resolution and workspace boundary enforcement for agents.files.get and agents.files.set. However, two other handlers in the same file (agents.create and agents.update) still use raw fs.appendFile on the IDENTITY.md file without any symlink containment check. An attacker who can place a symlink in the agent workspace can hijack the IDENTITY.md path to append attacker-controlled content to arbitrary files on the system.

Details

In src/gateway/server-methods/agents.ts, the agents.create handler constructs the identity path and appends agent metadata without verifying symlinks:

// agents.create — line 283-291
const identityPath = path.join(workspaceDir, DEFAULT_IDENTITY_FILENAME);
const lines = [
  "",
  `- Name: ${safeName}`,
  ...(emoji ? [`- Emoji: ${sanitizeIdentityLine(emoji)}`] : []),
  ...(avatar ? [`- Avatar: ${sanitizeIdentityLine(avatar)}`] : []),
  "",
];
await fs.appendFile(identityPath, lines.join("\n"), "utf-8"); // ← NO SYMLINK CHECK

The agents.update handler has the same issue at line 348-349:

// agents.update — line 348-349
const identityPath = path.join(workspace, DEFAULT_IDENTITY_FILENAME);
await fs.appendFile(identityPath, `\n- Avatar: ${sanitizeIdentityLine(avatar)}\n`, "utf-8"); // ← NO SYMLINK CHECK

fs.appendFile follows symlinks by default. If the IDENTITY.md file in the workspace is a symlink pointing to a sensitive file (e.g., /etc/crontab, ~/.bashrc, or ~/.ssh/authorized_keys), calling agents.create will append the agent identity metadata to that file.

The ensureAgentWorkspace function (called at line 274 before the append) uses exclusive-create mode (flag: 'wx') for IDENTITY.md. If a symlink already exists at that path, the EEXIST error is silently caught, and the subsequent fs.appendFile follows the symlink.

Attack flow:

1. Attacker plants symlink: workspace/IDENTITY.md → /etc/crontab
2. ensureAgentWorkspace skips creation (EEXIST from symlink)
3. fs.appendFile follows symlink → writes to /etc/crontab
4. Attacker-controlled content (name, emoji, avatar) injected into crontab → RCE

PoC

Prerequisites: Docker and Python 3 installed.

Step 1: Build and start the test environment.

cd llm-enhance/cve-finding/RCE/CVE-2026-32013-identity-appendFile-variant-exp/
docker compose up -d --build
sleep 3

Step 2: Run the exploit.

python3 poc_exploit.py

This script:

  1. Plants a symlink IDENTITY.md → /etc/target-file.txt inside the agent workspace
  2. Calls the agents.create API endpoint via HTTP POST
  3. Verifies that the agent identity metadata was appended to /etc/target-file.txt

Step 3: Run the control experiment.

python3 control-patched_realpath.py

Step 4: Cleanup.

docker compose down

Log of Evidence

Exploit output:

=== CVE-2026-32013 Variant: Symlink Traversal via IDENTITY.md appendFile ===
[*] Planting symlink: IDENTITY.md -> /etc/target-file.txt
[*] Symlink: lrwxrwxrwx 1 root root 20 /workspaces/evil-agent/IDENTITY.md -> /etc/target-file.txt
[*] Original /etc/target-file.txt: ORIGINAL_SENSITIVE_CONTENT

[*] Calling agents.create with name='evil-agent'...
[*] API response: {'ok': True, 'agentId': 'evil-agent', 'workspace': '/workspaces/evil-agent'}

[*] /etc/target-file.txt after exploit:
    ORIGINAL_SENSITIVE_CONTENT

- Name: evil-agent
- Emoji: 💀
- Avatar: evil.png

[+] SUCCESS! Symlink traversal confirmed.
[+] fs.appendFile followed IDENTITY.md symlink and wrote to /etc/target-file.txt
[+] Attacker-controlled content injected into arbitrary file.

Control output:

=== CONTROL: Patched agents.create blocks symlink traversal ===
[*] Planting symlink: IDENTITY.md -> /etc/target-file.txt
[*] Original /etc/target-file.txt: ORIGINAL_SENSITIVE_CONTENT

[*] Calling PATCHED agents.create with name='safe-agent'...
[*] API response: {'ok': False, 'error': 'symlink_traversal_blocked', 'realPath': '/etc/target-file.txt'}

[*] /etc/target-file.txt after patched call: ORIGINAL_SENSITIVE_CONTENT

[+] CONTROL PASSED: Patched endpoint detected and blocked symlink traversal.
[+] /etc/target-file.txt remains unchanged.

Impact

An attacker who can plant a symlink in the agent workspace directory can use the agents.create or agents.update gateway API to append attacker-controlled content to arbitrary files on the system. If the target file is:

  • /etc/crontab or user crontab → Remote Code Execution
  • ~/.bashrc or ~/.profile → Persistent code execution on login
  • ~/.ssh/authorized_keys → Unauthorized SSH access
  • Application configuration files → Service disruption

The attacker-controlled content includes the agent name (arbitrary string), emoji, and avatar fields, which are only lightly sanitized (whitespace normalization via sanitizeIdentityLine).

Affected products

  • Ecosystem: npm
  • Package name: openclaw
  • Affected versions: <= 2026.2.22
  • Patched versions: None

Occurrences

Permalink Description
https://github.com/openclaw/openclaw/blob/main/src/gateway/server-methods/agents.ts#L283-L291 agents.create handler uses fs.appendFile on IDENTITY.md without symlink resolution or workspace boundary check.
https://github.com/openclaw/openclaw/blob/main/src/gateway/server-methods/agents.ts#L348-L349 agents.update handler uses fs.appendFile on IDENTITY.md without symlink resolution or workspace boundary check.
https://github.com/openclaw/openclaw/blob/main/src/gateway/server-methods/agents.ts#L274 ensureAgentWorkspace is called before append, but its exclusive-create (wx) flag silently skips existing symlinks (EEXIST).

Affected versions

npm

PackageVulnerableFixed in
openclaw
<= 2026.2.22
No fix yet

How to fix

No fixed version has been published yet. Until one is, remove or replace the package, or turn off or isolate the affected feature. This page updates when a fix ships.

Severity breakdown

CVSS 4.0 0.0

CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N

Attack vector
Local
Attack complexity
Low
Attack requirements
None
Privileges required
Low
User interaction
None
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
High
Availability (vulnerable system)
High
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None

CVSS 3.1 7.1

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
High

Weakness

CWE-61: UNIX Symbolic Link (Symlink) Following

The product, when opening a file or directory, does not sufficiently account for when the file is a symbolic link that resolves to a target outside of the intended control sphere. This could allow an attacker to cause the product to operate on unauthorized files.

How to prevent it
  • Implementation: Symbolic link attacks often occur when a program creates a tmp directory that stores files/links. Access to the directory should be restricted to the program as to prevent attackers from manipulating the files.
  • Architecture and Design: Follow the principle of least privilege when assigning access rights to entities in a software system. Denying access to a file can prevent an attacker from replacing that file with a link to a sensitive file. Ensure good compartmentalization in the system to provide protected areas that can be trusted.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-3x84-qq85-fj65
OpenClaw: Browser CDP discovery could accept blocked WebSocket URLs
High Also affects openclaw
GHSA-9c3v-684m-579c
OpenClaw MCP SSE redirects could forward Authorization headers
Medium Also affects openclaw
GHSA-f397-5vjw-v2c2
OpenClaw: Shell inline-command parsing could miss an allowlist check
High Also affects openclaw
GHSA-rx78-29qr-5hq8
OpenClaw: Workspace-derived service PATH could influence trash command selection
High Also affects openclaw
GHSA-ccwh-wwpp-6wg5
OpenClaw: Host environment sanitizer missed two Node.js control variables
High Also affects openclaw
GHSA-985f-72mj-8gf7
OpenClaw: Tool group policy callers could accept unvalidated group IDs
Medium Also affects openclaw
GHSA-9v8j-9c9g-w66c
OpenClaw: Bootstrap token replay could widen pending pairing scopes
Medium Also affects openclaw
GHSA-c226-q6fx-6j6c
OpenClaw: macOS Swift exec allowlist missed combined POSIX inline flags
Medium Also affects openclaw
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor