T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/create_agent.py:550
- Finding
- Unvalidated Agent and Workspace Paths Allow Arbitrary File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create_agent.py:550-556, 592-604, 613-622` **Vulnerability Type**: Path traversal and arbitrary destination write **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument('--id', help='Agent ID(如 dev-fe)') parser.add_argument('--name', help='Agent 名称(如 前端工程师)') parser.add_argument('--role', default='custom', help='预设角色模板') parser.add_argument('--model', default=None, help='使用的模型') parser.add_argument('--channel', default='telegram', help='通信渠道') parser.add_argument('--emoji', default=None, help='Agent emoji') parser.add_argument('--workspace', default=None, help='工作区路径') ``` ```python workspace = args.workspace or f"/root/.openclaw/workspace-{args.id}" agent_dir = Path(f'/root/.openclaw/agents/{args.id}/agent') workspace_dir = Path(workspace) if not args.dry_run: agent_dir.mkdir(parents=True, exist_ok=True) workspace_dir.mkdir(parents=True, exist_ok=True) ``` ```python create_identity_file(args.id, args.name, args.role, emoji, report_to, agent_dir / 'IDENTITY.md', args.dry_run) create_soul_file(args.role, agent_dir / 'SOUL.md', args.dry_run) create_agents_file(args.id, agent_dir / 'AGENTS.md', args.dry_run) create_user_file(agent_dir / 'USER.md', args.dry_run) # Synchronize into the workspace if not args.dry_run: import shutil for f in ['IDENTITY.md', 'SOUL.md', 'AGENTS.md', 'USER.md']: shutil.copy(agent_dir / f, workspace_dir / f) ``` The destination files are opened in write mode by the generation functions, for example: ```python with open(output_path, 'w', encoding='utf-8') as f: f.write(template) ``` ### Technical Analysis The documentation specifies that an agent ID should contain lowercase letters, numbers, and hyphens, but the implementation does not enforce this restriction. The `--id` value is interpolated directly into an absolute filesystem path, allowing path components such as `..`. More directly, `--workspace` accepts an arbitra ...[truncated 2200 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Strictly validate agent IDs before performing any filesystem operation: ```python import re if not re.fullmatch(r'[a-z0-9]+(?:-[a-z0-9]+)*', args.id or ''): raise ValueError("Agent ID must contain only lowercase letters, digits, and hyphens") ``` 2. Canonicalize and constrain generated paths to approved roots: ```python agent_root = Path.home() / ".openclaw" / "agents" agent_dir = (agent_root / args.id / "agent").resolve() if agent_root.resolve() not in agent_dir.parents: raise ValueError("Agent path escapes the approved agent root") ``` 3. Restrict workspaces to a configured workspace root unless an explicit administrative override is used. Resolve the requested path and verify containment before creating it. 4. Reject symbolic links in destination path components and before each write. Where practical, use descriptor-based operations with no-follow semantics to reduce time-of-check/time-of-use risks. 5. Do not silently overwrite existing files. Use exclusive creation, create a backup, or require explicit `--force` confirmation. 6. Run the Skill as an unprivileged OpenClaw service account rather than root. 7. Validate all arguments before creating any directory or changing `openclaw.json`, so invalid input cannot leave a partially modified installation. ]]>
