T09 · Insecure Skill Coding Practices
Error
- Location
- web/app.py:42
- Finding
- Arbitrary File Overwrite and Deletion Through Unsanitized Upload Filename<![CDATA[ ## Vulnerability Details **File Location**: `web/app.py:42-59` **Vulnerability Type**: Path traversal and unsafe temporary-file handling **Risk Level**: Critical ### Vulnerable Code ```python @app.route('/upload', methods=['POST']) def upload_file(): if 'file' not in request.files: return jsonify({'error': '没有选择文件'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': '没有选择文件'}), 400 if file and allowed_file(file.filename): # 保存临时文件 temp_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename) file.save(temp_path) # 生成波形数据 waveform = get_waveform_data(temp_path) # 删除临时文件 os.unlink(temp_path) return jsonify(waveform) return jsonify({'error': '不支持的文件格式'}), 400 ``` ### Technical Analysis The multipart filename is controlled by the requester and is used directly as a filesystem path. The application neither applies `werkzeug.utils.secure_filename` nor generates a server-controlled temporary filename. `os.path.join()` does not guarantee that the resulting path remains under `UPLOAD_FOLDER`. A filename containing parent-directory components can escape the temporary directory. On platforms where an absolute path is accepted as the uploaded filename, the absolute component can also replace the configured temporary directory entirely. The extension allowlist does not prevent the vulnerability. An attacker only needs to target a writable path whose final extension is one of `mp3`, `wav`, `flac`, `ogg`, or `m4a`. After saving attacker-controlled content to that path, the application unconditionally calls `os.unlink(temp_path)`. Audio parsing failures are caught inside `get_waveform_data()`, so an invalid audio payload does not prevent the subsequent deletion. The use of a predictable, client-selected temporary path also permits filename collisions and creates symlink-related risks in a shared temporary directory. ### ...[truncated 1382 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Never derive a server-side path from the submitted filename. - Create a unique server-controlled file with `tempfile.NamedTemporaryFile`, `tempfile.mkstemp`, or an equivalent safe API. - Preserve the original filename only as non-path metadata. - If a filename must be retained, apply `secure_filename()` and verify with `os.path.realpath()` that the final path remains inside a dedicated, private upload directory. - Reject absolute paths, path separators, parent-directory components, and empty normalized filenames. - Open temporary files using exclusive creation semantics to prevent collisions. - Do not use a shared predictable path in the system-wide temporary directory. - Delete the generated temporary file in a `finally` block, but only after confirming that it is the exact server-created file. - Run the service under a dedicated low-privilege account with access only to required directories. ]]>
