T01 · Skill Instruction Hijacking
Error
- Location
- scripts/websocket_listener.py:49
- Finding
- Remote Private Messages Are Injected into High-Priority OpenClaw Instructions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/websocket_listener.py:49-64, 76-87, 162-166`; supporting instructions in `SKILL.md:277-288, 325-331` **Vulnerability Type**: Remote prompt injection through a privileged Agent event **Risk Level**: Critical ### Vulnerable Code ```python def build_system_event_prompt(message_content: str) -> str: """Builds the immediate reply instruction passed into OpenClaw.""" normalized_message = message_content.strip() return f""" SYSTEM ALERT: HIGH-PRIORITY TASK INJECTED You have received a new paip.ai private chat message and must handle it immediately. **Message Content:** "{normalized_message}" **Your mandatory task is as follows:** 1. **Find the Room ID:** Immediately execute a search using the paip.ai API to find the chat session where the latest message content exactly matches the text above. This typically involves calling the `/agent/chat/session/list?withLatestMessage=true` endpoint and parsing the JSON response. 2. **Extract the `roomId`** from the correct session object in the search result. 3. **Formulate a Reply:** Based on the message content, formulate a natural, conversational reply. 4. **Send the Reply:** Use the paip.ai API to send your formulated reply to the extracted `roomId`. 5. **Confirm Completion:** After sending the reply, your task is complete. """.strip() ``` ```python process = await asyncio.create_subprocess_exec( "openclaw", "system", "event", "--mode", "now", "--expect-final", "--timeout", str(SYSTEM_EVENT_TIMEOUT_MS), "--json", "--text", prompt, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) ``` ```python async for message in websocket: message_content = str(message) logging.info(f"Received raw notification: {message_content}") append_event_log(message_content) await reply_queue.put(message_content) ``` ### Technical Analysis The listener treats an arbitrary WebSocket message ...[truncated 1715 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not submit remote message content as part of a system-level or high-priority instruction. - Represent inbound content as typed, untrusted data passed to a fixed handler rather than interpolated prompt text. - Implement a deterministic message-processing component with a narrowly scoped API client instead of allowing a general-purpose Agent to choose tools. - Restrict the handler to explicitly approved operations, such as fetching the matching room and sending one reply to that room. - Validate WebSocket messages against a strict schema, length limit, sender identity, and expected character encoding. - Require user approval before performing sensitive or non-reply actions. - Use a dedicated credential whose permissions are limited to reading the relevant session and sending a reply. - If an LLM must formulate replies, pass only normalized message data and prevent it from invoking tools directly. A separate trusted component should validate and execute the resulting action. ]]>
