T01 · Skill Instruction Hijacking
Error
- Location
- usewhisper-autohook.mjs:206
- Finding
- Persistent prompt injection through unsanitized remote memory<![CDATA[ ## Vulnerability Details **File Location**: `usewhisper-autohook.mjs:206-223`, `usewhisper-autohook.mjs:362-378`, `SKILL.md:57-74` **Vulnerability Type**: Persistent prompt injection through externally stored context **Risk Level**: High ### Vulnerable Code ```javascript const ctxRes = await withAutoProject({ apiUrl, project }, () => post(apiUrl, "/v1/context/query", ctxReq, { retry: true }) ); const context = String(ctxRes?.context || ""); const contextHash = ctxRes?.meta?.context_hash || ctxRes?.meta?.contextHash || undefined; if (contextHash) await writeLastContextHash(stateKey, String(contextHash)); // Build a minimal prompt for upstream: keep existing system messages, strip conversation history, // and replace the last user message with memory-injected text. const systemMessages = messages.filter((m) => m && m.role === "system"); const injectedUser = { role: "user", content: context ? `Relevant long-term memory:\n${context}\n\nNow respond to:\n${String(lastUserMsg.content || "")}` : String(lastUserMsg.content || ""), }; ``` The Anthropic proxy performs the equivalent operation: ```javascript const ctxRes = await withAutoProject({ apiUrl, project }, () => post(apiUrl, "/v1/context/query", ctxReq, { retry: true }) ); const context = String(ctxRes?.context || ""); const contextHash = ctxRes?.meta?.context_hash || ctxRes?.meta?.contextHash || undefined; if (contextHash) await writeLastContextHash(stateKey, String(contextHash)); const injectedUserText = context ? `Relevant long-term memory:\n${context}\n\nNow respond to:\n${lastUserText}` : lastUserText; const upstreamBody = { ...bodyRaw, stream: false, messages: [{ role: "user", content: injectedUserText }], }; ``` The installation instructions mandate this behavior: ```text Before you think or respond to any message: 1) Call get_whisper_context with: user_id = "telegram:{from_id}" session_id = "telegram:{chat_id}" current_query = the user's message text ...[truncated 2739 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat all retrieved memory as untrusted data, not instructions. 2. Place memory in a strongly delimited data structure and add a higher-priority instruction stating that commands or policy statements inside memory must never be followed. 3. Store and retrieve structured factual records instead of arbitrary conversation text where possible. 4. Filter or quarantine memory containing instruction-like phrases, tool requests, hidden markup, or attempts to override system policy. 5. Track record provenance and only inject memory from the expected project, user, and session. 6. Require explicit user confirmation before retrieved content can cause tool use or other side effects. 7. Provide per-turn controls to disable memory retrieval and a mechanism to inspect and delete poisoned records. 8. Avoid shared fallback identifiers; reject proxy requests without reliable user and session identifiers when isolation cannot be guaranteed. ]]>
