Back to skill

Security audit

PV_21

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a resource-efficiency persona, but it adds automatic cross-session memory that stores user information locally without clear consent, limits, or deletion controls.

Review this skill carefully before installing. It may automatically save things you say, including preferences and decisions, to a local plaintext memory file and reuse them in future sessions. Only use it if you are comfortable with persistent memory, and prefer a version with explicit opt-in, review, delete, retention, and sensitive-data filtering controls.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:43
Finding
Automatic Plaintext Persistence of Potentially Sensitive User Data<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 43–69 and 108–116 **Vulnerability Type**: Plaintext sensitive-data storage without explicit consent or retention controls **Risk Level**: Medium ### Vulnerable Code ```python PALACE_PATH = os.path.expanduser("~/.openclaw/pv_palace/") def store_memory(content, importance=5, tags=None): """Store memory in the local palace""" os.makedirs(PALACE_PATH, exist_ok=True) path = os.path.join(PALACE_PATH, "memories.json") data = {"memories": [], "index": {}} if not os.path.exists(path) else json.load(open(path)) mem_id = hashlib.sha256(f"{content}{datetime.now().isoformat()}".encode()).hexdigest()[:12] memory = {"id": mem_id, "content": content, "importance": importance, "tags": tags or [], "created_at": datetime.now().isoformat()} data["memories"].append(memory) for tag in (tags or []): data["index"].setdefault(tag, []).append(mem_id) json.dump(data, open(path, 'w'), ensure_ascii=False, indent=2) return f"✓ Memory stored ({importance}/10)" ``` The documented automatic-storage behavior includes: ```text | User expresses a preference | Automatically call store_memory(content, importance=8, tags=["preference"]) | | Important decision | Automatically call store_memory(decision, importance=9, tags=["decision"]) | | New session starts | Automatically call get_context() to load memory | ``` ### Technical Analysis The skill instructs the agent to automatically retain user preferences, decisions, and other conversational information. The content is serialized directly into `~/.openclaw/pv_palace/memories.json` as plaintext JSON. No explicit user opt-in, sensitivity filtering, retention period, deletion mechanism, encryption, or restrictive file mode is defined. `os.makedirs()` and `open()` rely on the host process's default permission and `umask` configuration, which may not provide the confidentiality expected for persi ...[truncated 1496 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require explicit, informed user consent before persisting any conversational information. 2. Disable automatic storage by default and provide per-item confirmation. 3. Reject secrets, credentials, financial data, health data, and other sensitive categories. 4. Store structured facts rather than unrestricted raw conversation text. 5. Create the storage directory and file with explicit owner-only permissions, such as directory mode `0700` and file mode `0600`. 6. Encrypt persistent memory at rest using a key managed separately from the data file. 7. Add configurable retention limits, automatic expiration, and user-facing list, export, and deletion controls. 8. Use atomic file replacement and locking to prevent corruption and concurrent-write data loss. 9. Clearly disclose the storage path, stored fields, retention period, and cross-session loading behavior. 10. Handle malformed or corrupted JSON safely rather than allowing it to terminate memory operations. ]]>

T02 · Agent Memory Poisoning

