Back to skill

Security audit

Openclaw Mem0

Security checks for vulnerabilities and agentic risk

Overview

This memory plugin matches its advertised purpose, but it automatically stores and reuses chat content with broad remote, cross-user, and deletion capabilities that need review before installation.

Install only if you deliberately want persistent agent memory. Before enabling, consider disabling autoCapture and autoRecall by default, using a trusted HTTPS Mem0 endpoint or self-hosted backend, scoping backend credentials per user or tenant, avoiding sensitive chats while capture is enabled, and upgrading the flagged dependencies. Review deletion behavior because memory_forget can remove records by ID or high-confidence query match without confirmation.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
index.ts:1294
Finding
Default Cloud Auto-Capture Transmits Raw Conversation Content to Mem0<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:545-546`, `index.ts:1294-1357`, `lib/mem0.ts:137-159` **Vulnerability Type**: Sensitive data exposure through default remote transmission **Risk Level**: High ### Vulnerable Code ```ts // index.ts:545-546 autoCapture: cfg.autoCapture !== false, autoRecall: cfg.autoRecall !== false, ``` ```ts // index.ts:1294-1357 if (cfg.autoCapture) { api.on("agent_end", async (event, ctx) => { if (!event.success || !event.messages || event.messages.length === 0) { return; } // Track session ID const sessionId = (ctx as any)?.sessionKey ?? undefined; if (sessionId) currentSessionId = sessionId; try { // Extract messages, limiting to last 10 const recentMessages = event.messages.slice(-10); const formattedMessages: Array<{ role: string; content: string; }> = []; for (const msg of recentMessages) { if (!msg || typeof msg !== "object") continue; const msgObj = msg as Record<string, unknown>; const role = msgObj.role; if (role !== "user" && role !== "assistant") continue; let textContent = ""; const content = msgObj.content; if (typeof content === "string") { textContent = content; } else if (Array.isArray(content)) { for (const block of content) { if ( block && typeof block === "object" && "type" in block && (block as Record<string, unknown>).type === "text" && "text" in block && typeof (block as Record<string, unknown>).text === "string" ) { textContent += (textContent ? "\n" : "") + ((block as Record<string, unknown>).text as string); } } } if (!textContent) continue; // Skip injected memory context if (textContent.includes("<relevant-memories ...[truncated 2786 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set `autoCapture` to `false` by default, especially in platform mode. 2. Require explicit, informed opt-in before enabling cloud capture. 3. Clearly disclose the destination, data categories, retention behavior, and deletion process. 4. Apply deterministic local redaction before calling the provider: - API keys and bearer tokens. - Passwords and connection strings. - Private keys and certificates. - Common financial and identity identifiers. 5. Capture only user-authored content unless assistant content is explicitly required. 6. Minimize the captured window and extract candidate facts locally where practical. 7. Allow users to mark individual messages or sessions as non-retainable. 8. Provide a preview or confirmation mode for sensitive memories. 9. Add automated tests proving that recognized secret formats never reach the network client. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
lib/mem0.ts:25
Finding
Unrestricted Custom Host Can Receive the Mem0 API Token and Conversation Data<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:562`, `index.ts:585`, `lib/mem0.ts:25-34`, `lib/mem0.ts:66-75`, `openclaw.plugin.json:88-92` **Vulnerability Type**: Credential disclosure and unsafe outbound endpoint configuration **Risk Level**: High ### Vulnerable Code ```ts // index.ts:562 host: typeof cfg.host === "string" ? resolveEnvVars(cfg.host) : undefined, ``` ```ts // index.ts:585 return new PlatformProvider(cfg.apiKey!, cfg.orgId, cfg.projectId, cfg.host); ``` ```ts // lib/mem0.ts:25-34 constructor(options: MemoryClientOptions) { this.apiKey = options.apiKey; this.host = options.host || "https://api.mem0.ai"; this.organizationName = options.organizationName || null; this.projectName = options.projectName || null; this.organizationId = options.organizationId || null; this.projectId = options.projectId || null; this.headers = { Authorization: `Token ${this.apiKey}`, "Content-Type": "application/json" }; ``` ```ts // lib/mem0.ts:66-75 private async _fetchWithErrorHandling(url: string, options: RequestInit): Promise<any> { const response = await fetch(url, { ...options, headers: { ...options.headers, Authorization: `Token ${this.apiKey}` } }); ``` ```json // openclaw.plugin.json:88-92 "host": { "type": "string" }, "apiKey": { "type": "string" }, ``` ### Technical Analysis The platform backend permits an arbitrary `host` string. Neither the runtime parser nor the plugin schema validates the URL scheme, hostname, port, or embedded credentials. The network wrapper unconditionally adds the Mem0 API token to every request sent through the client. Consequently, an attacker-controlled or accidentally unsafe host receives the API token. Capture and search requests can also disclose conversation content and user identifiers. Because HTTPS is not required, a configured `http://` endpoint can expose both credentials and content to network interception. A configurable host can be legit ...[truncated 1430 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the host with the standard `URL` API and reject malformed values. 2. Require HTTPS for all non-loopback destinations. 3. In platform mode, allowlist the official `api.mem0.ai` hostname. 4. Introduce a separate, explicitly named custom-endpoint mode for private deployments. 5. Require a separate credential for a custom host rather than forwarding a cloud credential automatically. 6. Reject URLs containing embedded usernames or passwords. 7. Warn and require explicit acknowledgement for loopback, private-network, or nonstandard-port destinations. 8. Consider certificate pinning or documented private-CA handling for high-security deployments. 9. Avoid including sensitive response bodies in propagated error messages. 10. Add tests confirming that tokens cannot be sent to unapproved schemes or hosts. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.ts:659
Finding
Memory Tools Lack User-Scope and Ownership Authorization<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:659-722`, `index.ts:782-819`, `index.ts:867-879`, `index.ts:906-956`, `index.ts:1011-1046` **Vulnerability Type**: Cross-user memory access, modification, and deletion **Risk Level**: High ### Vulnerable Code ```ts // index.ts:672-722 userId: Type.Optional( Type.String({ description: "User ID to scope search (default: configured userId)", }), ), ... const { query, limit, userId, scope = "all" } = params as { query: string; limit?: number; userId?: string; scope?: "session" | "long-term" | "all"; }; ... results = await provider.search( query, buildSearchOptions(userId, limit), ); ``` ```ts // index.ts:790-819 userId: Type.Optional( Type.String({ description: "User ID to scope this memory", }), ), ... const { text, userId, longTerm = true } = params as { text: string; userId?: string; metadata?: Record<string, unknown>; longTerm?: boolean; }; ... const result = await provider.add( [{ role: "user", content: text }], buildAddOptions(userId, runId), ); ``` ```ts // index.ts:869-879 name: "memory_get", label: "Memory Get", description: "Retrieve a specific memory by its ID from Mem0.", parameters: Type.Object({ memoryId: Type.String({ description: "The memory ID to retrieve" }), }), async execute(_toolCallId, params) { const { memoryId } = params as { memoryId: string }; try { const memory = await provider.get(memoryId); ``` ```ts // index.ts:913-956 userId: Type.Optional( Type.String({ description: "User ID to list memories for (default: configured userId)", }), ), ... const { userId, scope = "all" } = params as { userId?: string; scope?: "session" | "long-term" | "all"; }; try { let memories: MemoryItem[] = []; const uid = userId || cfg.userId; ... memories = await provider.getAll({ user_id: uid }); ``` ```ts // index.ts:1034-1040 if (memoryId) { await provider.delete(memoryId); return { content: [ { ty ...[truncated 2314 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `userId` from all Agent-callable tool schemas. 2. Derive the user identifier from authenticated request or session context. 3. Pass session identity through each tool invocation rather than storing it in a shared mutable variable. 4. Before `get` or `delete`, fetch metadata using a privileged internal path and verify that the record belongs to the current authenticated user. 5. Reject operations where the requested record has no verifiable owner. 6. Use distinct backend credentials or enforced tenant scopes where possible. 7. Separate administrative cross-user tools from normal Agent tools and require explicit administrator authorization. 8. Require user confirmation for destructive deletion. 9. Record security audit logs for read, write, and delete operations without logging memory contents or credentials. 10. Add multi-user tests proving that one session cannot list, search, retrieve, modify, or delete another user's records. ]]>

