Back to skill

Security audit

Task Memory

Security checks for vulnerabilities and agentic risk

Overview

This task-memory skill mostly does what it claims, but it silently reads and writes a hard-coded todo file outside the skill directory and includes under-scoped external reminder instructions.

Review before installing. Use this only if you are comfortable with a task manager that stores task titles, notes, and deadlines on disk, and fix or configure the storage path before running it so it cannot read or modify another workspace's todo file. Do not enable QQ/IM reminder forwarding without explicit destination controls and redaction for sensitive task text.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/todo_manager.py:18
Finding
Undisclosed Access to a Hard-Coded File Outside the Skill Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/todo_manager.py`, lines 18–28 **Vulnerability Type**: Hard-coded external storage path and insufficient path-boundary enforcement **Risk Level**: Medium ### Vulnerable Code ```python TODO_FILE = "/home/openclaw/.openclaw/workspace/backtest/todo.json" def load(): if os.path.exists(TODO_FILE): with open(TODO_FILE) as f: return json.load(f) return {"version": "1.0", "updated": "", "items": []} def save(data): data["updated"] = datetime.now().isoformat() with open(TODO_FILE, 'w') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The task manager does not use the bundled `references/todo.json`. Instead, every operation reads from or writes to a hard-coded path in a separate workspace: `/home/openclaw/.openclaw/workspace/backtest/todo.json` This behavior conflicts with the documented project-local storage model. Commands such as `--list` and `--check` can disclose task metadata from that external workspace, while `--add`, `--done`, `--remove`, `--update`, and `--purge` can modify or delete its records. The script performs no validation that the target resides within an approved directory. It also does not verify file ownership or reject symbolic links. If an attacker who can manipulate the target path replaces the file with a symbolic link, writes may be redirected to another file writable by the script's operating-system identity. ### Attack Path 1. A user or Agent invokes the task manager according to the documented commands. 2. The script ignores the package's `references/todo.json` and resolves the hard-coded external path. 3. A read command exposes titles, notes, deadlines, and other metadata stored by the external workspace. 4. A mutating command overwrites, removes, archives, or purges records in that workspace. 5. If a local attacker can replace the target with a symbolic link, the write may be redirected to anot ...[truncated 691 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store data within the Skill directory by resolving the path relative to the script: ```python from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parent.parent TODO_FILE = PROJECT_ROOT / "references" / "todo.json" ``` 2. If configurable storage is required, require an explicit configuration value rather than silently using a path from another workspace. 3. Resolve the canonical path and verify that it remains under an approved storage directory before every read or write. 4. Reject symbolic-link targets where they are not explicitly supported. 5. Verify file ownership and use restrictive permissions, such as owner-only read and write access. 6. Update the documentation and implementation so that they identify the same storage location. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/todo_manager.py:25
Finding
Non-Atomic and Unlocked Task Database Writes<![CDATA[ ## Vulnerability Details **File Location**: `scripts/todo_manager.py`, lines 25–28 **Vulnerability Type**: Unsafe persistent-state write and concurrent update race **Risk Level**: Low ### Vulnerable Code ```python def save(data): data["updated"] = datetime.now().isoformat() with open(TODO_FILE, 'w') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The task database is opened directly in write mode, which truncates the existing file before serialization completes. There is no file lock, temporary file, atomic replacement, flush, or synchronization to durable storage. The documentation recommends use from interactive sessions, startup checks, heartbeat processes, cron jobs, and other automation. These execution contexts can overlap. Because each command independently loads, modifies, and saves the entire JSON document, simultaneous operations may overwrite each other's changes. Interruption after truncation but before serialization completes can also leave an empty or malformed database. ### Attack Path 1. Two Agent, heartbeat, cron, or interactive processes load the same database state. 2. Each process independently modifies its in-memory copy. 3. The first process writes its result. 4. The second process writes its stale copy, silently discarding the first process's update. 5. Alternatively, a process is interrupted after opening the file in write mode, leaving truncated or partially serialized JSON. 6. A subsequent `load()` call fails to parse the malformed database, disrupting all task operations. ### Impact Assessment An attacker or unreliable concurrent automation can affect the integrity and availability of the task database by triggering overlapping writes or interrupting a write operation. Consequences include: - Silent loss of newly added or updated tasks. - Reappearance of removed or completed tasks due to stale writes. - Corruption of the JSON database. - Failure of deadline checks an ...[truncated 171 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Protect the complete read-modify-write transaction with an inter-process file lock. 2. Serialize the updated database to a temporary file created in the destination directory. 3. Flush the temporary file and call `os.fsync()` before replacement. 4. Atomically replace the original file with `os.replace()`. 5. Apply restrictive permissions to both the temporary and final files. 6. Consider retaining a validated backup so malformed or interrupted state can be recovered. 7. For frequent concurrent use, migrate persistence to SQLite and use transactions rather than a shared JSON document. A safe write pattern should resemble: ```python import os import tempfile directory = os.path.dirname(TODO_FILE) fd, temporary_path = tempfile.mkstemp(dir=directory) try: with os.fdopen(fd, "w") as temporary_file: json.dump(data, temporary_file, ensure_ascii=False, indent=2) temporary_file.flush() os.fsync(temporary_file.fileno()) os.replace(temporary_path, TODO_FILE) finally: if os.path.exists(temporary_path): os.unlink(temporary_path) ``` This atomic replacement must still be combined with locking around the entire load-and-save transaction to prevent lost updates. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/todo_manager.py:243
Finding
Task Updates Bypass Deadline and Status Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/todo_manager.py`, lines 243–249 **Vulnerability Type**: Inconsistent input validation and reminder suppression **Risk Level**: Low ### Vulnerable Code ```python if "--title" in args: item["title"] = args[args.index("--title") + 1] if "--deadline" in args: item["deadline"] = args[args.index("--deadline") + 1] if "--status" in args: item["status"] = args[args.index("--status") + 1] save(data) print(f"✅ 更新: [{id_}] {item['title']}") ``` ### Technical Analysis The `--add` operation calls `_validate_deadline()`, but the `--update` operation directly persists an arbitrary deadline. It also accepts arbitrary status strings instead of restricting them to the documented states: `pending`, `in_progress`, `completed`, and `cancelled`. The deadline checker attempts to parse persisted deadlines with `datetime.fromisoformat()`. Its broad exception handler silently skips invalid values. Consequently, a malformed deadline introduced through `--update` can prevent a task from being classified as overdue or upcoming without notifying the operator. Arbitrary status values can also produce inconsistent behavior across listing, filtering, and checking operations. In particular, the data model no longer enforces the states promised by the documentation. ### Attack Path 1. A caller selects an existing task identifier. 2. The caller executes `--update` with a malformed deadline or unsupported status. 3. The script persists the value without validation. 4. During a later `--check`, deadline parsing raises an exception. 5. The broad exception handler suppresses the error and skips the task. 6. The malformed task no longer produces the expected overdue or upcoming reminder. ### Impact Assessment A caller with permission to invoke the manager can suppress reminders or corrupt task-state semantics. Potential effects include: - Overdue tasks being silently omitted from checks. - Upcoming tasks failing to pr ...[truncated 284 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply `_validate_deadline()` before assigning an updated deadline. 2. Restrict status updates to an explicit allowlist: ```python VALID_STATUSES = {"pending", "in_progress", "completed", "cancelled"} ``` 3. Reject invalid values with a nonzero exit status and a clear diagnostic. 4. Replace broad exception handlers in deadline processing with `except (TypeError, ValueError)` and report malformed records. 5. Validate the complete database schema when loading it, including required keys and expected value types. 6. Route transitions to `completed` through the existing `done()` workflow so `completed_at` and archive behavior remain consistent. 7. Add tests confirming that invalid updates are rejected and cannot suppress deadline alerts. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (8)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill clearly instructs the agent to create and update a persistent `references/todo.json`, which is a file-write capability, but the manifest does not declare any explicit tool scope or permissions. This creates an authorization ambiguity where a host may grant broader filesystem access than intended, making accidental or unsafe writes more likely.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs persistent storage of task data in `todo.json` but does not warn that user-provided task details will be written to disk. This can surprise users and operators, and may expose sensitive plans, notes, or deadlines through local file access, backups, or logs.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The skill is described as a local task-memory system, but the documentation also directs pushing overdue reminders to external QQ/IM channels. That expands the data flow from local persistence into outbound messaging without corresponding scope, consent, or security controls, increasing the chance of task data leakage.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation tells the agent to push overdue task reminders to QQ/IM but provides no privacy warning, consent requirement, or guidance on minimizing sensitive content. Since task titles and notes may contain personal, financial, or operational details, this can lead to inadvertent disclosure to third-party channels.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The AGENTS/HEARTBEAT integration instructions operationalize external QQ/IM reminder delivery even though the skill's stated purpose is local todo tracking. Embedding this in startup and heartbeat flows increases the likelihood of automatic, repeated disclosure of potentially sensitive task details to external channels.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This markdown file documents that completed tasks are automatically archived and that a purge command deletes archived items older than 30 days. Those behaviors affect user data retention and deletion, but the document provides no warning or caution about these impacts.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file contains natural-language strings that effectively force a specific language for usage instructions and operational output. Under the policy, locale-specific behavior should either offer user opt-in/choice or be clearly justified as region-specific, which is not present here.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The docstring at L144 says archived items are '保留30天' and the output at L160-L164 presents the archive as retained for 30 days, but completed tasks are actually archived indefinitely in todo.json until the separate --purge command is run. This is an active contradiction about lifecycle behavior, not just missing detail, because the code only filters display to 30 days and does not enforce automatic deletion.

Static analysis

No suspicious patterns detected.