T09 · Insecure Skill Coding Practices
- Location
scripts/upload-files.py:127- Finding
Local File Disclosure Through an Unvalidated Upload URL
- Content
View full analysis
bool: """Asynchronously upload a file to a pre-signed URL.""" if not HAS_AIOHTTP: # Execute the synchronous upload in a thread pool. loop = asyncio.get_event_loop() return await loop.run_in_executor( None, self.upload_file_sync, upload_url, file_path, mime_type ) # Read the complete local file. loop = asyncio.get_event_loop() data = await loop.run_in_executor(None, Path(file_path).read_bytes) async with aiohttp.ClientSession() as session: headers = {'Content-Type': mime_type} async with session.put(upload_url, data=data, headers=headers) as response: return response.status in (200, 201) def upload_file_sync(self, upload_url: str, file_path: str, mime_type: str) -> bool: """Synchronously upload a file to a pre-signed URL.""" with open(file_path, 'rb') as f: data = f.read() headers = {'Content-Type': mime_type} response = requests.put(upload_url, data=data, headers=headers) return response.status_code in (200, 201) ``` Related instructions in `references/files.md` and `references/blocks.md` similarly direct the agent to send local file contents to the URL returned by the MCP service: ```bash curl -X PUT \ -H "Content-Type: " \ --data-binary "@" \ "" ``` ### Technical Analysis The upload feature legitimately requires transmitting a user-selected file to a pre-signed object-storage URL. However, the implementation treats `upload_url` as fully trusted and performs no validation of: - The URL scheme, including whether HTTPS is required. - The des ...[truncated 2300 chars]- Remediation
View remediation
