Advisory Details
Title: Sandboxed message tool can read host files outside sandboxRoot via media=file://... during attachment hydration
Description:
Summary
A path traversal / local file read flaw in openclaw-cn allows a sandboxed agent that has been explicitly granted the built-in message tool to read host files outside its configured sandboxRoot. The issue occurs because createMessageTool() validates path and filePath inputs but fails to forward sandboxRoot into runMessageAction(), leaving the media=file://... attachment path unsandboxed. As a result, attacker-controlled media input can reach the local file read sink and load arbitrary readable host files into outbound attachment buffers.
Details
The vulnerable flow is in the built-in outbound message/attachment path.
At the tool entrypoint, createMessageTool() invokes runMessageAction() without passing sandboxRoot:
const result = await runMessageAction({
cfg,
action,
params,
defaultAccountId: accountId ?? undefined,
gateway,
toolContext,
agentId: options?.agentSessionKey
? resolveSessionAgentId({ sessionKey: options.agentSessionKey, config: cfg })
: undefined,
abortSignal: signal,
});
Because sandboxRoot is omitted here, downstream attachment hydration does not receive the sandbox context. hydrateSendAttachmentParams() then resolves media before any equivalent sandbox enforcement and passes it into loadWebMedia():
const mediaSource = mediaHint ?? fileHint;
if (!params.dryRun && !readStringParam(params.args, "buffer", { trim: false }) && mediaSource) {
const media = await loadWebMedia(mediaSource, maxBytes);
params.args.buffer = media.buffer.toString("base64");
}
Finally, loadWebMedia() accepts file:// URLs, converts them to local paths, and reads the file from disk:
if (mediaUrl.startsWith("file://")) {
mediaUrl = fileURLToPath(mediaUrl);
}
...
const data = await fs.readFile(mediaUrl);
The result is a parameter-shape bypass:
path=/host/file is expected to be sandbox-constrained
media=file:///host/file reaches the same sink without the sandbox guard
I verified this with the real exported message tool boundary and the real attachment hydration logic. The verification PoC shows that a canary file outside the sandbox root is read into the attachment buffer, while a control run using path= against the same file is rejected with Path escapes sandbox root.
Operational scope note: this is not reachable in the default sandbox tool allowlist, because message is not allowed by default. It becomes reachable in realistic deployments where an operator explicitly enables message for a sandboxed agent and an accepted inbound prompt/input can induce the tool call.
PoC
Prerequisites
openclaw-cn checked out locally with dependencies installed
- Node.js 22+
- Python 3
- A runtime context where the built-in
message tool is available to a sandboxed agent
- Access to the provided PoC artifact directory
Reproduction Steps
- Download the TypeScript driver from: message_tool_sandbox_capture_driver.ts
- Download the verification script from: verification_test.py
- Download the control script from: control-path-guard.py
- From the repository root, run the verification script:
python3 llm-enhance/cve-finding/similar/path-traversal/CVE-2026-29611-dataflow-message-tool-sandboxroot-bypass-exp/verification_test.py
- Confirm that
verification_result.json shows ok: true, captureContainsCanary: true, and the returned attachment buffer contains the canary from host_secret.txt.
- Run the control script:
python3 llm-enhance/cve-finding/similar/path-traversal/CVE-2026-29611-dataflow-message-tool-sandboxroot-bypass-exp/control-path-guard.py
- Confirm that
control_result.json shows ok: false, bufferBytes: 0, and an error containing Path escapes sandbox root.
Log of Evidence
Verification run:
[DEFECT-CONFIRMED-WITH-LIMITATIONS]
mode=Integration-Test
interface=exported message tool execute() -> runMessageAction() -> hydrateSendAttachmentParams() -> loadWebMedia()
driver_capture_contains_canary=True
independent_capture_contains_canary=True
buffer_bytes=54
Verification artifact highlights:
{
"ok": true,
"mode": "vuln",
"bufferBytes": 54,
"captureContainsCanary": true,
"capturePreview": "CVE-2026-29611-CANARY-88971305cd6d40edb40cc1d3b9b70f89"
}
Control run:
[CONTROL-PASS]
mode=Integration-Test
interface=exported message tool execute()
variant=path parameter outside sandbox root
Control artifact highlights:
{
"ok": false,
"mode": "control",
"bufferBytes": 0,
"executionError": "Path escapes sandbox root (...): .../host_secret.txt"
}
Impact
This is a local file read vulnerability at the agent tool boundary. In deployments that explicitly expose message to a sandboxed agent, an attacker who can influence an accepted tool call can cause the agent to read arbitrary host files readable by the openclaw-cn process and package those contents into outbound attachment buffers. Depending on the configured channel action, this can lead directly to exfiltration of local source files, configuration files, session state, or other sensitive host data.
Affected products
- Ecosystem: npm
- Package name: openclaw-cn
- Affected versions: <= 2026.2.5
- Patched versions:
Severity
- Severity: High
- Vector string: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weaknesses
- CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Occurrences
Advisory Details
Title: Sandboxed
messagetool can read host files outsidesandboxRootviamedia=file://...during attachment hydrationDescription:
Summary
A path traversal / local file read flaw in
openclaw-cnallows a sandboxed agent that has been explicitly granted the built-inmessagetool to read host files outside its configuredsandboxRoot. The issue occurs becausecreateMessageTool()validatespathandfilePathinputs but fails to forwardsandboxRootintorunMessageAction(), leaving themedia=file://...attachment path unsandboxed. As a result, attacker-controlledmediainput can reach the local file read sink and load arbitrary readable host files into outbound attachment buffers.Details
The vulnerable flow is in the built-in outbound message/attachment path.
At the tool entrypoint,
createMessageTool()invokesrunMessageAction()without passingsandboxRoot:Because
sandboxRootis omitted here, downstream attachment hydration does not receive the sandbox context.hydrateSendAttachmentParams()then resolvesmediabefore any equivalent sandbox enforcement and passes it intoloadWebMedia():Finally,
loadWebMedia()acceptsfile://URLs, converts them to local paths, and reads the file from disk:The result is a parameter-shape bypass:
path=/host/fileis expected to be sandbox-constrainedmedia=file:///host/filereaches the same sink without the sandbox guardI verified this with the real exported
messagetool boundary and the real attachment hydration logic. The verification PoC shows that a canary file outside the sandbox root is read into the attachment buffer, while a control run usingpath=against the same file is rejected withPath escapes sandbox root.Operational scope note: this is not reachable in the default sandbox tool allowlist, because
messageis not allowed by default. It becomes reachable in realistic deployments where an operator explicitly enablesmessagefor a sandboxed agent and an accepted inbound prompt/input can induce the tool call.PoC
Prerequisites
openclaw-cnchecked out locally with dependencies installedmessagetool is available to a sandboxed agentReproduction Steps
python3 llm-enhance/cve-finding/similar/path-traversal/CVE-2026-29611-dataflow-message-tool-sandboxroot-bypass-exp/verification_test.pyverification_result.jsonshowsok: true,captureContainsCanary: true, and the returned attachment buffer contains the canary fromhost_secret.txt.python3 llm-enhance/cve-finding/similar/path-traversal/CVE-2026-29611-dataflow-message-tool-sandboxroot-bypass-exp/control-path-guard.pycontrol_result.jsonshowsok: false,bufferBytes: 0, and an error containingPath escapes sandbox root.Log of Evidence
Verification run:
Verification artifact highlights:
{ "ok": true, "mode": "vuln", "bufferBytes": 54, "captureContainsCanary": true, "capturePreview": "CVE-2026-29611-CANARY-88971305cd6d40edb40cc1d3b9b70f89" }Control run:
Control artifact highlights:
{ "ok": false, "mode": "control", "bufferBytes": 0, "executionError": "Path escapes sandbox root (...): .../host_secret.txt" }Impact
This is a local file read vulnerability at the agent tool boundary. In deployments that explicitly expose
messageto a sandboxed agent, an attacker who can influence an accepted tool call can cause the agent to read arbitrary host files readable by theopenclaw-cnprocess and package those contents into outbound attachment buffers. Depending on the configured channel action, this can lead directly to exfiltration of local source files, configuration files, session state, or other sensitive host data.Affected products
Severity
Weaknesses
Occurrences
createMessageTool()callsrunMessageAction()without forwardingsandboxRoot, so downstream attachment handling loses sandbox context.hydrateSendAttachmentParams()prioritizesmediaand passes the resolved local source directly intoloadWebMedia()for buffer hydration.sendAttachmentwithout any preceding sandbox-media normalization in this release.loadWebMedia()acceptsfile://URLs and converts them into local filesystem paths.fs.readFile(), making host file contents available to outbound attachment processing.