T09 · Insecure Skill Coding Practices
Warning
- Location
- index.ts:49
- Finding
- Unfiltered Persistent Capture of Conversation Content<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:49-87` **Vulnerability Type**: Unprotected persistent storage of potentially sensitive conversation data **Risk Level**: Medium ### Vulnerable Code ```ts async function writeToLanceDB(sender: "爸爸" | "张褐", content: string, timestamp: Date, api: OpenClawPluginApi) { try { await api.memory.store({ text: `${sender}:${content}`, category: "fact", importance: 0.6, metadata: { sender: sender, timestamp: timestamp.getTime(), date: formatDate(timestamp, "date"), }, }); } catch (err) { api.logger.error(`写入向量库失败: ${err instanceof Error ? err.message : String(err)}`); } } export default function registerPlugin(api: OpenClawPluginApi) { // 监听用户发来的消息 api.events.on("inbound-message", async (msg: InboundMessage) => { if (msg.content.type === "text" && msg.content.text?.trim()) { const timestamp = new Date(msg.timestamp); // 双写:同时写入文件和向量库 await Promise.all([ writeToMarkdown("爸爸", msg.content.text, timestamp), writeToLanceDB("爸爸", msg.content.text, timestamp, api) ]); } }); // 监听助理发出的消息,过滤工具调用和系统消息 api.events.on("outbound-message", async (msg: OutboundMessage) => { if (msg.content.type === "text" && msg.content.text?.trim() && msg.content.text !== "NO_REPLY" && !msg.toolCall) { const timestamp = new Date(); await Promise.all([ writeToMarkdown("张褐", msg.content.text, timestamp), writeToLanceDB("张褐", msg.content.text, timestamp, api) ]); } }); api.logger.info("✅ 记忆自动同步插件启动成功,所有对话将自动双写到记忆文件和LanceDB向量库"); } ``` ### Technical Analysis The plugin subscribes globally to inbound and outbound text-message events and sends every qualifying message to both a Markdown writer and the OpenClaw memory store. The filtering only excludes empty text, tool calls, and the special `NO_REPLY` value. It does not detect credentials, authentication tokens, pr ...[truncated 2013 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require explicit, informed opt-in before enabling conversation capture. 2. Allow users to select which conversations, participants, or message categories may be stored. 3. Apply secret and PII detection before either persistence operation; reject or redact passwords, tokens, private keys, payment data, and sensitive identifiers. 4. Provide separate controls for Markdown storage and vector-memory storage. 5. Define retention limits and implement deletion that removes corresponding records from both storage systems. 6. Use encryption at rest and restrictive filesystem permissions for retained conversation data. 7. Avoid automatically categorizing all messages as durable facts; store only content explicitly selected for long-term memory. 8. Clearly document the storage locations, retrieval behavior, access model, retention policy, and residual copies created by indexing or backups. ]]>
