Back to skill

Security audit

Memory Router

Security checks for vulnerabilities and agentic risk

Overview

MemoryRouter is a local memory-management skill, but its destructive memory restore and tiering safety guarantees are weaker than the documentation suggests.

Review carefully before installing. Use only on a backed-up workspace, avoid custom path settings with absolute paths or .. components, run dry-run/status/audit first, and do not rely on the skill as the only backup before using --restore --force or any destructive memory operation.

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

Error
Location
memory-router.js:96
Finding

Destructive tiering continues after backup or archive write failure

Content
View full analysis
MAX_FILE_SIZE) { console.error(`[memory-router] Content too large (${content.length} bytes) for ${filepath}`); return; } // Atomic write: write to temp file, then rename ensureDir(path.dirname(filepath)); const tmpPath = resolved + '.tmp-' + process.pid; try { fs.writeFileSync(tmpPath, content, 'utf8'); fs.renameSync(tmpPath, resolved); } catch (err) { // Clean up temp file on failure try { fs.unlinkSync(tmpPath); } catch {} console.error(`[memory-router] Write failed for ${filepath}: ${err.message}`); } } ``` ```js writeSafe(backupFile, backupContent); console.log(`[memory-router] ✅ Pre-tier backup: ${backupFile} (${lineCount} lines saved)`); // ─── Actual tiering ─── const archiveDir = path.join(WORKSPACE, config.tiering.archiveDir); ensureDir(archiveDir); const archiveFile = path.join(archiveDir, `MEMORY-archive-${getToday()}.md`); let archiveContent = `# Archived Memory Sections\n\n`; archiveContent += `> Auto-archived on ${getToday()} by memory-router skill\n`; archiveContent += `> Original MEMORY.md had ...[truncated 3081 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
memory-router.js:467
Finding

Configuration-controlled directory paths are created before workspace-boundary validation

Content
View full analysis
Created ${getToday()} ${new Date().toISOString()} by memory-router skill `; backupContent += `> Original: ${lineCount} lines, ${charCount} chars `; backupContent += `> This is a full backup before tiering. Do NOT delete this file. `; backupContent += `--- `; backupContent += `---END-METADATA--- `; backupContent += content; writeSafe(backupFile, backupContent); console.log(`[memory-router] ✅ Pre-tier backup: ${backupFile} (${lineCount} lines saved)`); // ─── Actual tiering ─── const archiveDir = path.join(WORKSPACE, config.tiering.archiveDir); ensureDir(archiveDir); const archiveFile = path.join(archiveDir, `MEMORY-archive-${getToday()}.md`); ``` The directory helper performs recursive creation without validation: ```js function ensureDir(dir) { if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); } ``` ### Technical Analysis The `backupDir` and `archiveDir` values are loaded from `config.json` and joined with the workspace path. Traversal components such as `../../outside` can cause the normalized path to escape the workspace. Although `writeSafe()` validates the eventual file path and rejects writes outside the workspace, `ensureDir()` is called first and does not perform equivalent validation. Recursive `mkdirSync()` can therefore create one or more directories outside the intended workspace boundary before the subse ...[truncated 1584 chars]
Remediation
View remediation
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · INSTALL.md (reported line 12)May include surrounding context.

Quick Install (1 minute)

bash
# 1. Create the skill directory
mkdir -p ~/.openclaw/workspace/skills/memory-router

# 2. Copy the skill files

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · INSTALL.md (reported line 140)May include surrounding context.

"No MEMORY.md found"

Create one:

bash
echo "# MEMORY.md - Long-Term Memory" > ~/.openclaw/workspace/MEMORY.md

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The design principles claim the tool generates reports and that 'nothing is silently deleted'. Earlier safety documentation explicitly states that archived files older than retentionDays are candidates for deletion and that this deletion is irreversible. That is an active contradiction in the skill's own intent and safety messaging.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The design principles state the system is 'Reversible' because original content is preserved in archives. However, the retention section explicitly warns that archived files may be deleted irreversibly after the configured retention period. This directly contradicts the claim that the system is reversible.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comments at L0479 and L0497 describe creating a full pre-tier backup and then proceeding with actual tiering, but the code declares const backupContent and then repeatedly appends to it, which would throw at runtime on the first reassignment. This means the documented safety backup flow does not occur as described, creating a direct contradiction between the inline intent and actual executable behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

This code performs a destructive file overwrite of MEMORY.md during restore. Although it logs warnings and requires a --force flag, there is no interactive confirmation prompt before the irreversible write, which is a weaker safeguard for a safety-critical operation affecting user data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The heartbeat guidance states that --tier --dry-run is 'side-effect free (no files created)'. Elsewhere, the configuration and feature description say tiering can auto-generate memory/memory-manifest.json via generateOnTier, which creates ambiguity about whether tier-related commands may write generated output. This is a documentation-level contradiction about operational side effects.

Content

No source excerpt is available for this finding.