Back to skill

Security audit

Agent Task List

Security checks for vulnerabilities and agentic risk

Overview

This task-list skill is mostly purpose-built, but it needs review because an Agent ID can escape the intended storage folder and read or overwrite task-list files elsewhere.

Review before installing in shared or multi-agent environments. Use only trusted Agent IDs, avoid path separators or absolute paths, and do not rely on this skill for isolation between users or agents until Agent ID validation and safer atomic locking are added.

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
scripts/task_manager.py:66
Finding

Unsanitized Agent ID Allows Path Traversal Outside the Task Data Directory

Content
View full analysis
Path: agent_dir = AGENTS_DIR / agent_id agent_dir.mkdir(parents=True, exist_ok=True) return agent_dir / "task-list.json" ``` Agent identifiers are accepted directly from CLI arguments without validation, for example: ```python create_parser.add_argument("--agent", required=True, help="Agent ID") list_parser.add_argument("--agent", required=True, help="Agent ID") start_parser.add_argument("--agent", required=True, help="Agent ID") ``` The resulting path is subsequently used for file reads and writes: ```python def load_agent_task_list(agent_id: str) -> Dict[str, Any]: task_file = get_agent_task_file(agent_id) if not task_file.exists(): return { "agent_id": agent_id, "agent_name": agent_id, "current_task": None, "pending_tasks": [], "completed_tasks": [], "failed_tasks": [], "created_at": get_timestamp(), "updated_at": get_timestamp() } try: with open(task_file, 'r', encoding='utf-8') as f: return json.load(f) ``` ```python def save_agent_task_list(agent_id: str, task_list: Dict[str, Any]): task_file = get_agent_task_file(agent_id) task_list["updated_at"] = get_timestamp() with open(task_file, 'w', encoding='utf-8') as f: json.dump(task_list, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis `agent_id` is treated as a filesystem path component rather than as an opaque identifier. Python's `pathlib` preserves traversal components such as `..`. If the supplied value is an absolute path, combining it with `AGENTS_DIR` also causes the intended base directory to be discarded. The implementation neither validates the identifier ...[truncated 2104 chars]
Remediation
View remediation
str: if not AGENT_ID_PATTERN.fullmatch(agent_id): raise ValueError("Invalid Agent ID") return agent_id ``` 2. Resolve and verify the resulting path before creating directories or accessing files: ```python def get_agent_task_file(agent_id: str) -> Path: validate_agent_id(agent_id) base = AGENTS_DIR.resolve() agent_dir = (base / agent_id).resolve() try: agent_dir.relative_to(base) except ValueError: raise ValueError("Agent path escapes the task data directory") agent_dir.mkdir(parents=True, exist_ok=True) return agent_dir / "task-list.json" ``` 3. Explicitly reject: - Absolute paths. - `/` and `\` path separators. - `.` and `..` path components. - Empty, excessively long, or control-character-containing identifiers. 4. Perform validation in the shared path-construction function so every CLI command and programmatic caller receives the same protection. 5. Add regression tests covering: - Relative traversal such as `../../tmp/target`. - Absolute paths. - Backslash-based traversal. - Nested path separators. - Symbolic-link escape attempts. - Valid identifiers containing only approved characters. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/task_manager.py:46
Finding

Unlocked and Non-Atomic State Updates Permit Duplicate IDs and Task Data Corruption

Content
View full analysis
int: counter = get_task_counter() + 1 TASK_COUNTER_FILE.write_text(str(counter)) return counter ``` Agent task lists are overwritten directly: ```python def save_agent_task_list(agent_id: str, task_list: Dict[str, Any]): task_file = get_agent_task_file(agent_id) task_list["updated_at"] = get_timestamp() with open(task_file, 'w', encoding='utf-8') as f: json.dump(task_list, f, ensure_ascii=False, indent=2) ``` The global index is also updated through a separate unlocked read-modify-write transaction: ```python if INDEX_FILE.exists(): try: with open(INDEX_FILE, 'r', encoding='utf-8') as f: index = json.load(f) except: index = {"agents": [], "total_tasks": { "current": 0, "pending": 0, "completed": 0, "failed": 0 }} ``` ```python with open(INDEX_FILE, 'w', encoding='utf-8') as f: json.dump(index, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis Persistent updates are composed of multiple independent operations without an inter-process lock: 1. Read the current counter or JSON state. 2. Modify it in memory. 3. Truncate and rewrite the destination file. 4. Update related files separately. Two concurrent processes can therefore observe the same initial state. For the counter, both can calculate the same next value and generate an identical task ID. For task lists and the index, the process that writes last can silently overwrite changes made by the other process. Directly writing JSON to the final destination also exposes a partially written or truncated file if another p ...[truncated 2147 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file’s natural-language content consistently forces a specific language/locale for readers and users, and there is no indication that Chinese is optional or that the skill is region-specific. Under the policy, language constraints should either be user-selectable or clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

该技能文档从标题到全部操作说明均固定为中文,未向用户提供语言/locale 选择,也未说明该技能仅面向特定中文环境或地区。根据语言/locale 政策要求,未经用户选择而强制单一语言属于自然语言层面的策略问题。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documents file read/write behavior and persistent storage under the user's home directory, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates an authorization ambiguity where an agent may use filesystem capabilities more broadly than the skill transparently communicates, increasing the risk of unintended file access or modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill describes creating and maintaining task data in files under ~/.openclaw/workspace/agent-tasks, but it does not clearly warn users that invoking these commands will create, modify, and retain persistent state in their home directory. This weakens informed consent and can lead to silent data mutation, accumulation of history, and operational confusion in multi-agent environments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The cancel and retry operations explicitly change queue state and may remove or reinsert tasks, yet the documentation provides no warning about the persistence and consequences of those mutations. In a shared or multi-agent workflow, this can cause accidental loss of task state, duplicate execution, or confusing history changes without clear operator awareness.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The list_all_agents() command exposes a global index of all agents and their task counts, contradicting the skill's stated model of independent per-agent task queues. This leaks operational metadata across agents, which can reveal workload, activity timing, and existence of other agents to unauthorized users.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The get_task(task_id) function iterates through every agent directory and returns task details for any matching task ID, which breaks the advertised per-agent isolation boundary. In a multi-agent environment, any caller who can invoke this script can discover another agent's tasks and metadata, enabling unauthorized cross-agent information disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code path cancels current or pending tasks and persists the change to disk via save_agent_task_list and update_index, but provides no confirmation prompt and no explicit warning in comments/docstrings that it irreversibly changes task state. For a code file, state-changing file writes that affect user-managed task data should include some visible disclosure when there is no surrounding markdown warning provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This Python file contains natural-language strings such as the module docstring, test descriptions, and printed status messages entirely in Chinese, which imposes a specific language on users and maintainers. The file does not indicate that the locale is optional, configurable, or justified by a region-specific requirement, which matches the language-policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The top-level natural-language description is entirely in Chinese and presents the script as a Chinese-language task management system, with CLI help strings and user-facing messages also fixed to Chinese throughout the file. This constitutes a locale/language constraint that is not presented as optional or justified as region-specific.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.