T09 · Insecure Skill Coding Practices
- Location
__init__.py:222- Finding
Task Name Path Traversal Enables Arbitrary JSON File Access and Untrusted Desktop Automation
- Content
View full analysis
dict: """Load a saved task.""" filepath = self.tasks_dir / f"{task_name.replace(' ', '_')}.json" with open(filepath, 'r') as f: return json.load(f) ``` The loaded task is subsequently interpreted as desktop automation instructions in `__init__.py:239-283`: ```python def execute_task(self, task_name: str, **variables): """Execute a learned task with optional variables.""" task = self.load_task(task_name) results = [] for step in task["steps"]: step_type = step.get("type") # Replace variables in text text = step.get("text", "") for key, value in variables.items(): text = text.replace("{" + key + "}", value) if step_type == "click": self.click(step.get("x"), step.get("y")) results.append(f"Clicked {step.get('x')}, {step.get('y')}") elif step_type == "type": self.type(text) results.append(f"Typed: {text}") elif step_type == "press": self.press(*step.get("keys")) results.append(f"Pressed: {step.get('keys')}") elif step_type == "hotkey": self.hotkey(*step.get("keys")) results.append(f"Hotkey: {step.get('keys')}") elif step_type == "wait": import time time.sleep(step.get("seconds", 1)) ...[truncated 3717 chars]- Remediation
View remediation
str: if not TASK_NAME_PATTERN.fullmatch(task_name): raise ValueError("Invalid task name") return task_name ``` Reject absolute paths, path separators, empty names, `.` components, and `..` components. 2. **Enforce canonical path containment** Resolve both paths and verify that the resulting task path is a child of the intended directory: ```python def _task_path(self, task_name: str) -> Path: validate_task_name(task_name) base = self.tasks_dir.resolve() candidate = (base / f"{task_name}.json").resolve() if candidate.parent != base: raise ValueError("Task path escapes the task directory") return candidate ``` Use this centralized helper for both loading and saving. 3. **Prevent unintended overwrites** Use exclusive creation mode when creating new tasks or require explicit confirmation before replacement: ```python with open(filepath, "x", encoding="utf-8") as f: json.dump(task_data, f, indent=2) ``` If replacement is necessary, write to a safely created temporary file within `learned_tasks` and atomically replace the target after validation. 4. **Validate task documents against a strict schema** Require a dictionary with an allowed `steps` array. For every step: - Allowlist supported step types. - Reject unknown properties where practical. - Validate coordinate ranges against the screen dimensions. - Allowlist recognized key names and hotkey combinations. - Require finite, non-negative wait durations and enforce a maximum. - Limit text length. - Validate screenshot destinations separately and confine them to an approved directory. - Enforce limits on ...[truncated 648 chars]
