Back to skill

Security audit

Task Persistence

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent task-recovery purpose, but it persistently stores broad session and conversation data in plaintext and has unsafe identifier handling that can read or overwrite JSON files outside intended folders.

Review before installing. Use only in workspaces where persistent plaintext task and session records are acceptable, avoid storing secrets in prompts or task metadata, and restrict workspace file permissions. Do not pass user-controlled or untrusted task IDs or session IDs until the path traversal issues are fixed with strict identifier validation and path containment checks.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/task_queue.py:142
Finding
Path Traversal Through Unsanitized Task Identifiers## Vulnerability Details **File Location**: `scripts/task_queue.py:142-160` and `scripts/task_queue.py:164-194` **Vulnerability Type**: Path traversal and arbitrary JSON-file overwrite **Risk Level**: High The same vulnerable implementation is duplicated in `dist/scripts/task_queue.py:142-160` and `dist/scripts/task_queue.py:164-194`. The attacker-controlled identifier enters these methods through `scripts/task_manager.py:31-38` and `scripts/task_manager.py:59-69`. ### Vulnerable Code ```python def complete_task(self, task_id: str, result_data: Dict[str, Any] = None) -> bool: """Mark a task as completed and move it to completed directory.""" for i, task in enumerate(self.task_queue): if task['id'] == task_id and task['status'] == 'running': task['status'] = 'completed' task['completed_at'] = datetime.now().isoformat() if result_data: task['result'] = result_data # Save to completed directory completed_file = self.completed_dir / f"{task_id}.json" try: with open(completed_file, 'w', encoding='utf-8') as f: json.dump(task, f, indent=2, ensure_ascii=False) except IOError as e: print(f"Warning: Failed to save completed task {task_id}: {e}") # Remove from queue self.task_queue.pop(i) self._save_queue() return True return False ``` ```python def fail_task(self, task_id: str, error_message: str = None) -> bool: """Mark a task as failed and handle retries.""" for task in self.task_queue: if task['id'] == task_id: task['retry_count'] += 1 if task['retry_count'] < task['max_retries']: task['status'] = 'queued' task['started_at'] = None self._save ...[truncated 3198 chars]
Remediation
## Remediation Suggestions 1. Restrict task identifiers to a conservative allowlist before storing or using them: ```python import re TASK_ID_PATTERN = re.compile(r"^[A-Za-z0-9_-]{1,128}$") def validate_task_id(task_id: str) -> str: if not TASK_ID_PATTERN.fullmatch(task_id): raise ValueError("Invalid task identifier") return task_id ``` 2. Reject identifiers containing `/`, `\`, `..`, null bytes, drive prefixes, or absolute-path syntax. 3. Resolve every destination and verify containment before opening it: ```python base = self.completed_dir.resolve() destination = (base / f"{task_id}.json").resolve() if destination.parent != base: raise ValueError("Task path escapes the completed-task directory") ``` 4. Apply equivalent containment checks to `failed_dir`. 5. Use generated internal identifiers, such as UUIDs, for filenames instead of user-provided display identifiers. 6. Write atomically through a securely created temporary file in the same directory, then use `os.replace()`. 7. Add tests for absolute paths, `../` traversal, Windows drive paths, alternate separators, Unicode separator edge cases, and symlink-based escapes.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/session_snapshot.py:23
Finding
Path Traversal Through Unsanitized Session Identifiers## Vulnerability Details **File Location**: `scripts/session_snapshot.py:23-60` **Vulnerability Type**: Path traversal causing arbitrary JSON-file read and overwrite **Risk Level**: High Related vulnerable path construction also appears in `scripts/gateway_monitor.py:60-78`. Both implementations are duplicated under `dist/scripts/`. ### Vulnerable Code ```python def create_snapshot(self, session_data: Dict[str, Any], session_id: str, include_context: bool = True) -> str: """Create a session snapshot with current state and context.""" snapshot = { "session_id": session_id, "timestamp": datetime.now().isoformat(), "model": session_data.get("model", "unknown"), "tokens": { "input": session_data.get("input_tokens", 0), "output": session_data.get("output_tokens", 0), "context_usage": session_data.get("context_usage", 0) }, "active_tasks": session_data.get("active_tasks", []), "conversation_history": session_data.get("history", []) if include_context else [], "system_state": session_data.get("system_state", {}), "pending_operations": session_data.get("pending_ops", []) } # Save snapshot snapshot_file = self.snapshot_dir / f"{session_id}_{int(time.time())}.json" with open(snapshot_file, 'w', encoding='utf-8') as f: json.dump(snapshot, f, indent=2, ensure_ascii=False) # Also save latest snapshot for quick recovery latest_file = self.snapshot_dir / f"{session_id}_latest.json" with open(latest_file, 'w', encoding='utf-8') as f: json.dump(snapshot, f, indent=2, ensure_ascii=False) return str(snapshot_file) def get_latest_snapshot(self, session_id: str) -> Optional[Dict[str, Any]]: """Get the latest snapshot for a session.""" latest_file = self.snapshot_dir / f"{ ...[truncated 2995 chars]
Remediation
## Remediation Suggestions 1. Validate session identifiers against a strict pattern such as `^[A-Za-z0-9_-]{1,128}$`. 2. Use an internally generated UUID or a cryptographic hash of the external session identifier as the filename. 3. Resolve and verify every path before reading or writing: ```python base = self.snapshot_dir.resolve() destination = (base / f"{safe_session_id}_latest.json").resolve() if destination.parent != base: raise ValueError("Snapshot path escapes the snapshot directory") ``` 4. Do not use untrusted values directly in `Path.glob()` patterns. 5. Reject absolute paths, path separators, traversal components, drive prefixes, and null bytes. 6. Apply the same validation and containment controls in `GatewayMonitor`. 7. Use atomic writes and avoid following attacker-controlled symlinks where the execution environment permits local untrusted access. 8. Add regression tests for read and write traversal through all session-related CLI entry points.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/session_snapshot.py:18
Finding
Sensitive Session and Conversation Data Stored in Plaintext## Vulnerability Details **File Location**: `scripts/session_snapshot.py:18-50` **Vulnerability Type**: Plaintext storage of sensitive session state with ambient filesystem permissions **Risk Level**: Medium Related unrestricted snapshot storage appears in `scripts/task_persistence.py:127-148` and `scripts/gateway_monitor.py:60-69`. The same implementations are present under `dist/scripts/`. ### Vulnerable Code ```python class SessionSnapshotManager: def __init__(self, workspace_path: str): self.workspace = Path(workspace_path) self.snapshot_dir = self.workspace / "memory" / "session_snapshots" self.snapshot_dir.mkdir(parents=True, exist_ok=True) self.current_session_id = None def create_snapshot(self, session_data: Dict[str, Any], session_id: str, include_context: bool = True) -> str: """Create a session snapshot with current state and context.""" snapshot = { "session_id": session_id, "timestamp": datetime.now().isoformat(), "model": session_data.get("model", "unknown"), "tokens": { "input": session_data.get("input_tokens", 0), "output": session_data.get("output_tokens", 0), "context_usage": session_data.get("context_usage", 0) }, "active_tasks": session_data.get("active_tasks", []), "conversation_history": session_data.get("history", []) if include_context else [], "system_state": session_data.get("system_state", {}), "pending_operations": session_data.get("pending_ops", []) } # Save snapshot snapshot_file = self.snapshot_dir / f"{session_id}_{int(time.time())}.json" with open(snapshot_file, 'w', encoding='utf-8') as f: json.dump(snapshot, f, indent=2, ensure_ascii=Fals ...[truncated 2832 chars]
Remediation
## Remediation Suggestions 1. Minimize stored data. Exclude full conversation history, credentials, tokens, authorization headers, environment variables, and unrelated system state by default. 2. Require explicit user consent before persisting conversation content. 3. Implement recursive redaction for fields whose names indicate secrets, including `token`, `secret`, `password`, `credential`, `authorization`, `cookie`, and private keys. 4. Create storage directories with mode `0700` and snapshot files with mode `0600`, independent of the ambient umask. 5. Verify and correct permissions on pre-existing snapshot directories and files. 6. Encrypt sensitive snapshots at rest using a key stored outside the snapshot directory and protected by the platform credential store. 7. Enforce a documented retention policy, maximum snapshot count, and automatic cleanup schedule. 8. Avoid unnecessary duplicate copies, or ensure `_latest.json` is an atomically updated protected file. 9. Provide an option to disable context capture entirely and make that the default. 10. Document precisely which fields are retained and expose a secure command for deleting all snapshots associated with a session.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
If the implementation does not actually provide restart detection and task recovery logic but does persist full conversation and system state, the skill creates privacy and trust risk without delivering the narrowly stated function. Broad state capture under a task-persistence label can mislead operators into enabling storage of sensitive context they did not intend to retain.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
If the implementation does not actually provide restart detection and task recovery logic but does persist full conversation and system state, the skill creates privacy and trust risk without delivering the narrowly stated function. Broad state capture under a task-persistence label can mislead operators into enabling storage of sensitive context they did not intend to retain.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill invokes local Python scripts that read environment-derived paths and persist data under /workspace, but it declares no tool scope or permissions boundaries. That omission weakens policy enforcement and transparency, making it easier for the skill to perform file and state operations beyond what a caller may expect.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger conditions include broad phrases like before/after any multi-step operation, which can cause the skill to activate during many normal workflows. In context, that increases the chance of unnecessary state capture and file writes, expanding exposure of user and session data beyond truly long-running recovery scenarios.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly states that it automatically saves long-running task state, session context, and conversation history to disk, but it does not warn users about this data persistence behavior or obtain informed consent. In an agent environment, this can expose sensitive prompts, secrets, file paths, or operational context to unintended retention, later access, or recovery after restart, making the omission a real privacy and security weakness.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a skill for task continuity, session snapshots, and restart recovery, but this file explicitly adds 'gateway monitoring' and continuously watches gateway status in a background loop. Ongoing service monitoring is a broader operational capability than the stated resume/recovery role and is not clearly implied by the manifest description.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The snapshot creation logic persists conversation history, active tasks, pending operations, and system state to disk in plaintext JSON under the workspace. These fields can easily contain sensitive prompts, tokens, secrets, filesystem paths, or operational context, and the code provides no minimization, encryption, consent, or retention controls beyond a simple age-based cleanup.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code persists arbitrary task metadata and full session snapshot data to JSON files on disk with no minimization, encryption, retention control, or user-facing warning that sensitive context may be stored. In this skill's context, session continuity may include prompts, credentials, tokens, operational context, or user data, so local disclosure becomes plausible if the workspace is shared, backed up, inspected, or has weak filesystem permissions.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The method is documented as detecting whether the gateway has been restarted, but the implementation only checks a persisted "startup_notified" flag and a 5-second time gap. That logic does not actually observe or verify a real gateway restart; it merely infers a first-run/unnotified state, which contradicts the stronger claim in the docstring and module description.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest describes a skill for task continuity, session snapshots, and restart recovery, but this file's module purpose explicitly adds ongoing gateway monitoring functionality. The code implements a persistent monitor loop, status tracking, and start/stop event handling, which go beyond passive persistence/recovery and introduce a broader operational monitoring role.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The module docstring is written entirely in Chinese and describes the skill's behavior in that language, with no indication that language selection is optional or region-specific. Per the policy, forcing a specific language or locale without user opt-in is a natural-language policy violation.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest frames the skill as something to use when starting long-running tasks, after restart, or when the user asks about status/recovery. In contrast, the code continuously runs a background thread that polls gateway state every 10 seconds and persists status changes, which is a persistent monitoring service rather than an on-demand continuity helper.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code emits natural-language output only in Chinese for recovery and status reporting. That creates a language policy concern because the skill forces a specific language without user opt-in, and there is no indication that the tool is intentionally limited to a Chinese-speaking context.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The snapshot manager persists full conversation history, system state, active tasks, and pending operations to disk in plaintext JSON under the workspace. These fields can contain secrets, personal data, prompts, internal state, or operational details, and the code provides no minimization, encryption, access controls, consent flow, or retention safeguards beyond age-based deletion.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code persists complete session snapshots to disk, including arbitrary session context, without any minimization, consent flow, retention control, or protection beyond plain JSON storage. In a task recovery skill, session state is likely to contain sensitive prompts, tokens, file paths, or user data, so local disclosure or later unintended reuse becomes a realistic confidentiality risk.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
The natural-language description forces a specific language/locale in user-facing documentation. The file does not indicate that Chinese is optional, user-selected, or required for a justified region-specific purpose.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The top-level docstring describes the skill entirely in Chinese, which can impose a specific language/locale on users or maintainers without any opt-in or stated regional requirement. The policy for this audit flags natural-language locale constraints when the file does not offer a choice or justify the language restriction.

Intent-Code Divergence

Low
Confidence
90% confidence
Finding
The restart handler comment says '恢复会话快照' and prints 'Restoring from latest session snapshot', implying actual session recovery. In practice, the code only loads the snapshot JSON and prints its timestamp without applying the saved data to restore session state.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The restore CLI prints restored session state directly to stdout, which may be captured by shell history, CI logs, wrappers, or other calling pipelines. Even though the restored object is narrower than the full snapshot, it still includes task, token, and system-state metadata that may be sensitive in shared or logged environments.

Missing User Warnings

Low
Confidence
86% confidence
Finding
Task metadata supplied by callers is written directly to persistent storage without any disclosure, filtering, or sensitivity checks. Although less severe than full session snapshots, task metadata in this skill could still include user inputs, identifiers, operational details, or secrets embedded in parameters, creating avoidable at-rest exposure.

Static analysis

No suspicious patterns detected.