Back to skill

Security audit

record a dream

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed local dream journal, but users should know it stores sensitive dream entries on disk and lacks deletion or overwrite safeguards.

Install only if you are comfortable with dream entries being stored as plaintext Markdown files under ~/.openclaw/memory/dreams/. Review or back up that directory yourself, avoid using it on shared accounts, and be cautious until the publisher adds deletion, confirmation, and safer file-creation behavior.

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

T09 · Insecure Skill Coding Practices

Warning
Location
save_dream.py:13
Finding
Existing Dream Records Can Be Silently Overwritten## Vulnerability Details **File Location**: `save_dream.py`, lines 13-16 and line 38 **Vulnerability Type**: Insecure filename allocation and non-exclusive file creation **Risk Level**: Medium **Vulnerable code:** ```python def next_filename(date_str: str) -> Path: existing = sorted(DREAMS_DIR.glob(f"{date_str}-*.md")) idx = len(existing) + 1 return DREAMS_DIR / f"{date_str}-{idx:03d}.md" ``` ```python filepath.write_text(content, encoding="utf-8") ``` ### Technical Analysis The sequence number is calculated from the number of matching files rather than the highest sequence number already in use. If files `YYYY-MM-DD-001.md` and `YYYY-MM-DD-003.md` exist, the function counts two files and selects `YYYY-MM-DD-003.md`, which is already occupied. `Path.write_text()` opens the selected path without exclusive-create semantics and truncates an existing file. Consequently, the collision silently replaces the prior dream record. A separate time-of-check/time-of-use race also exists. Two concurrent processes can inspect the same directory state, derive the same sequence number, and write to the same destination. One write may replace the other, or the resulting content may depend on execution timing. ### Attack Path **Numbering-gap path:** 1. Arrange for a numbering gap in the current day's records, such as by deleting or moving `YYYY-MM-DD-002.md` while `001.md` and `003.md` remain. 2. Invoke `save_dream.py` with a new dream record. 3. `next_filename()` observes two matching files and calculates index `3`. 4. The script selects the existing `YYYY-MM-DD-003.md` path. 5. `write_text()` truncates and replaces the existing journal record without warning. **Concurrent-write path:** 1. Invoke two instances of `save_dream.py` concurrently. 2. Both instances count the same existing files before either creates its destination. 3. Both select the same next filename. 4. Both write non-exclusively ...[truncated 579 chars]
Remediation
## Remediation Suggestions 1. Parse valid numeric suffixes and choose a number greater than the highest existing suffix rather than using the number of matching files. 2. Create the destination atomically with exclusive mode, such as `open("x", encoding="utf-8")`, so an existing record can never be silently truncated. 3. If exclusive creation reports `FileExistsError`, recompute the sequence and retry. This addresses concurrent invocations. 4. Validate filenames against the exact expected pattern before considering them during sequence allocation. 5. Consider writing and flushing content to a securely created temporary file before atomically renaming it to the exclusively reserved destination, if crash-consistent writes are required. 6. Add tests covering numbering gaps, malformed filenames, pre-existing destination files, and simultaneous save operations. Example allocation strategy: ```python def save_with_retry(date_str: str, content: str) -> Path: indices = [] for path in DREAMS_DIR.glob(f"{date_str}-*.md"): suffix = path.stem.removeprefix(f"{date_str}-") if suffix.isdigit(): indices.append(int(suffix)) idx = max(indices, default=0) + 1 while True: filepath = DREAMS_DIR / f"{date_str}-{idx:03d}.md" try: with filepath.open("x", encoding="utf-8") as output: output.write(content) return filepath except FileExistsError: idx += 1 ```
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (7)

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The README states the skill is for recording and interpreting dreams 'in Chinese,' which imposes a language constraint in the user-facing description. The file does not indicate that other languages are supported or that Chinese is optional, so this appears to violate the language/locale policy for natural-language instructions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README explicitly says dream records are saved locally and these records can contain highly sensitive personal information, emotions, and behavioral details. Failing to warn users about persistent storage and privacy implications can lead to unintentional retention of intimate data on disk, increasing exposure to local compromise, backup leakage, or shared-device access.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill performs persistent file read/write operations but does not declare any explicit tool scope or permissions boundaries. This weakens least-privilege controls and makes it easier for the skill to access or store sensitive user data without clear platform enforcement or reviewer visibility.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill stores intimate dream narratives persistently in a local memory directory but does not clearly notify the user about retention, location, or how historical data will later be queried. Because dream content can reveal mental state, relationships, fears, or other sensitive personal information, lack of informed consent and retention transparency creates a meaningful privacy risk.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The history-query trigger is broad enough to overlap with ordinary conversation, which can cause the skill to activate unexpectedly and retrieve private dream records when the user did not clearly intend it. In this context, accidental activation matters because the content is sensitive and persisted across sessions.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This script writes user-provided dream content directly into a persistent file under ~/.openclaw/memory/dreams without any confirmation, visibility, or access-control checks in the code path. In an agent skill context, that creates a real privacy and consent risk because highly sensitive personal data can be stored on disk automatically and may later be exposed to other local tools, backups, or users of the same account.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The generated markdown headings and default title are hard-coded in Chinese (for example, '原始描述', '整理版本', and '无题梦境') with no option for the user to choose language or locale. This is a natural-language policy concern because the skill imposes a locale-specific output format rather than offering opt-in or documenting a justified regional constraint.

Static analysis

No suspicious patterns detected.