Back to skill

Security audit

memory-compact

Security checks for vulnerabilities and agentic risk

Overview

This memory backup skill is mostly purpose-aligned, but it creates recurring agent runs and writes raw conversation-derived content into persistent memory while overstating its safety.

Review this skill before installing or enabling its cron job. It does not show network exfiltration or hidden remote payloads, but it will process sensitive OpenClaw memory, append selected lines into long-term MEMORY.md, move source files into backups, and may run every day if the cron command is added. Install only if you are comfortable with automatic memory promotion, and consider adding review, deletion, cron removal, symlink-safe path checks, and clearer timezone/language configuration first.

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 (3)

T06 · System Persistence

Error
Location
SKILL.md:114
Finding
Recurring Agent Task Creates Cross-Session Persistence<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:114-136` and `README.md:119-141` **Vulnerability Type**: T06: System Persistence **Risk Level**: High ### Complete Code Snippet ```bash cron add --job '{ "name": "memory-compact Daily Backup", "schedule": { "kind": "cron", "expr": "30 6 * * *", "tz": "Asia/Shanghai" }, "payload": { "kind": "agentTurn", "message": "Run /root/.openclaw/workspace/skills/memory-compact/wrapper.py to process the daily memory backup", "timeoutSeconds": 60 }, "sessionTarget": "isolated", "enabled": true, "delivery": { "mode": "announce" } }' ``` The displayed snippet is an English rendering of the operational cron configuration in both documentation files; the executable path, schedule, payload type, timeout, session target, and enabled state are unchanged. ### Technical Analysis The installation instructions direct the user to register an enabled OpenClaw cron job. Its `agentTurn` payload launches the Skill every day at 06:30 in the `Asia/Shanghai` time zone. Unlike a one-time Skill invocation, the scheduled task survives the current run and repeatedly creates new Agent turns. Those turns execute `wrapper.py`, which invokes `memory_backup.py` and grants it recurring access to workspace memory files. The persistence mechanism is disclosed in the documentation, but it remains a security-sensitive cross-session modification. The instructions do not provide a corresponding removal command, expiration policy, per-run approval requirement, or least-privilege limitation. ### Attack Path 1. A user installs the Skill and follows the cron setup instructions. 2. OpenClaw registers the enabled recurring `agentTurn` job. 3. The cron entry remains active after the installation session ends. 4. At each scheduled time, a new isolated Agent turn is initiated. 5. The turn runs `wrapper.py`, which launches `memory_backup.py`. 6. The process reads conversation-derived memory, modifies lo ...[truncated 629 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic cron-registration instructions from the default installation workflow. 2. Require explicit, informed opt-in before creating any persistent scheduled task. 3. Show the exact schedule, executable, affected files, and execution privileges before confirmation. 4. Provide a documented command that disables and removes the cron job. 5. Consider expiration after a limited number of runs rather than indefinite persistence. 6. Prefer a narrowly scoped local scheduler that runs the Python program directly instead of creating autonomous Agent turns. 7. Require per-run approval before reading conversation memory or changing `MEMORY.md`. 8. Record each execution and memory modification in an auditable log. ]]>

T02 · Agent Memory Poisoning

Error
Location
memory_backup.py:147
Finding
Conversation Content Is Copied Verbatim into Persistent Agent Memory<![CDATA[ ## Vulnerability Details **File Location**: `memory_backup.py:147-184` **Vulnerability Type**: T02: Agent Memory Poisoning **Risk Level**: High ### Complete Code Snippet ```python def extract_key_points(content): """ Use rules to extract key points. """ lines = content.split("\n") key_points = [] keywords = ["decide", "like", "dislike", "remember", "important", "plan", "goal"] for line in lines: line = line.strip() if not line or len(line) <= 10: continue if any(keyword in line for keyword in keywords): key_points.append(line) if len(key_points) >= 3: break if not key_points: for line in lines: line = line.strip() if line and len(line) > 20: key_points.append(line) if len(key_points) >= 3: break return key_points[:3] def append_to_memory_md(key_points): """Append key points to MEMORY.md.""" date_str = get_yesterday_date_str() try: with open(MEMORY_MD, "a", encoding="utf-8") as f: f.write(f"## {date_str}\n") for i, point in enumerate(key_points, 1): f.write(f"{i}. {point}\n") f.write("\n") return True ``` The keyword literals and comments above are translated for readability. The audited implementation performs the same raw string matching and verbatim append operations. ### Technical Analysis `extract_key_points()` treats conversation-derived text as ordinary strings but does not establish whether the selected lines are trustworthy. Any matching line is added directly to `key_points`. If no keyword matches, the fallback accepts the first three nonempty lines longer than 20 characters. `append_to_memory_md()` then writes each selected line verbatim into the persistent `MEMORY.md` file. The implementation does not: - distinguish factual memory from instructions; - dete ...[truncated 1720 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not copy raw conversation lines into trusted long-term Agent context. 2. Store extracted information in a structured data format with explicit fields for content, source, timestamp, and trust level. 3. Treat all conversation-derived values as untrusted data rather than executable instructions. 4. Reject or quarantine imperative statements, role changes, tool-use directives, safety-policy changes, and other prompt-like content. 5. Require explicit user approval before promoting extracted content into long-term memory. 6. Escape or delimit stored text so the Agent can distinguish quoted historical data from governing instructions. 7. Replace keyword extraction with a constrained schema validator that only permits narrowly defined fact categories. 8. Deduplicate entries and provide a review and deletion interface for persisted memory. 9. Configure future Agent sessions not to treat memory records as higher-priority instructions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
memory_backup.py:121
Finding
Symlink Following Can Redirect Persistent Writes and Backup Moves Outside the Workspace<![CDATA[ ## Vulnerability Details **File Location**: `memory_backup.py:121-132`, `memory_backup.py:174-184`, and `memory_backup.py:193-208` **Vulnerability Type**: T09: Insecure Skill Coding Practices **Risk Level**: Medium ### Complete Code Snippet ```python def create_memory_md(): """Create an empty MEMORY.md if it does not exist.""" if not os.path.exists(MEMORY_MD): try: with open(MEMORY_MD, "w", encoding="utf-8") as f: f.write("# MEMORY - Long-term memory\n\n") print("Created MEMORY.md") except PermissionError: print("Unable to create MEMORY.md: insufficient permission") except Exception as e: print(f"Unable to create file: {e}") def append_to_memory_md(key_points): """Append key points to MEMORY.md.""" date_str = get_yesterday_date_str() try: with open(MEMORY_MD, "a", encoding="utf-8") as f: f.write(f"## {date_str}\n") for i, point in enumerate(key_points, 1): f.write(f"{i}. {point}\n") f.write("\n") return True except PermissionError: print("Unable to write MEMORY.md: insufficient permission") return False except Exception as e: print(f"Unable to write file: {e}") return False def backup_file(file_path): """Move the file to the backup directory.""" try: ensure_directory(BACKUP_DIR) file_name = os.path.basename(file_path) dest_path = os.path.join(BACKUP_DIR, file_name) if not is_safe_path(BACKUP_DIR, dest_path): print("Unsafe backup path; operation refused") return None os.rename(file_path, dest_path) return dest_path ``` The messages and comments above are translated for readability. The file-opening, path-validation, and rename operations are unchanged from the audited implementation. ### Technical Analysis There are two related symlink weaknesses. F ...[truncated 2649 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve and validate `WORKSPACE_ROOT` once, then validate every source and destination against that root immediately before access. 2. Reject `MEMORY_MD`, `BACKUP_DIR`, source files, and destination files if any relevant path component is a symbolic link. 3. Use `os.lstat()` to inspect path components without following symlinks. 4. On supported platforms, open files with `os.open()` and `O_NOFOLLOW`, then wrap the resulting descriptor with `os.fdopen()`. 5. Open and operate on directories through trusted directory descriptors and use descriptor-relative APIs where available. 6. Validate that the resolved `BACKUP_DIR` is itself within the resolved `WORKSPACE_ROOT`; do not use a potentially attacker-controlled directory as the sole trust root. 7. Revalidate path identity immediately before mutation to reduce time-of-check/time-of-use exposure. 8. Create directories with restrictive permissions and verify ownership before writing. 9. Use atomic write and move operations and fail closed if any path or ownership check cannot be completed. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
This second mismatch finding is also valid: the skill presents itself as a memory-processing feature, but the visible content indicates a generic wrapper entrypoint that may launch external code via python/script dispatch without declaring that execution model. Hidden indirection through wrapper scripts increases risk because the real logic and side effects may exist outside the reviewed file.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
This second mismatch finding is also valid: the skill presents itself as a memory-processing feature, but the visible content indicates a generic wrapper entrypoint that may launch external code via python/script dispatch without declaring that execution model. Hidden indirection through wrapper scripts increases risk because the real logic and side effects may exist outside the reviewed file.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The skill documentation presents the skill entirely in Chinese and labels it with a Chinese title, while the scheduled configuration later hard-codes the Asia/Shanghai timezone. There is no indication that users may choose another language or locale, nor any explanation that the skill is intended only for a China-specific environment.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README describes an automated daily job that reads prior memory files, appends extracted content into a long-term memory file, and creates backups, but it does not present this as a clear user-facing privacy/data-handling warning. Because the data involved is memory content, the lack of explicit disclosure and consent can cause silent collection, retention, and duplication of potentially sensitive information.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看备份文件

```bash
ls -la ~/.openclaw/workspace/backup/memory/
```

### 查看提取结果
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看备份文件

```bash
ls -la ~/.openclaw/workspace/backup/memory/
```

### 查看提取结果
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看备份文件

```bash
ls -la ~/.openclaw/workspace/backup/memory/
```

### 查看提取结果
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看备份文件

```bash
ls -la ~/.openclaw/workspace/backup/memory/
```

### 查看提取结果
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

File System Enumeration

Medium
Category
Data Exfiltration
Content
### 查看备份文件

```bash
ls -la ~/.openclaw/workspace/backup/memory/
```

### 查看提取结果
Confidence
60% confidence
Finding
Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares no explicit tool scope or permissions, yet its documentation describes capabilities equivalent to reading files, writing files, and invoking scripts via shell/python execution. This creates an authorization and review gap: operators cannot accurately assess what the skill is allowed to do, and a wrapper script could perform broader actions than users expect.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The skill description and all user-facing documentation are written exclusively in Chinese, including operational instructions and example output. This imposes a specific language/locale on users without any stated opt-in, fallback, or note that the skill is intended only for a Chinese-speaking or China-region context.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The security claims are inaccurate: the script says all file operations are restricted to the workspace, but it writes to MEMORY.md in create_memory_md() and append_to_memory_md() before any explicit path validation. Because WORKSPACE_ROOT is derived from the current user's home directory and then trusted globally, a manipulated environment, symlinked path, or unexpected filesystem layout could cause reads or writes outside the intended workspace boundary, making the documented safety guarantee unreliable.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill description says '自动压缩备份' (automatic compressed backup), which implies creating a compressed archive or compacted backup artifact. The implementation in backup_file() merely renames the original markdown file into a backup folder, with no compression logic at all.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The package description is written only in Chinese ("每日记忆自动压缩备份和关键点提取"), which imposes a specific language for understanding the skill metadata. The file does not indicate that language choice is optional or that the skill is intended only for a Chinese-speaking or region-specific audience.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The docstring states that the wrapper 'does not include ... subprocess' and 'does not perform dangerous operations,' yet the module imports subprocess and later uses subprocess.run to launch memory_backup.py. This is an active contradiction between the inline security description and the implementation, not merely an omitted detail.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        # 执行目标脚本
        result = subprocess.run(
            [sys.executable or "python3", SCRIPT_PATH],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The cron configuration fixes the locale-sensitive timezone to Asia/Shanghai, which can violate language/locale policy when presented as the default behavior without offering alternatives. The README does not explain that the skill is limited to that region or tell users to adjust the timezone to their own locale.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
This Python file includes its main docstring and operational messages primarily in Chinese, and does not indicate any user option to select another language. That can violate a language/locale policy when a skill is expected to avoid forcing a specific language without user opt-in.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The documentation minimizes the wrapper as 'only an entry point,' but the code performs process execution control, timeout handling, working-directory selection, and output forwarding. While related to wrapping, the documentation's safety framing understates these concrete side effects and execution capabilities.

Static analysis

No suspicious patterns detected.