T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/update_stock_list.py:17- Finding
Unrestricted Path Traversal in Image Selection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/update_stock_list.py, lines 17–18
Vulnerability Type: Path traversal leading to unauthorized local file access
Risk Level: MediumVulnerable Code
python def ocr_stocks(uuid: str) -> list: """Use RapidOCR to recognize stocks in an image.""" try: from rapidocr_onnxruntime import RapidOCR import cv2 img_path = f"/Users/wy/.openclaw/media/inbound/{uuid}.jpg" img = cv2.imread(img_path) if img is None: print(f"Image does not exist: {img_path}") return []Technical Analysis
The
uuidcommand-line value is interpolated directly into a filesystem path without format validation, path normalization, or a containment check. Although the application appends.jpg, an attacker can include../path segments in the value to escape the intended/Users/wy/.openclaw/media/inbound/directory.cv2.imread()consequently attempts to read the attacker-selected path using the permissions of the process running the Skill. The attack is limited to files that OpenCV can decode as images and whose resulting path ends in.jpg, but it still violates the intended directory boundary.Attack Path
- An attacker or untrusted caller gains control of the positional
uuidargument supplied toupdate_stock_list.py. - The attacker supplies a traversal value such as
../../../../tmp/target. - The application constructs a path similar to:
/Users/wy/.openclaw/media/inbound/../../../../tmp/target.jpg. - The operating system resolves the traversal segments, causing
cv2.imread()to access/tmp/target.jpgrather than a file in the inbound media directory. - RapidOCR processes the external image. Recognized six-digit strings are displayed as stock codes and may be written to
manual_stock_list.jsonunless--dry-runis used.
Impact Assessment
The issue ...[truncated 548 chars]
- An attacker or untrusted caller gains control of the positional
- Remediation
View remediation
Remediation Suggestions
- Validate the argument as an actual UUID before constructing the path, rejecting path separators, traversal sequences, and malformed identifiers.
- Resolve both the trusted base directory and candidate path, then verify that the candidate remains beneath the trusted directory.
- Reject symlinks where the deployment model permits untrusted users to create files in the inbound directory.
- Avoid exposing full local filesystem paths in user-facing error messages.
- Add tests covering absolute paths,
../traversal, encoded separators, malformed UUIDs, and symlink escapes.
Example hardened implementation:
python from pathlib import Path from uuid import UUID INBOUND_DIR = Path("/Users/wy/.openclaw/media/inbound").resolve() def trusted_image_path(value: str) -> Path: canonical_uuid = str(UUID(value)) candidate = (INBOUND_DIR / f"{canonical_uuid}.jpg").resolve() try: candidate.relative_to(INBOUND_DIR) except ValueError: raise ValueError("Image path is outside the inbound directory") if not candidate.is_file() or candidate.is_symlink(): raise ValueError("Image does not exist or is not an allowed file") return candidate
