T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/feishu_file_sender.py:116
- Finding
- Unrestricted Local File Upload to Feishu## Vulnerability Details **File Location**: `scripts/feishu_file_sender.py`, lines 116–133 and 195–224 **Vulnerability Type**: Arbitrary local file disclosure through insufficient path validation **Risk Level**: Medium ### Vulnerable Code ```python def upload_file(token: str, file_path: Path, file_type: str) -> str: headers = {"Authorization": f"Bearer {token}"} with file_path.open("rb") as f: files = {"file": (file_path.name, f)} data = { "file_type": file_type, "file_name": file_path.name, } resp = requests.post( FEISHU_UPLOAD_URL, headers=headers, data=data, files=files, timeout=30, ) resp.raise_for_status() data = resp.json() if data.get("code") != 0: raise RuntimeError(f"Upload failed: {data}") return data["data"]["file_key"] ``` ```python def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Upload file to Feishu and send") parser.add_argument("--file", required=True, help="Local file path") parser.add_argument("--receive-id", default=None, help="chat_id or open_id") parser.add_argument( "--receive-id-type", default=None, help="chat_id / open_id / user_id (auto-detect if omitted)", ) parser.add_argument( "--file-type", default="stream", help="file_type for upload, default stream", ) return parser.parse_args() def main() -> None: args = parse_args() file_path = Path(args.file) if not file_path.exists(): raise FileNotFoundError(f"File not found: {file_path}") config = load_openclaw_config() app_id, app_secret = resolve_feishu_account(config) receive_id = resolve_receive_id(args.receive_id) receive_id_type = infer_receive_id_type(receive_id, args.receive ...[truncated 2755 chars]
- Remediation
- ## Remediation Suggestions 1. Resolve the requested path using `Path.resolve(strict=True)` before opening it. 2. Restrict uploads to approved OpenStoryline output roots, such as the current session's render directory. 3. Use `Path.relative_to()` against a trusted canonical output root and reject paths outside that root. 4. Require `Path.is_file()` and reject symbolic links or resolve them before containment validation. 5. Allow only expected video extensions such as `.mp4`, and validate the actual media format rather than relying solely on the filename. 6. Associate the file with the active `session_id` and require it to match a generated `output_*.mp4` artifact. 7. Display the canonical file path, size, and Feishu recipient and require explicit user confirmation before upload. 8. Validate `receive_id_type` against a fixed allowlist and ensure the recipient matches the active conversation where possible. 9. Avoid logging access tokens, application secrets, or complete API responses that could contain sensitive metadata.