T02 · Agent Memory Poisoning

Error
Location
index.ts:1229
Finding
Persisted Memory Is Injected Verbatim into the System Prompt<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:782-819`, `index.ts:1229-1286` **Vulnerability Type**: Persistent prompt injection through recalled memory **Risk Level**: High ### Vulnerable Code ```ts // index.ts:784-819 name: "memory_store", label: "Memory Store", description: "Save important information in long-term memory via Mem0. Use for preferences, facts, decisions, and anything worth remembering.", ... async execute(_toolCallId, params) { const { text, userId, longTerm = true } = params as { text: string; userId?: string; metadata?: Record<string, unknown>; longTerm?: boolean; }; try { const runId = !longTerm && currentSessionId ? currentSessionId : undefined; const result = await provider.add( [{ role: "user", content: text }], buildAddOptions(userId, runId), ); ``` ```ts // index.ts:1229-1286 if (cfg.autoRecall) { api.on("before_agent_start", async (event, ctx) => { if (!event.prompt || event.prompt.length < 5) return; // Track session ID const sessionId = (ctx as any)?.sessionKey ?? undefined; if (sessionId) currentSessionId = sessionId; try { // Search long-term memories (user-scoped) const longTermResults = await provider.search( event.prompt, buildSearchOptions(), ); // Search session memories (session-scoped) if we have a session ID let sessionResults: MemoryItem[] = []; if (currentSessionId) { sessionResults = await provider.search( event.prompt, buildSearchOptions(undefined, undefined, currentSessionId), ); } // Deduplicate session results against long-term const longTermIds = new Set(longTermResults.map((r) => r.id)); const uniqueSessionResults = sessionResults.filter( (r) => !longTermIds.has(r.id), ); if (longTermResults.length === 0 && uniqueSessionResults.length === 0) return; // Build context with clear labels ...[truncated 3038 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all recalled memory as untrusted data. 2. Do not place raw memory text in the system prompt when a lower-privilege structured context channel is available. 3. Add an explicit trusted instruction stating that memory entries are historical data and that instructions contained within them must never be followed. 4. Serialize memories as structured data with clear field boundaries instead of interpolating free-form text. 5. Escape or remove control-like markup and instruction-delimiter patterns. 6. Detect and quarantine memories containing imperative instructions, role declarations, tool commands, or prompt-override language. 7. Require user confirmation before executing sensitive or destructive actions derived from recalled memory. 8. Preserve provenance, including who created a memory, when it was created, and whether it was automatically extracted. 9. Allow users to inspect and approve persistent memories before they become eligible for automatic recall. 10. Add adversarial tests covering persistent prompt injection, delimiter injection, induced tool calls, and cross-session poisoning. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (29)

