T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/dlna_push.py:125
- Finding
- Temporary DLNA Push Server Exposes the Selected File's Entire Parent Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dlna_push.py:125-127` and `scripts/dlna_push.py:178-181` **Vulnerability Type**: Unauthenticated file and directory exposure **Risk Level**: Medium ### Vulnerable Code ```python def start_http_server(root_dir: Path, host: str, port: int): cmd = [sys.executable, '-m', 'http.server', str(port), '--bind', host, '--directory', str(root_dir)] proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(0.8) if proc.poll() is not None: raise RuntimeError('HTTP server exited immediately') return proc ``` ```python http_root = track.parent server = start_http_server(http_root, serve_ip, serve_port) file_url = f'http://{serve_ip}:{serve_port}/{urllib.request.pathname2url(track.name)}' metadata = didl_for(file_url, track) ``` ### Technical Analysis The single-track DLNA push workflow starts Python's generic `http.server` with the selected track's parent directory as its document root. The standard handler permits unauthenticated retrieval of every file below that directory and generates directory listings when a directory URL is requested. Consequently, the implementation exposes more data than the single selected audio file. It can also expose non-audio files stored beside the track. Binding to the automatically detected LAN interface makes the service reachable by other devices on the same network, subject to host firewall rules. The server stays active after the push operation so the receiver can fetch the media. It remains available until the user runs the `stop` command, the process terminates, or an external mechanism kills it. The documentation mentions temporary HTTP serving but does not clearly disclose that the entire parent directory is browsable. ### Attack Path 1. A user pushes an audio file using `dlna_push.py push`. 2. The script resolves the selected track and uses `track.parent` as the HTTP document root. 3. It launches an ...[truncated 835 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace `python -m http.server` with a dedicated HTTP handler that serves exactly one selected file. 2. Expose the file through a cryptographically random, unguessable URL path rather than its original filename. 3. Return `404` for directory paths and all resources other than the selected file. 4. Do not enable directory listing or recursive access to the parent directory. 5. Where practical, restrict requests to the receiver's source IP address. 6. Add an automatic expiration timer and terminate the server after playback or a short configurable timeout. 7. Ensure error and shutdown paths remove saved state and terminate the server. 8. Explicitly warn users that the selected media becomes reachable over the LAN for the duration of playback. ]]>
