Back to skill

Security audit

Task Director

Security checks for vulnerabilities and agentic risk

Overview

This is a visible task-planning helper, but a path-handling flaw could let its CLI read or overwrite JSON files outside its stated storage folder.

Review the generated scenes before approving them, because command fields may install packages, remove files, or make network calls when the agent executes them. Avoid passing hand-written or untrusted movie IDs until the path traversal issue is fixed, and prefer a version that validates movie IDs and confines all reads and writes to ~/.openclaw/memory/movies/.

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
scripts/director.py:45
Finding
Arbitrary JSON File Access Through Unsanitized Movie IDs## Vulnerability Details **File Location**: `scripts/director.py:45-54` **Vulnerability Type**: Path traversal and arbitrary file read/write **Risk Level**: Medium ### Vulnerable Code ```python def load_movie(movie_id): f = get_data_dir() / f"{movie_id}.json" if not f.exists(): return None return json.loads(f.read_text(encoding="utf-8")) def save_movie(movie): f = get_data_dir() / f"{movie['id']}.json" f.write_text(json.dumps(movie, ensure_ascii=False, indent=2), encoding="utf-8") ``` ### Technical Analysis The application directly interpolates a CLI-controlled movie ID into a filesystem path without validating its format or verifying that the resolved path remains inside `~/.openclaw/memory/movies/`. A movie ID containing `../` components can traverse outside the intended storage directory. An absolute path is also unsafe because Python's `pathlib` discards the preceding base path when the right-hand operand is absolute. This affects every command that passes an untrusted `--id` value to `load_movie`. After loading a document, mutating commands call `save_movie`, which independently trusts the `id` property stored inside that document. An attacker can therefore control both the source path and, through the loaded JSON content, the subsequent destination path. The mandatory `.json` suffix limits accessible targets to paths ending in `.json`, and successful mutation requires the selected document to contain the structure expected by the invoked command. These constraints reduce, but do not eliminate, the vulnerability. ### Attack Path 1. The attacker identifies or creates a structurally valid JSON document outside `~/.openclaw/memory/movies/`, such as `/tmp/movie.json`. 2. The attacker supplies an absolute or traversal-based identifier to a command that accepts `--id`, for example: ```bash python scripts/director.py approve --id /tmp/movie ``` 3. `load_movie()` constructs the path from the unvalidated identifier an ...[truncated 1120 chars]
Remediation
## Remediation Suggestions 1. Enforce the generated movie-ID format before every read or write: ```python import re MOVIE_ID_PATTERN = re.compile(r"^movie_[0-9]{7}$") def validate_movie_id(movie_id): if not isinstance(movie_id, str) or not MOVIE_ID_PATTERN.fullmatch(movie_id): raise ValueError("Invalid movie ID") return movie_id ``` 2. Resolve candidate paths and enforce containment within the movie data directory: ```python def movie_path(movie_id): movie_id = validate_movie_id(movie_id) base = get_data_dir().resolve() candidate = (base / f"{movie_id}.json").resolve() if candidate.parent != base: raise ValueError("Movie path escapes the data directory") return candidate ``` 3. Use the same validated path helper in both `load_movie()` and `save_movie()`. 4. Do not trust the `id` field read from persisted JSON. Retain the validated ID supplied to `load_movie()` and use that trusted value when saving. Alternatively, verify that the document's `id` exactly matches the validated filename ID before processing it. 5. Reject absolute paths, path separators, dot components, and unexpected Unicode representations in identifiers as defense in depth. 6. Perform writes atomically by creating a temporary file in the same protected directory, setting restrictive permissions, flushing it, and replacing the destination only after serialization succeeds. 7. Add regression tests covering absolute IDs, `../` traversal, nested separators, malformed IDs, and persisted documents whose internal `id` differs from the filename.
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 (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill describes automated workflow execution, persists state under the user's home directory, and directs an agent to read/write files, but it does not declare any tool scope or permissions boundaries. In an agent ecosystem, this can lead to over-broad file access and unsafe execution of user- or skill-generated commands because the runtime has no explicit least-privilege contract to enforce.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest says the skill will 'execute step by step with fallback support,' but `cmd_action` does not actually execute any task logic. It marks state as running and prints JSON containing `action` and `command` for some external agent to execute, making this a workflow/state manager rather than an executor.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The primary title and descriptive content begin in Chinese, while later text switches to English, but the document does not state whether users may choose their preferred language. Under the policy rule, forcing or implicitly assuming a specific language without opt-in can be a natural-language policy concern.

Description-Behavior Mismatch

Low
Confidence
84% confidence
Finding
The stated purpose emphasizes planning, review, and execution flow, but the implementation also creates and maintains persistent local state in `~/.openclaw/memory/movies`. Persistent filesystem storage may be a meaningful behavior beyond a simple 'turn tasks into movie storyboards' description because it accumulates historical task data and notes across runs.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The code hard-codes UTC+8 in `now_iso()`, which determines displayed and stored timestamps for all users. This imposes a locale-specific behavior without offering a user opt-in or explaining why that region-specific setting is required.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The JSON uses Chinese natural-language values for scene names, descriptions, and actions throughout the file. This imposes a specific language/locale on users without any indication of opt-in, alternative locale support, or region-specific justification, which matches the stated language policy concern.

Static analysis

No suspicious patterns detected.