Credential Access

High
Category
Privilege Escalation
Content
"enabled": true,
  "config": {
    "mode": "platform",
    "apiKey": "${MEM0_API_KEY}", // 请在 .env 文件中设置
    "userId": "default-user",
    "autoRecall": true,
    "autoCapture": true
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Known Vulnerable Dependency: @hono/node-server==1.19.9 — 3 advisory(ies): CVE-2026-39406 (@hono/node-server: Middleware bypass via repeated slashes in serveStatic); GHSA-frvp-7c67-39w9 (Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode); CVE-2026-29087 (@hono/node-server has authorization bypass for protected static paths via encode)

High
Category
Supply Chain
Confidence
96% confidence
Finding
@hono/node-server 1.19.9 is flagged for path traversal and middleware/authorization bypass issues in static file serving. Because this dependency sits within an agent framework stack that may expose HTTP endpoints, these flaws are meaningfully dangerous if any feature serves files or relies on path-based protection, especially on Windows or with encoded/repeated-slash paths.

Known Vulnerable Dependency: @mariozechner/pi-coding-agent==0.52.9 — 3 advisory(ies): CVE-2026-54326 (Pi Agent: Potential XSS in HTML session exports via Markdown URL sanitization by); CVE-2026-54328 (Pi Agent: Predictable temporary extension install paths allow local privilege es); CVE-2026-54327 (Pi Agent: Race condition in Pi auth.json writes could expose stored credentials)

High
Category
Supply Chain
Confidence
95% confidence
Finding
@mariozechner/pi-coding-agent 0.52.9 is flagged for XSS in HTML exports, predictable temporary extension install paths, and credential exposure through auth.json write races. In this skill context that is especially relevant because the package is part of an agentic/coding toolchain that may handle local files, credentials, rendered reports, and extension installation, increasing the practical blast radius.

Known Vulnerable Dependency: minimatch==10.1.2 — 3 advisory(ies): CVE-2026-27904 (minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regu); CVE-2026-26996 (minimatch has a ReDoS via repeated wildcards with non-matching literal in patter); CVE-2026-27903 (minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adja)

High
Category
Supply Chain
Confidence
90% confidence
Finding
minimatch 10.1.2 is reported vulnerable to multiple ReDoS cases through crafted glob patterns that trigger catastrophic backtracking. Given this dependency appears in tooling related to coding-agent functionality, an attacker who can supply patterns, ignore rules, or file-selection expressions could cause CPU exhaustion and denial of service.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README explicitly advertises automatic capture and storage of conversation turns into long-term memory, but provides no accompanying warning about sensitive data collection, retention, consent, or downstream use. In an agent plugin context, this is security-relevant because users may unknowingly cause secrets, personal data, or regulated information from chats to be persisted automatically.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The platform/cloud configuration instructs users to send memory data to a managed external Mem0 service, but does not warn that conversation-derived memory content may leave the local environment and be transmitted to a third party. In a long-term memory plugin, this omission increases the risk of accidental exfiltration of sensitive prompts, personal data, credentials, or proprietary information.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README explicitly advertises automatic recall and automatic capture of user conversations into long-term memory, but it does not provide a clear privacy notice, consent model, retention policy, or guidance on handling sensitive data. In an agent plugin context, silently persisting conversational content can expose personal, confidential, or regulated information and increases the risk of unauthorized retention and reuse.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill advertises automatic recall and automatic capture of conversation data, including injecting recalled memory into the system prompt, but does not warn users about privacy, retention, consent, or possible exposure of prior sensitive information. In an agent memory plugin, this omission is security-relevant because it can lead to silent collection of personal data and unintended prompt-context disclosure across sessions.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The documented memory_forget capability allows deletion by memory ID or query, which can remove stored data broadly, yet the skill provides no warning about destructive effects, confirmation requirements, or safeguards against accidental or unauthorized deletion. In a long-term memory plugin, this increases the risk of integrity loss, especially if an agent or user issues an overly broad query.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The plugin explicitly offers automatic storage of conversation context after each agent turn, but the UI/help text provides no warning that sensitive, regulated, or irrelevant user data may be persisted to a third-party or self-hosted memory backend. In a memory skill, this omission is materially risky because users or operators may enable the feature without understanding that secrets, personal data, or transient prompt content could be captured automatically.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The `memory_store` tool documentation and parameter schema state that callers can provide `metadata` to attach to a memory, but the execute handler destructures `metadata` and never uses it in the call to `provider.add`. This is an active contradiction between the tool's documented behavior and the actual code path, which can mislead users or agents into believing metadata is preserved when it is silently dropped.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The auto-recall hook sends the current user prompt to the memory backend as a search query before each agent turn, without any user-facing disclosure in this file. This can leak sensitive prompt content to the memory provider—including a third-party cloud service in platform mode—even when the user did not intend their current message to be transmitted for storage/retrieval processing.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The auto-capture hook stores the last 10 user/assistant messages to the memory backend whenever an agent run succeeds, with no consent, notice, opt-in workflow, or content minimization beyond skipping the injected memory block. That can persist sensitive user data, secrets, personal details, or regulated content to long-term/session memory unexpectedly, increasing privacy risk and downstream exposure if the backend is external or later queried by other flows.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The client sends messages, queries, metadata, webhook data, feedback, and export/filter information to remote `mem0.ai` endpoints via many POST/PUT/GET requests, but the file contains no docstrings, comments, or user-visible logging explaining that user/system data is transmitted over the network. Because this library handles memory content and related identifiers, users may not be adequately warned about privacy-impacting remote transmission.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code defines deletion methods for individual memories and bulk memory deletion, including `delete`, `deleteAll`, `deleteUser`, `deleteUsers`, and `batchDelete`, but provides no confirmation prompt, user-facing log/print, or explanatory comment/docstring warning that data will be removed. Several of these actions are irreversible and can affect many records, especially `deleteAll`, `deleteUsers`, and `batchDelete`.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The manifest advertises automatic capture of conversation context and automatic reinjection of prior memories, but it does not describe any guardrails such as consent requirements, exclusions for sensitive data, scope limits, or trigger conditions. In a memory plugin, this can lead to over-collection of user data and unintended resurfacing of prior sensitive content into later prompts or tool calls.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The manifest describes auto-capture and auto-recall as convenience features but does not explicitly warn that conversation content may be stored externally and later re-injected into model context. This lack of transparency increases the risk that users unknowingly expose personal, confidential, or regulated data to persistence and future prompt inclusion.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill advertises automatic storage of conversation context after each agent turn, but the UI text does not warn that this may capture sensitive data such as credentials, personal information, or proprietary content. In a memory plugin, silent or underexplained persistence materially increases privacy and data-retention risk because users may not realize their full conversations are being sent to or stored in an external memory system.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The file presents all user-facing instructions in Chinese only. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation when no alternative language option or locale justification is provided in the file.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The plugin states that relevant memories are automatically injected before each agent turn, but does not warn that previously stored content may re-enter prompts and influence model behavior or expose old sensitive data in new contexts. This is especially relevant for a memory skill because prompt injection, stale secrets, or cross-context leakage can arise from automatic recall even when retrieval is functioning as designed.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The skill states that relevant memories will be automatically injected before each agent turn, but it does not clearly warn users that prior stored content can influence future model behavior and may resurface sensitive information unexpectedly. In the context of a memory plugin, this can cause privacy leakage or confusing agent behavior if users do not understand that historical data is being reintroduced into prompts.

Known Vulnerable Dependency: @babel/core==7.29.0 — 1 advisory(ies): CVE-2026-49356 (@babel/core: Arbitrary File Read via sourceMappingURL Comment)

Low
Category
Supply Chain
Confidence
82% confidence
Finding
The lockfile pins @babel/core 7.29.0, which the finding reports as affected by an arbitrary file read via sourceMappingURL parsing. In this package-lock context it is a real dependency risk, but it is dev-only and typically only exposed during build/test workflows, so exploitability in the shipped skill is limited unless untrusted code or artifacts are processed in CI or local tooling.

Known Vulnerable Dependency: uuid==10.0.0 — 1 advisory(ies): CVE-2026-41907 (uuid: Missing buffer bounds check in v3/v5/v6 when buf is provided)

Low
Category
Supply Chain
Confidence
77% confidence
Finding
uuid 10.0.0 is reported as missing buffer bounds checks for certain APIs when a caller provides a buf parameter. This is a real library-level defect, but impact is usually limited because exploitation requires application code to invoke the affected UUID functions with attacker-influenced buffer arguments; a lockfile alone does not show such usage.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
  },
  "dependencies": {
    "@sinclair/typebox": "^0.34.48",
    "dotenv": "^17.2.4",
    "mem0ai": "^2.2.2",
    "openclaw": "^2026.2.9"
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "@sinclair/typebox": "^0.34.48",
    "dotenv": "^17.2.4",
    "mem0ai": "^2.2.2",
    "openclaw": "^2026.2.9"
  },
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Static analysis

No suspicious patterns detected.