T01 · Skill Instruction Hijacking
Error
- Location
- scripts/task_progress_stream.js:252
- Finding
- Untrusted Log Content Is Injected into an Agent Chat Session<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task_progress_stream.js`, lines 175, 198, 252–273, 319–321, and 395–397 **Vulnerability Type**: Prompt injection through untrusted process or log output **Risk Level**: High ### Vulnerable Code ```js // Lines 175 and 198: untrusted log content is embedded in chat messages. if (this.lastLine) rows.push(`- 最新日志: \`${truncate(this.lastLine, 160)}\``); ... if (this.lastLine) rows.push(`- 最后一行日志: \`${truncate(this.lastLine, 200)}\``); // Lines 252–273: the resulting message is injected into a chat session. function spawnOpenClawInject(session, message) { return new Promise((resolve) => { const payload = JSON.stringify({ sessionKey: session, message }); const child = spawn( "openclaw", ["gateway", "call", "chat.inject", payload], { stdio: ["ignore", "pipe", "pipe"], } ); let out = ""; let err = ""; child.stdout.on("data", (d) => (out += d.toString())); child.stderr.on("data", (d) => (err += d.toString())); child.on("close", (code) => { resolve({ code, out, err }); }); child.on("error", (e) => { resolve({ code: -1, out: "", err: String(e) }); }); }); } // Lines 319–321: command output reaches the progress state. function onLine(line) { state.pushLine(line); logStream.write(line + "\n"); flushState(); } // Lines 395–397: tailed file content also reaches the progress state. for (const line of text.split(/\r?\n/)) { if (line.trim()) state.pushLine(line); } ``` ### Technical Analysis The script treats output from a spawned process and content from a tailed file as trusted chat content. `pushLine()` stores each input line in `state.lastLine`. The `summaryText()` and `finalText()` methods then interpolate that value into a Markdown message, which is submitted to the selected OpenClaw session through `chat.inject`. The only content control applied is length truncation. Truncation does not escape Markdow ...[truncated 1949 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not inject raw process output or file content into an agent-interpreted chat message. 2. Prefer a structured, UI-only progress API whose content is not added to the language model's instruction context. 3. If no such API exists, omit `lastLine` from injected messages and transmit only strictly parsed numeric fields such as step, epoch, loss, and percentage. 4. Apply strict schemas and bounds to every transmitted field. Reject unexpected values rather than forwarding arbitrary text. 5. If log excerpts must be displayed, escape Markdown delimiters and control characters and render the excerpt in a non-agent-visible interface. Escaping alone must not be treated as a complete prompt-injection defense. 6. Mark all externally derived content as untrusted data and ensure the receiving system enforces that distinction independently of natural-language labels. 7. Restrict allowed destination sessions and require explicit user confirmation before sending externally controlled content to a privileged session. 8. Apply least privilege and confirmation gates to any tools available in sessions receiving automated updates. ]]>
