Back to skill

Security audit

ClawMem

Security checks for vulnerabilities and agentic risk

Overview

ClawMem is a memory tool, but it can automatically retain full agent tool and memory event data without clear privacy controls.

Review this skill carefully before installing. Use it only if you intentionally want local long-term memory of agent sessions, tool calls, and memory writes. Treat the SQLite database as sensitive, avoid sending secrets through monitored events, and add or require redaction, retention/deletion controls, encryption or strict file permissions, and explicit opt-in before enabling lifecycle monitoring.

Vulnerability Patterns
  • 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
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
src/core/lifecycle-monitor.js:129
Finding
Unredacted Lifecycle Payloads Are Persisted in Plaintext<![CDATA[ ## Vulnerability Details **File Location**: `src/core/lifecycle-monitor.js:129-141`, `src/core/lifecycle-monitor.js:194-199`, and `database/init.js:52-62` **Vulnerability Type**: Plaintext storage of potentially sensitive event data **Risk Level**: Medium ### Vulnerable Code ```javascript // src/core/lifecycle-monitor.js:129-141 if (this._shouldStoreL2(event, payload)) { clawMem.storeL2({ record_id: recordId, full_content: JSON.stringify(payload, null, 2), metadata: { event_type: event, session_id: payload.session_id, importance: this._calculateImportance(event, payload) }, token_cost: JSON.stringify(payload).length / 4 }); } ``` ```javascript // src/core/lifecycle-monitor.js:194-199 _shouldStoreL2(event, payload) { // Store only high-value events const highValueEvents = ['memory.write', 'tool.call']; return highValueEvents.includes(event); } ``` ```javascript // database/init.js:52-62 db.exec(` CREATE TABLE IF NOT EXISTS l2_details ( id INTEGER PRIMARY KEY AUTOINCREMENT, record_id TEXT UNIQUE NOT NULL, full_content TEXT, metadata TEXT, embeddings TEXT, token_cost INTEGER DEFAULT 0, created_at INTEGER DEFAULT (strftime('%s', 'now')) ) `); ``` ### Technical Analysis The lifecycle monitor treats every `tool.call` and `memory.write` event as sufficiently valuable for L2 retention. It serializes the complete event payload with `JSON.stringify(payload, null, 2)` and passes the result to `storeL2()`, which writes it to the SQLite `full_content` text column without redaction or encryption. Tool arguments and memory-write payloads can legitimately contain API tokens, passwords, authorization headers, personal information, private prompts, uploaded content, or other confidential data. The implementation has no recursive secret filtering, field allowlist, maximum payload size, retention period, encryption control, or caller-controlled consent flag. In addition, `src/index.js ...[truncated 1719 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace full-payload serialization with an explicit allowlist of fields that are necessary for memory functionality. 2. Implement recursive redaction for common sensitive keys, including `password`, `secret`, `token`, `api_key`, `authorization`, `cookie`, and private-key material. 3. Make L2 payload capture disabled by default and require an explicit opt-in configuration setting. 4. Allow callers to mark events or individual fields as non-persistable. 5. Encrypt sensitive L2 content at rest using a key stored separately from the database. 6. Create the database and its containing directory with owner-only permissions, such as `0600` for the database and `0700` for its directory. 7. Add configurable retention limits and secure deletion or expiration of historical details. 8. Enforce a maximum serialized payload size before enqueueing or storing an event. 9. Avoid starting lifecycle monitoring as an import-time side effect. Require an explicit `start()` call by the integrating application. 10. Document which data is captured and provide controls for consent, deletion, and inspection. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
src/core/retrieval.js:120
Finding
Caller-Controlled Limits Bypass the Configured Retrieval Maximum<![CDATA[ ## Vulnerability Details **File Location**: `src/core/retrieval.js:120-123`, `src/core/search.js:24-50`, and `src/core/search.js:183-217` **Vulnerability Type**: Missing bounds validation on database query limits **Risk Level**: Low ### Vulnerable Code ```javascript // src/core/retrieval.js:120-123 if (query.limit) { sql += ' LIMIT ?'; params.push(query.limit); } ``` ```javascript // src/core/search.js:24-50 const { category, timeRange, limit = this.maxResults } = options; let sql = ` SELECT * FROM l0_index WHERE summary LIKE ? `; const params = [`%${keyword}%`]; if (category) { sql += ' AND category = ?'; params.push(category); } if (timeRange) { sql += ' AND timestamp BETWEEN ? AND ?'; params.push(timeRange.start, timeRange.end); } sql += ' ORDER BY timestamp DESC LIMIT ?'; params.push(limit); const stmt = db.prepare(sql); const results = stmt.all(...params); ``` ```javascript // src/core/search.js:183-217 const { keyword, category, tags, session_id, timeRange, event_type, includeDetails = false, limit = this.maxResults } = query; let results = []; if (keyword) { results = this.searchByKeyword(keyword, { category, timeRange, limit }); } else if (session_id) { return this.searchBySession(session_id, { includeDetails }); } else if (tags && tags.length > 0) { results = this.searchByTags(tags, { limit }); } else if (timeRange) { results = this.searchByTimeRange(timeRange, { session_id, event_type, limit }); } else { const stmt = db.prepare(` SELECT * FROM l0_index ORDER BY timestamp DESC LIMIT ? `); results = stmt.all(limit); } ``` ### Technical Analysis The configured `maxRetrieveLimit` is assigned to `this.maxResults`, but it is only used as a default value. A caller-provided `limit` replaces that default without any type, sign, integer, or upper-bound validation. SQLite interprets `LIMIT -1` as no limit. Therefore, a caller can supply `limit: -1` to request all matching rows. ...[truncated 1870 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add one centralized limit-normalization function and use it in every public retrieval and search method. ```javascript _normalizeLimit(value) { const parsed = Number(value); if (!Number.isSafeInteger(parsed) || parsed <= 0) { return this.maxResults; } return Math.min(parsed, this.maxResults); } ``` 2. Apply the normalized value before constructing every query: ```javascript const safeLimit = this._normalizeLimit(options.limit); params.push(safeLimit); ``` 3. Reject negative, zero, fractional, nonnumeric, and non-finite limits rather than relying on SQLite behavior. 4. Add explicit limits to `searchBySession()` and any other currently unbounded query. 5. Cap the total number and aggregate byte size of L2 details returned by one request. 6. Add pagination using validated `limit` and cursor values for callers that legitimately need large result sets. 7. Enforce authorization independently of result limits; a limit must not be treated as an access-control mechanism. 8. Add tests for `-1`, `0`, very large values, strings, fractional values, `Infinity`, and `NaN`. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (35)

Missing User Warnings

High
Confidence
96% confidence
Finding
The README explicitly advertises 'silent' lifecycle monitoring and background processing of agent activity, but it does not disclose what user/session data is collected, how long it is stored, or what consent controls exist. In a memory-management skill for an AI agent, this can lead to covert collection of prompts, tool inputs, and memory content that may contain secrets or personal data.

Missing User Warnings

High
Confidence
96% confidence
Finding
The listed intercepted events include session lifecycle, tool calls, and memory reads/writes, all of which can contain highly sensitive data such as prompts, credentials in tool arguments, internal memory contents, or user identifiers. Documenting interception without warning about sensitive-content capture normalizes unsafe deployment and increases the risk of unintentional surveillance or secret retention.

Credential Access

High
Category
Privilege Escalation
Content
Copy `.env.example` to `.env`:

```bash
cp .env.example .env
```

Edit configuration as needed:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
Copy `.env.example` to `.env`:

```bash
cp .env.example .env
```

Edit configuration as needed:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The supplied code does not implement the declared memory management behavior itself. It does not perform memory storage, retrieval, lifecycle monitoring, advanced search, or token-cost optimization logic. Instead, it only loads configuration from a local .env file, applies defaults, and exposes the resulting settings. While the configuration keys reference concepts like retrieval tiers and lifecycle events, this chunk’s actual behavior is limited to configuration management. That is a materially different primary purpose from the declared skill description, so this should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
86% confidence
Finding
The code substantially matches the core claim of a lightweight 3-tier memory storage/retrieval system with L0/L1/L2 layers and token-cost estimation. However, parts of the declared description overstate the implemented functionality. There is no visible automatic lifecycle monitoring (such as expiration, cleanup, state transitions, retention policies, or hooks). Search is basic rather than advanced: L0 supports simple category and timestamp filtering plus limit, while L1/L2 are direct lookups by record ID only. The 60–80% savings claim appears as a hardcoded estimate in stats and is not demonstrated by actual optimization logic or benchmarking in this code. Because these are material descriptive claims rather than minor implementation details, this is a description-behavior mismatch.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Configure Environment

```bash
cp .env.example .env
# Edit .env with your configuration
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Configure Environment

```bash
cp .env.example .env
# Edit .env with your configuration
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Configure Environment

```bash
cp .env.example .env
# Edit .env with your configuration
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
### 2. Configure Environment

```bash
cp .env.example .env
# Edit .env with your configuration
```
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
}

// 加载配置
const envConfig = parseEnvFile(join(__dirname, '..', '.env'));

// 默认配置
const defaultConfig = {
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

High
Confidence
98% confidence
Finding
The code automatically persists full event payloads to L2 using `JSON.stringify(payload, null, 2)` for `memory.write` and `tool.call`, which can include session identifiers, tool arguments, memory content, and other sensitive data. In a memory-management skill, this is especially dangerous because it creates silent long-term retention of potentially confidential prompts, outputs, and operational data without visible user consent, minimization, or redaction.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README promotes automatic interception of session, tool, and memory events, which can capture prompts, tool arguments, outputs, and other potentially sensitive user data. In a memory-management skill, this is especially risky because the feature is central to the product, yet the documentation shown does not warn about consent, retention, redaction, or privacy boundaries.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The examples encourage storing full details and performing searches over persisted memory contents, which may include sensitive prompts, API outputs, personal data, or secrets. Because this is framed as normal usage without a warning, users may unintentionally persist confidential data and later expose it through retrieval or search flows.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill describes lifecycle monitoring that intercepts OpenClaw events and stores session/tool data, but it does not prominently warn users that potentially sensitive prompts, tool arguments, or session content may be persisted. In a memory-management skill, this omission is security-relevant because users may unknowingly store secrets or private operational data.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
All headings, descriptions, and usage guidance in this file are presented in Chinese, which effectively forces a specific language for users of the skill documentation. There is no indication that this is an optional locale, nor any justification that the skill is intended only for a Chinese-language audience.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file documents `searchBySession(..., { includeDetails: true })` and shows retrieval of complete session data and L2 details, which could expose sensitive conversation contents. The guide does not include any warning about privacy, access control, or careful handling of returned session data.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The comments describe the component as 'imperceptible' and 'fully automatic' monitoring of key lifecycle events, indicating a design oriented toward undisclosed observation rather than transparent telemetry. In this skill context, which already centralizes memory and retrieval, hidden monitoring increases the risk of collecting behavioral and content data beyond user expectations.

Ssd 3

Medium
Confidence
96% confidence
Finding
The natural-language design intent emphasizes stealthy automatic interception and retention of event data, and the implementation supports that by queueing intercepted events and later storing summaries and full payload content. Even without overt exfiltration, covert capture of session and tool/memory content is a security and privacy concern because it expands the sensitive-data footprint and can expose secrets if the local database is accessed.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Comments, log strings, and returned user-facing messages in this file are written in Chinese, indicating a fixed language experience. The file does not offer opt-in language selection or document that the skill is intentionally region- or locale-specific.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The L2 storage path persists `record.full_content` and associated metadata to the database, which can include detailed user data. Although the code logs that storage occurred, there is no warning, confirmation, or comment/docstring disclosing the privacy-sensitive nature of storing complete content.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The search methods write user-controlled search terms directly to logs, and this memory system is specifically designed to store and retrieve conversational history and related metadata. In this context, keywords can include sensitive personal data, secrets, or internal identifiers, so logging them creates an unnecessary secondary exposure path through log files and observability systems.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
`advancedSearch` logs the entire query object, which may include keywords, tags, session identifiers, time ranges, categories, and other sensitive retrieval parameters. Because this component operates on a memory store for agent conversations, full-query logging can expose highly sensitive user activity and correlation data to anyone with log access.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file’s natural-language header, startup logs, and demo messaging are presented only in Chinese, which imposes a specific language on users without any visible opt-in or documented locale limitation. This matches the policy-violation category for language/locale constraints because the skill does not indicate that users may choose another language or that the skill is intentionally region-specific.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
This README is written in Chinese and serves as a user-facing skill document. Although it links to English docs, the file itself does not state a language choice or opt-in, so it may impose a locale on readers of this variant.

Static analysis

No suspicious patterns detected.