T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/index.py:101
- Finding
- Unrestricted Local File Read and Upload to External Recognition API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/index.py:101-103`, `scripts/index.py:163-183`, and `scripts/index.py:247` **Vulnerability Type**: Unrestricted local-file upload caused by insufficient path and file validation **Risk Level**: High ### Vulnerable Code ```python # scripts/index.py:101-103 with open(file_path, "rb") as file: encoded_string = base64.b64encode(file.read()) return encoded_string.decode("utf-8") ``` ```python # scripts/index.py:163-183 if not os.path.exists(file_path): return {"error": f"Audio file not found: {file_path}"} print(f"Starting song recognition:") print(f" Audio file: {file_path}") print(f" Audio encoding: {encoding}") print(f" Sample rate: {sample_rate}") encoded_file = self.encode_file(file_path) if not encoded_file: return {"error": "Failed to encode song file"} request_body = self.build_request_body(encoded_file, encoding, sample_rate) signed_url = self.create_signed_url(self.host_url, "POST") print("Calling song recognition API...") response = requests.post( signed_url, json=request_body, timeout=self.timeout ) ``` ```python # scripts/index.py:247 audio_path = sys.argv[1] ``` ### Technical Analysis The Skill accepts a caller-controlled filesystem path from the command line and validates only whether that path exists. It does not verify that the path: - Resolves to a regular file rather than a directory, device, or other special object. - Is located within an approved audio-upload or workspace directory. - Is not a symbolic link to another file. - Contains valid MP3 or supported audio data. - Satisfies a safe maximum file-size limit. The selected file is read in full, Base64-encoded, placed in `payload.data.audio`, and transmitted over HTTPS to the fixed iFlytek endpoint at `cn-east-1.api.xf-yun.com`. Base64 encoding is necessary for the documented API transport and is not, by itself, evidence of covert exfiltration. Uploading user-selected audio is also inheren ...[truncated 2327 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Restrict accessible paths** - Resolve the supplied path with `Path.resolve(strict=True)`. - Require the resolved path to remain under an explicitly approved upload or workspace directory. - Reject paths outside that directory. 2. **Reject symbolic links and non-regular files** - Use `lstat()` and reject symbolic links. - Require `Path.is_file()` and a regular-file mode. - Where supported, open files with protections such as `O_NOFOLLOW` to reduce time-of-check/time-of-use and symlink attacks. 3. **Validate actual audio content** - Do not rely only on filename extensions or caller-provided encoding values. - Check an allowlist of supported extensions and MIME types. - Parse or decode the file with a trusted audio library and reject malformed or unsupported content before transmission. 4. **Enforce resource limits** - Define a conservative maximum file size based on the API's documented limits. - Check file size before reading. - Avoid unbounded `file.read()` operations, and fail safely when the limit is exceeded. 5. **Require informed upload authorization** - Clearly identify the destination service and state that the selected file will be uploaded. - In interactive or agent-controlled environments, require explicit confirmation for files outside a designated user-upload area. 6. **Minimize information disclosure** - Avoid printing full sensitive filesystem paths unless required. - Return generic validation errors to untrusted callers while retaining appropriately protected diagnostic logs. 7. **Add security tests** - Verify rejection of paths outside the approved directory. - Verify rejection of symbolic links, special files, non-audio files, oversized files, and malformed audio. - Verify that only explicitly selected and validated audio reaches the network request. ]]>
