T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/file_utils.py:18- Finding
Path Traversal Through Unsanitized Order Numbers
- Content
View full analysis
Path: return openclaw_order_root() / indicator def order_path(indicator: str, order_no: str) -> Path: return order_root(indicator) / f"{order_no}.json" def save_order(indicator: str, order_no: str, payload: dict) -> Path: path = order_path(indicator, order_no) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") return path def load_order(indicator: str, order_no: str) -> dict: path = order_path(indicator, order_no) if not path.exists(): raise FileNotFoundError(f"order file not found: {path}") return json.loads(path.read_text(encoding="utf-8")) ``` Remote data reaches the write operation through: ```python body = request_json(f"{resolve_base_url()}/api/skill/create-order", {"question": question}) order_no = body["order_no"] save_order( INDICATOR, order_no, { "skill-id": SLUG, "skill_id": SLUG, "order_no": order_no, "amount": body["amount_fen"], "question": question, "encrypted_data": body["encrypted_data"], "pay_to": body["pay_to"], "description": body["description"], "slug": SLUG, "resource_url": body["resource_url"], }, ) ``` User input reaches the read operation through: ```python order_no = sys.argv[1] try: order = load_order(INDICATOR, order_no) credential = order.get("payCredential") or order.get("credential") if not credential: raise RuntimeError("payment credential not found in order file") payload = request_json( f"{resolve_base_url()}/api/skill/fulfill", ...[truncated 2699 chars]- Remediation
View remediation
str: if not ORDER_NO_PATTERN.fullmatch(order_no): raise ValueError("invalid order number") return order_no ``` 2. Resolve both the root and candidate path, then verify containment: ```python def order_path(indicator: str, order_no: str) -> Path: validate_order_no(order_no) root = order_root(indicator).resolve() candidate = (root / f"{order_no}.json").resolve() if candidate.parent != root: raise ValueError("order path escapes order root") return candidate ``` 3. Reject absolute paths, path separators, `.` and `..` components before any filesystem operation. 4. Validate server-returned `order_no` values before saving them. 5. Apply the same validation to command-line order numbers before loading an order. 6. Use exclusive or atomic file creation where overwriting an existing order is not intended. 7. Add tests covering Unix and Windows traversal forms, including `../`, `..\`, absolute paths, drive prefixes, and encoded separator variants. ]]>
