T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/plant_tracker.py:218
- Finding
- Unsafe Export Path Validation Allows Arbitrary Home-File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/plant_tracker.py:218-226, 248-277` **Vulnerability Type**: Arbitrary file overwrite through incomplete path restrictions and unsafe path-prefix validation **Risk Level**: High ### Vulnerable Code ```python # Security: Validate output path output_path = Path(output_file) if not is_safe_path(output_path): print(f"❌ Security error: Cannot write to '{output_path}'") print(" Path must be within workspace or home directory (not system paths)") return False # Ensure parent directory exists output_path.parent.mkdir(parents=True, exist_ok=True) ``` ```python output_path.write_text(md) print(f"✓ Exported {len(plants)} plants to {output_path}") return True def is_safe_path(filepath): """Check if file path is within safe directories (workspace, home, or /tmp).""" try: path = Path(filepath).expanduser().resolve() workspace = Path.home() / ".openclaw" / "workspace" home = Path.home() tmp = Path("/tmp") path_str = str(path) workspace_str = str(workspace.resolve()) home_str = str(home.resolve()) tmp_str = str(tmp.resolve()) in_workspace = path_str.startswith(workspace_str) in_home = path_str.startswith(home_str) in_tmp = path_str.startswith(tmp_str) # Block system paths system_dirs = ["/etc", "/usr", "/var", "/root", "/bin", "/sbin", "/lib", "/lib64", "/opt", "/boot", "/proc", "/sys"] blocked = any(path_str.startswith(d) for d in system_dirs) # Block sensitive dotfiles in home directory sensitive_patterns = [".ssh", ".bashrc", ".zshrc", ".profile", ".bash_profile", ".config/autostart"] for pattern in sensitive_patterns: if pattern in path_str: blocked = True break return (in_workspace or in_tmp or in_home) and not blocked except Exception: return False ``` ### Technical Analysis The ex ...[truncated 3402 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Restrict exports to a dedicated directory** Permit exports only beneath a directory such as: ```python export_root = ( Path.home() / ".openclaw" / "workspace" / "exports" ).resolve() ``` This is sufficient for the declared export functionality and avoids granting write access across the entire home directory. 2. **Use path-component-aware containment** Replace string-prefix checks with `Path.is_relative_to()`: ```python def is_safe_path(filepath): try: export_root = ( Path.home() / ".openclaw" / "workspace" / "exports" ).resolve() path = Path(filepath).expanduser().resolve(strict=False) return path.is_relative_to(export_root) except (OSError, RuntimeError, ValueError): return False ``` For Python versions without `is_relative_to()`, use `relative_to()` inside a `try` block. 3. **Do not rely on a sensitive-file blacklist** A blacklist cannot enumerate every configuration, credential, startup, or application-controlled file. Use an allowlisted export root and, if appropriate, require a safe extension such as `.md`. 4. **Prevent silent replacement of existing files** Refuse to overwrite existing files unless the caller explicitly requests it. For example, use exclusive creation: ```python with output_path.open("x", encoding="utf-8") as output: output.write(md) ``` If overwrite support is required, expose an explicit `--overwrite` option and clearly warn the user. 5. **Harden against symlink and race-condition attacks** Where supported, create files using no-follow and exclusive flags, verify the resolved parent directory immediately before opening the file, and avoid separate validation and write operations that can be raced. 6. **Apply secure permissions** Create export directories and files with permissions that do not expose potentially private plant note ...[truncated 222 chars]
