T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/screenshot_tool.py:365
- Finding
- Arbitrary Python Expression Evaluation of Media-Derived Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/screenshot_tool.py:365-372` **Vulnerability Type**: Unsafe use of `eval()` on FFprobe output **Risk Level**: High ### Vulnerable Code ```python # Extract information info = { 'duration': float(data.get('format', {}).get('duration', 0)), 'width': int(video_stream.get('width', 0)), 'height': int(video_stream.get('height', 0)), 'fps': eval(video_stream.get('r_frame_rate', '0/1')) } return info ``` ### Technical Analysis The `r_frame_rate` value is obtained from JSON produced by FFprobe after processing a potentially untrusted video file. The value is passed directly to Python's `eval()`, which evaluates arbitrary Python expressions rather than only parsing a rational frame rate. The expected format is a fraction such as `30000/1001`. Evaluating that format does not require `eval()`. If a crafted media container, compromised FFprobe executable, or unexpected metadata-processing path causes an attacker-controlled expression to appear in `r_frame_rate`, the expression will execute in the Python process. Exploitability through an ordinary media file depends on whether the installed FFprobe version and relevant demuxer normalize the field before serialization. Nevertheless, this remains a dangerous local code-execution sink and violates secure parsing requirements. ### Attack Path 1. An attacker supplies or publishes a specially crafted video file. 2. The user processes the file with `screenshot_tool.py` or another caller of `get_video_info()`. 3. FFprobe parses the file and returns stream metadata as JSON. 4. The application retrieves the `r_frame_rate` string. 5. The string is evaluated by Python's `eval()`. 6. If an executable expression reaches this field, it runs with the privileges of the user running the analyzer. An equivalent path exists if an attacker can replace or wrap the `ffprobe` executable resolved through the process environment. ### Impact Assessment Successful e ...[truncated 512 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Replace `eval()` with strict rational-number parsing: ```python from fractions import Fraction frame_rate = video_stream.get('r_frame_rate', '0/1') try: fps_fraction = Fraction(frame_rate) fps = float(fps_fraction) if fps_fraction.denominator != 0 else 0.0 except (ValueError, ZeroDivisionError): fps = 0.0 info = { 'duration': float(data.get('format', {}).get('duration', 0)), 'width': int(video_stream.get('width', 0)), 'height': int(video_stream.get('height', 0)), 'fps': fps, } ``` Additional hardening should include: 1. Validate the source value against an allowlist such as `^[0-9]+/[1-9][0-9]*$`. 2. Reject unexpectedly long values before parsing. 3. Resolve FFprobe from a trusted absolute path or verify the executable selected through `PATH`. 4. Process untrusted media in a restricted subprocess or sandbox where practical. 5. Add regression tests proving that Python expressions and malformed fractions cannot execute. ]]>