Error
Location
SKILL.md:53
Finding
Persistent Memory Poisoning Through Unsanitized Conversation Content<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 53–68 and 90–116 **Vulnerability Type**: Untrusted content persisted and automatically reintroduced into future agent context **Risk Level**: High ### Vulnerable Code The storage function accepts and preserves arbitrary content without distinguishing factual data from instructions: ```python def store_memory(content, importance=5, tags=None): """Store memory in the local palace""" os.makedirs(PALACE_PATH, exist_ok=True) path = os.path.join(PALACE_PATH, "memories.json") data = {"memories": [], "index": {}} if not os.path.exists(path) else json.load(open(path)) mem_id = hashlib.sha256(f"{content}{datetime.now().isoformat()}".encode()).hexdigest()[:12] memory = {"id": mem_id, "content": content, "importance": importance, "tags": tags or [], "created_at": datetime.now().isoformat()} data["memories"].append(memory) for tag in (tags or []): data["index"].setdefault(tag, []).append(mem_id) json.dump(data, open(path, 'w'), ensure_ascii=False, indent=2) return f"✓ Memory stored ({importance}/10)" ``` The context function then selects entries according to attacker-influenced importance and returns their raw content for future use: ```python def get_context(limit=10): """Get memory context""" path = os.path.join(PALACE_PATH, "memories.json") if not os.path.exists(path): return "No memories" data = json.load(open(path)) memories = sorted(data["memories"], key=lambda x: x.get("importance", 0), reverse=True)[:limit] lines = ["=== Memory Context ==="] for m in memories: imp = "⭐" * min(m.get("importance", 5), 5) tags = ", ".join(m.get("tags", [])[:3]) lines.append(f"{imp} {m['content'][:60]}") if tags: lines.append(f" [{tags}]") return "\n".join(lines) ``` The documented lifecycle explicitly calls for this data to be loaded ...[truncated 2941 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never inject raw persistent-memory text into the agent's instruction context. 2. Store only structured, narrowly typed facts with fields such as subject, attribute, value, provenance, owner, consent status, and expiration time. 3. Treat every memory entry as untrusted data and explicitly delimit it from system, developer, and skill instructions. 4. Reject or quarantine imperative language, role-change requests, tool directives, safety-override language, and references to hidden prompts or credentials. 5. Do not allow conversational input to control importance directly; calculate ranking through trusted application logic. 6. Require user confirmation before storing high-importance or cross-session memories. 7. Require confirmation before acting on any retrieved memory that could trigger tools, external communication, data disclosure, or consequential decisions. 8. Bind memories to the correct user and workspace to prevent cross-user contamination. 9. Record provenance and display retrieved entries as quoted historical data, not operational instructions. 10. Implement review, revocation, expiration, and deletion controls so poisoned entries can be identified and removed. 11. Add adversarial tests using short instruction-like payloads, because the existing 60-character truncation is not an effective security control. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Missing User Warnings

High
Confidence
98% confidence
Finding
The configuration disables risk reminders while the skill enables automatic local persistence of user data, removing an important safeguard that could alert users to file writes and retention behavior. In context, this makes the data collection more covert and increases the likelihood that sensitive information is stored without awareness.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill explicitly claims to automatically remember user preferences, decisions, and important information across sessions, but provides no user-facing privacy warning, consent step, or retention notice. Because the stored content may include sensitive personal or operational details, this omission materially increases the chance of covert data collection and unexpected disclosure.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest presents the skill as a resource-efficiency assistant, but the body adds a persistent cross-session memory subsystem that stores user preferences, decisions, and other information locally. This is a material capability expansion that changes the data-handling and privacy profile of the skill, creating undisclosed retention risk and making users more likely to share sensitive information without informed consent.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill automatically stores user preferences and decisions even though that behavior is not necessary for the stated purpose of resource-efficient execution. Automatic retention of potentially sensitive user data without clear necessity or consent creates privacy risk, expands the attack surface, and can expose personal or business information across sessions or to other local users/processes.

Ssd 3

Medium
Confidence
94% confidence
Finding
The skill instructs the agent to automatically retain and later surface user-provided information across sessions in plain language, which can expose sensitive data to unintended viewers or future prompts. Because the memory is stored in a local JSON file without any described access controls, minimization, or sanitization, the context makes this more dangerous than a transient contextual aid.

Context-Inappropriate Capability

Low
Confidence
81% confidence
Finding
The skill documentation includes shell commands invoking Python with inline code to store, search, and retrieve memory. While these are examples, they introduce an execution-oriented capability for local command invocation that is not justified by a manifest focused only on resource-efficient decisions/execution behavior.

Static analysis

No suspicious patterns detected.