T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/visualize.py:256
- Finding
- COCO Filename Path Traversal Enables Arbitrary Image File Access and Overwrite## Vulnerability Details **File Location**: `scripts/visualize.py`, lines 256-258 and 285 **Vulnerability Type**: Unvalidated path traversal and absolute-path injection **Risk Level**: High ### Vulnerable Code ```python img_info = images.get(img_id, {}) img_name = img_info.get('file_name', f'{img_id}.jpg') img_path = images_dir / img_name if not img_path.exists(): continue ``` ```python output_path = output_dir / img_name visualize_image( str(img_path), annotations, str(output_path), thickness=args.thickness, fill=args.fill, show_label=args.show_label, font_size=args.font_size ) ``` The destination is subsequently created and written in `visualize_image`: ```python os.makedirs(os.path.dirname(output_path) if os.path.dirname(output_path) else '.', exist_ok=True) img.save(output_path) ``` ### Technical Analysis The COCO `file_name` property is taken directly from an attacker-controlled JSON annotation and used to construct both input and output paths. The code does not reject absolute paths, `..` path components, or resolved paths outside the configured image and output directories. With `pathlib`, joining a base path to an absolute second operand discards the base path. Relative traversal components can similarly escape the intended directory after path resolution. Consequently, `img_path` can refer to any image file readable by the invoking user, while `output_path` can refer to a location outside the designated output directory. The output function also creates missing parent directories and saves the rendered image without checking whether the destination remains within the approved output directory. ### Attack Path 1. An attacker prepares a COCO JSON document containing an image entry whose `file_name` is an absolute path or includes traversal components, such as `/home/user/important.png` or `../../important.png`. 2. The victim invokes the documented command: ```ba ...[truncated 1359 chars]
- Remediation
- ## Remediation Suggestions Treat every COCO `file_name` value as untrusted input: 1. Reject absolute filenames. 2. Resolve the candidate input and output paths before accessing them. 3. Verify with `Path.relative_to()` or `Path.is_relative_to()` that each resolved path remains under its authorized base directory. 4. Reject filenames containing parent-directory traversal components. 5. Use a sanitized basename or an internally generated filename for output rather than reproducing the input path. 6. Refuse to overwrite existing output files unless explicitly authorized. 7. Avoid automatically creating directories derived from untrusted filenames. Example hardening pattern: ```python images_root = Path(args.images).resolve() output_root = Path(args.output).resolve() supplied_name = Path(img_name) if supplied_name.is_absolute() or ".." in supplied_name.parts: raise ValueError(f"Unsafe COCO filename: {img_name}") input_path = (images_root / supplied_name).resolve() if not input_path.is_relative_to(images_root): raise ValueError(f"Input path escapes images directory: {img_name}") safe_output_name = supplied_name.name output_path = (output_root / safe_output_name).resolve() if not output_path.is_relative_to(output_root): raise ValueError(f"Output path escapes output directory: {img_name}") ``` Where support for older Python versions is required, replace `is_relative_to()` with a guarded `relative_to()` call.
