Back to skill

Security audit

Memory Archiver

Security checks for vulnerabilities and agentic risk

Overview

This memory skill is locally scoped and purpose-aligned, but it automatically persists and reinjects conversation content through persistent hooks and cron jobs without strong user controls.

Review this skill carefully before installing. It is not showing network theft or destructive behavior, but it will create persistent local memory, session notes, hooks, and scheduled jobs that can retain sensitive prompt content and bring old memory back into future conversations. Install only if you want automatic local conversation memory, and be prepared to disable the hook and cron jobs and clean the memory files if needed.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (5)

T02 · Agent Memory Poisoning

Error
Location
hooks/handler.js:286
Finding
Persistent memory poisoning through verbatim message storage and context injection<![CDATA[ ## Vulnerability Details **File Location**: `hooks/handler.js:286-296`; `scripts/memory-extract.js:91-113`; `scripts/auto-memory-search.js:216-220` **Vulnerability Type**: Persistent prompt injection through agent memory **Risk Level**: High ### Vulnerable Code ```js // hooks/handler.js:286-296 console.log(`[MemorySearch] Detected message type: ${msgType}`); const searchResults = await searchMemory(userMessage); if (searchResults) { event.messages.push(`📚 Relevant memory:\n${searchResults}`); console.log('[MemorySearch] Memory injected'); } // Automatic memory extraction in the background console.log('[MemoryExtract] Triggering background memory extraction'); extractMemoryAsync(userMessage); ``` ```js // scripts/memory-extract.js:91-113 function writeMemory(type, title, content, tags = []) { ensureDirs(); if (isDuplicate(type, content)) { return { success: false, reason: 'duplicate' }; } const filename = generateFilename(type, title); const filepath = path.join(MEMORY_DIR, type, filename); const now = new Date().toISOString().split('T')[0]; const memoryContent = `--- type: ${type} created: ${now} tags: [${tags.join(', ')}] --- # ${title} ${content} `; fs.writeFileSync(filepath, memoryContent, 'utf8'); ``` ```js // scripts/auto-memory-search.js:216-220 if (allResults.length === 0) { console.log('📭 No related memory found'); } else { console.log('\n✅ Multi-dimensional memory search completed\n'); console.log(allResults.join('\n\n')); console.log('\n---\nThe memory above is for reference; cite it as appropriate'); } ``` ### Technical Analysis Every eligible user message is passed to `memory-extract.js`, which stores the message body verbatim in a persistent Markdown file. The retrieval code subsequently prints matching stored text without sanitization, and the message hook appends that output directly to `event.messages`. There is no separation between trusted instructions and untrusted recalled data. The im ...[truncated 1740 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not inject raw memory text into an instruction-bearing message list. 2. Store structured, minimal facts rather than complete messages. 3. Reject or quarantine content containing imperative instructions, role changes, safety overrides, tool-use directives, or prompt-injection indicators. 4. Preserve provenance, author, timestamp, and trust level for every memory item. 5. Present retrieved memory as explicitly quoted, untrusted data through a dedicated data channel. 6. Require explicit user approval before creating durable memories. 7. Apply retrieval allowlists and relevance thresholds rather than broad keyword matching. 8. Add tests demonstrating that stored instructions cannot alter later agent behavior. 9. Provide controls to inspect, edit, quarantine, and delete stored memories. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
hooks/handler.js:260
Finding
Automatic plaintext retention of potentially sensitive user messages<![CDATA[ ## Vulnerability Details **File Location**: `hooks/handler.js:260-296`; `scripts/memory-extract.js:102-113` **Vulnerability Type**: Unfiltered sensitive-data persistence **Risk Level**: High ### Vulnerable Code ```js // hooks/handler.js:260-296 if (event.type !== 'message' || event.action !== 'received') { return; } const userMessage = event.context?.content || event.message?.text || ''; if (!userMessage) { console.log('[MemoryArchiver] No message content'); return; } // Skip selected system messages, cron messages, and heartbeat messages if (userMessage.startsWith('System:') || userMessage.includes('memory timely-write check') || userMessage.includes('work progress check') || userMessage.includes('error monitoring check') || userMessage.includes('full work monitoring') || userMessage.includes('automatic token usage record') || userMessage.includes('HEARTBEAT')) { console.log('[MemoryArchiver] Skipping system/cron/heartbeat'); return; } // Automatic memory extraction in the background console.log('[MemoryExtract] Triggering background memory extraction'); extractMemoryAsync(userMessage); ``` ```js // scripts/memory-extract.js:102-113 const memoryContent = `--- type: ${type} created: ${now} tags: [${tags.join(', ')}] --- # ${title} ${content} `; fs.writeFileSync(filepath, memoryContent, 'utf8'); ``` ### Technical Analysis The hook applies only a small system-message exclusion list. All other received message content is forwarded to the extractor, including messages that may contain passwords, API tokens, private keys copied into a prompt, personal information, confidential project data, or proprietary source material. The extractor writes the complete message to a plaintext Markdown file. It does not perform secret detection, personal-data redaction, field minimization, encryption, access-control validation, or a user-consent check. The file is created without an explicit restrictive mode, leaving its final ...[truncated 1156 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make memory persistence opt-in and visibly indicate when a message will be retained. 2. Extract only explicitly approved facts instead of storing complete message bodies. 3. Detect and redact common credentials, authorization headers, private keys, connection strings, personal identifiers, and payment information. 4. Add a user command or API for marking a message as non-persistent. 5. Create memory files with mode `0600` and memory directories with mode `0700`. 6. Define and enforce a retention period, secure deletion procedure, and per-item deletion mechanism. 7. Keep sensitive memories out of broad keyword-search results. 8. Add automated tests confirming that representative secrets are neither stored nor returned. ]]>

T06 · System Persistence

Error
Location
scripts/install.js:45
Finding
Automatic installation of persistent hooks and recurring main-session jobs<![CDATA[ ## Vulnerability Details **File Location**: `skill.json:19-21`; `scripts/install.js:45-60`; `scripts/install.js:76-116` **Vulnerability Type**: Automatic cross-session persistence **Risk Level**: High ### Vulnerable Code ```json // skill.json:19-21 "scripts": { "postinstall": "node scripts/install.js" } ``` ```js // scripts/install.js:45-60 fs.mkdirSync(HOOKS_DIR, { recursive: true }); fs.copyFileSync(handlerJs, path.join(HOOKS_DIR, 'handler.js')); fs.copyFileSync(hookMd, path.join(HOOKS_DIR, 'HOOK.md')); const listOutput = execSync('openclaw hooks list 2>/dev/null', { encoding: 'utf8' }); if (!listOutput.includes('memory-archiver-hook')) { const oldHookDir = path.join( process.env.HOME, '.openclaw', 'hooks', 'memory-archiver-hook' ); try { fs.rmSync(oldHookDir, { recursive: true, force: true }); } catch {} execSync(`openclaw hooks install --link "${HOOKS_DIR}"`, { stdio: 'pipe' }); } ``` ```js // scripts/install.js:86-116 const cronJobs = [ { name: 'Memory timely write', schedule: '{"kind":"every","everyMs":600000}', payload: '{"kind":"systemEvent","text":"Memory timely-write check (silent mode)"}' }, { name: 'Memory archive - Daily', schedule: '{"kind":"cron","expr":"0 23 * * *","tz":"Asia/Shanghai"}', payload: '{"kind":"systemEvent","text":"Daily memory archive time"}' }, { name: 'Memory summary - Weekly', schedule: '{"kind":"cron","expr":"0 22 * * 0","tz":"Asia/Shanghai"}', payload: '{"kind":"systemEvent","text":"Weekly memory summary time"}' } ]; for (const job of cronJobs) { execSync( `openclaw cron add --name "${job.name}" ` + `--schedule '${job.schedule}' --payload '${job.payload}' ` + `--session-target main --delivery '{"mode":"none"}'`, { stdio: 'pipe' } ); } ``` ### Technical Analysis Package installation automatically executes `scripts/install.js`. That script copies a message-processing hook into the workspace, registers it ...[truncated 1403 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic hook and cron registration from `postinstall`. 2. Prompt separately for permission to install the message hook and each scheduled job. 3. Display the exact event scope, retained data, schedule, and session target before activation. 4. Default scheduled tasks to an isolated session instead of the main session. 5. Add an uninstall command that disables and removes registered hooks, cron jobs, copied files, and generated state. 6. Track installed resource identifiers so cleanup does not rely on name matching. 7. Make installation idempotent using exact identifiers rather than counting unrelated job names. 8. Document how users can pause or disable all persistent behavior. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install.js:18
Finding
Shell command injection through environment-derived installation paths<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.js:18-20,50-60`; `scripts/auto-memory-search.js:170-173`; `scripts/memory-refresh.js:37-40`; `scripts/memory-search.js:47-50` **Vulnerability Type**: Shell command injection **Risk Level**: Medium ### Vulnerable Code ```js // scripts/install.js:18-20 const WORKSPACE = path.join(process.env.HOME, '.openclaw', 'workspace'); const SKILL_DIR = path.join(WORKSPACE, 'skills', 'memory-archiver'); const HOOKS_DIR = path.join(WORKSPACE, 'hooks', 'memory-archiver-hook'); ``` ```js // scripts/install.js:50-60 const listOutput = execSync( 'openclaw hooks list 2>/dev/null', { encoding: 'utf8' } ); execSync( `openclaw hooks install --link "${HOOKS_DIR}"`, { stdio: 'pipe' } ); ``` ```js // scripts/auto-memory-search.js:170-173 if (!fs.existsSync(SESSION_STATE)) { const loaderPath = path.join(__dirname, 'memory-loader.js'); if (fs.existsSync(loaderPath)) { try { execSync(`node "${loaderPath}"`, { stdio: 'pipe' }); } catch {} } } ``` ```js // scripts/memory-refresh.js:37-40 const loaderPath = path.join(__dirname, 'memory-loader.js'); if (fs.existsSync(loaderPath)) { require('child_process').execSync( `node "${loaderPath}"`, { stdio: 'inherit' } ); } ``` ### Technical Analysis `execSync()` executes a command string through a shell. The code interpolates `HOOKS_DIR` and `loaderPath` into those strings. These paths are derived from `HOME` or the Skill installation directory and are not validated before shell interpretation. Double quotes do not neutralize all shell syntax. For example, command substitution using `$()` remains active inside double quotes, and an embedded quote can terminate the quoted argument. Therefore, a crafted environment or installation path can introduce shell syntax. The practical precondition is that an attacker can influence `HOME`, the installation directory, or the execution environment. Under ordinary single-user installations this ma ...[truncated 838 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace shell command strings with `execFileSync()` or `spawnSync()` and explicit argument arrays. 2. Use code equivalent to: ```js execFileSync( 'openclaw', ['hooks', 'install', '--link', HOOKS_DIR], { stdio: 'pipe' } ); execFileSync( process.execPath, [loaderPath], { stdio: 'pipe' } ); ``` 3. Replace shell redirection such as `2>/dev/null` with Node.js `stdio` configuration. 4. Validate that resolved paths remain under the expected workspace or package root. 5. Reject paths containing null bytes and avoid relying on manual shell quoting. 6. Add tests using paths containing spaces, quotes, dollar signs, backticks, and command-substitution syntax. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dream-consolidate.js:61
Finding
JavaScript maintenance scripts are incorrectly executed by Bash<![CDATA[ ## Vulnerability Details **File Location**: `hooks/bootstrap-loader/handler.js:23-35`; `scripts/dream-consolidate.js:61-94,228-237` **Vulnerability Type**: Incorrect interpreter selection and ineffective concurrency protection **Risk Level**: Medium ### Vulnerable Code ```js // hooks/bootstrap-loader/handler.js:23-35 const homeDir = process.env.HOME || '/root'; const workspaceDir = path.join(homeDir, '.openclaw', 'workspace'); const scriptPath = path.join( workspaceDir, 'skills', 'memory-archiver', 'scripts', 'memory-loader.js' ); if (!fs.existsSync(scriptPath)) { console.log('[MemoryBootstrapLoad] Script does not exist:', scriptPath); return; } const { stdout, stderr } = await execAsync(`bash "${scriptPath}"`); ``` ```js // scripts/dream-consolidate.js:61-94 const LOCK_SCRIPT = path.join(__dirname, 'dream-lock.js'); function tryLock() { try { const result = execSync( `bash "${LOCK_SCRIPT}" "${MEMORY_DIR}" acquire`, { encoding: 'utf8', timeout: 5000 } ).trim(); return result.startsWith('ACQUIRED') || result.startsWith('FORCED'); } catch (e) { return false; } } function releaseLock() { execSync( `bash "${LOCK_SCRIPT}" "${MEMORY_DIR}" release`, { encoding: 'utf8', timeout: 5000 } ); } function checkLock() { const result = execSync( `bash "${LOCK_SCRIPT}" "${MEMORY_DIR}" check`, { encoding: 'utf8', timeout: 5000 } ).trim(); return result.startsWith('FREE'); } ``` ```js // scripts/dream-consolidate.js:228-237 if (fs.existsSync(MEMORY_DEDUP)) { const dedupOutput = execSync( `bash "${MEMORY_DEDUP}"`, { encoding: 'utf8', timeout: 30000 } ).trim(); report.dedupDone = true; } ``` ### Technical Analysis The referenced files are JavaScript programs with Node.js shebangs, but the callers explicitly invoke `bash`. Bash will attempt to parse JavaScript syntax and terminate with errors. In the consol ...[truncated 1642 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Execute JavaScript files with Node.js rather than Bash. 2. Use `process.execPath` and argument arrays: ```js execFileSync( process.execPath, [LOCK_SCRIPT, MEMORY_DIR, 'acquire'], { encoding: 'utf8', timeout: 5000 } ); ``` 3. Invoke `memory-loader.js` and `memory-dedup.js` in the same manner. 4. Add integration tests for lock acquisition, lock release, concurrent consolidation, bootstrap loading, and deduplication. 5. Fail closed with a clear error if a lock cannot be acquired. 6. Register the bootstrap hook only after confirming its interpreter and installation behavior work correctly. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (59)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Manual CLI search invoking a separate loader script is a notable behavioral detail if it is undeclared, because chained script execution increases complexity and can surprise operators about what code runs when a simple search command is used. In a local-skill context this is less severe than remote code execution, but it still affects transparency and reviewability.

Vague Triggers

High
Confidence
95% confidence
Finding
The hook is registered for every `message:received` event and the documented trigger terms are so broad that ordinary conversation is likely to activate memory search. This creates excessive collection and context injection behavior, increasing the chance that unrelated or sensitive prior data is surfaced without clear user intent or narrow scoping.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill states that it automatically extracts persistent memory from every user message and writes session notes, yet no notice, consent, retention limit, or opt-out is described. This is dangerous because users may disclose secrets, personal data, or project-sensitive information that gets silently persisted and later reused or exposed.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill advertises installation and automated hook/cron behavior that imply environment and execution capabilities, but it declares no explicit tool scope or permissions. In a security-sensitive agent ecosystem, missing capability declarations weakens user consent and policy enforcement because the skill can access local workspace state and invoke surrounding tooling without transparent scoping.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
A skill that automatically captures, searches, summarizes, and persists conversation content via hooks and cron jobs creates a significant privacy and data-governance risk if that collection is not disclosed prominently. Users may reveal sensitive information under the assumption of ephemeral processing, while the skill silently stores it in workspace memory files for later retrieval or injection.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The installation steps describe automatic hook deployment and cron registration, but do not prominently warn that this enables ongoing background persistence and automated file modifications. In context, that makes the skill more dangerous because it is not just an on-demand utility; it becomes a persistent component that can continuously process and store user conversations.

Natural-Language Policy Violations

Medium
Confidence
79% confidence
Finding
Natural-language instructions and descriptions throughout the file are presented in Chinese, with no indication that the user can select another language or that the skill is intentionally restricted to a Chinese-speaking context. This can violate a language/locale policy when a skill forces a specific language without user opt-in.

Ssd 3

Medium
Confidence
96% confidence
Finding
Automatically extracting and storing content from every user message creates a persistent data retention risk, because free-form chat often contains personal, confidential, or security-relevant information. Once stored in categorized memory paths, that information may be unintentionally retrieved, leaked to later contexts, or retained longer than necessary.

Ssd 3

Medium
Confidence
95% confidence
Finding
Persistent session-note logging of ongoing conversations creates a continuous transcript trail that can accumulate sensitive user and project information. Even if intended for convenience, such logs expand the attack surface and raise the risk of unauthorized disclosure, over-retention, and cross-session privacy leakage.

Missing User Warnings

Medium
Confidence
80% confidence
Finding
The hook is designed to auto-load memory into `SESSION-STATE.md` cache during bootstrap, meaning session state is updated implicitly before the user takes action. While this aligns with the skill's memory-management purpose, silent mutation of session context can affect privacy, auditability, and user expectations if prior memory is injected without clear notice.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The bootstrap hook implicitly spawns a shell via `bash` during agent startup, which increases attack surface because startup execution happens automatically and without user review. Even though the script path is hardcoded under the skill workspace, any compromise or unexpected modification of that script results in arbitrary code execution every time the agent boots.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This hook performs subprocess execution automatically on `agent:bootstrap` with no user-facing warning or consent. Silent execution at startup is risky because it creates a persistence-like mechanism: users may not realize code is being run, and any malicious change to the invoked script will execute repeatedly and implicitly.

Ssd 3

Medium
Confidence
96% confidence
Finding
The documented behavior combines automatic memory search, memory extraction, and session-note tracking over all received messages, meaning user-provided content is broadly retained and reused across multiple persistence and retrieval paths. In a memory-management skill this context makes the issue more dangerous, not less, because the entire purpose is to capture and later surface prior conversation data, increasing the chance of unintended disclosure of sensitive information into future prompts or local files.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/auto-memory-search.js:173

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/dream-consolidate.js:65

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/install.js:52

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/memory-refresh.js:40

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/memory-search.js:50