T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/upload_to_wechat.py:244- Finding
Unrestricted Local File Upload Through Markdown Image References
- Content
View full analysis
Vulnerability Details
File Location:
scripts/upload_to_wechat.py, lines 83-100, 136-145, and 244-259
Vulnerability Type: Unrestricted local file access and external transmission
Risk Level: HighVulnerable Code
python def run_manual(self, title, raw_content): # 1. Look for images in content images = re.findall(r'!\[(.*?)\]\((.*?)\)', raw_content) thumb_media_id = None processed_content = raw_content # 2. Upload images found in content for i, (alt, url) in enumerate(images): logger.info(f"Processing image {i+1}: {url}") # Add cover logic: first image as cover if i == 0: thumb_media_id = self.upload_cover_image(url) # Upload for article body (returns URL) _, wechat_url = self.upload_image(url) if wechat_url: # Replace markdown image with HTML img tag processed_content = processed_content.replace(f'', f'<img src="{wechat_url}" alt="{alt}" />')python else: image_path = image_path_or_url # Check if file exists if not os.path.exists(image_path): logger.error(f"Image file not found: {image_path}") return None, None # Upload to WeChat try: with open(image_path, 'rb') as f: files = {'media': (os.path.basename(image_path), f)} r = requests.post(url, files=files) res = r.json()python else: image_path = image_path_or_url try: with open(image_path, 'rb') as f: files = {'media': (os.path.basename(image_path), f)} r = requests.post(url, files=files) res = r.json()Technical Analysis
Markdown image destinations are treated either as remote URLs or local filesystem paths. For local paths, the uploader performs no canonicalization, directory restriction, symbolic-link check, file-type validation, or authorization che ...[truncated 1782 chars]
- Remediation
View remediation
Remediation Suggestions
- Create a dedicated media directory and permit uploads only from that directory.
- Resolve every input with
Path.resolve(strict=True)and verify that the resolved path remains beneath the approved media root. - Reject symbolic links, non-regular files, device files, pipes, and sockets.
- Validate the decoded image format using a trusted image library rather than relying on the extension or API-side rejection.
- Enforce an explicit allowlist of image formats and maximum dimensions and sizes.
- Separate local-path and remote-URL inputs instead of inferring their type from a string prefix.
- Run the uploader under a dedicated, minimally privileged account that cannot read unrelated secrets.
- Require explicit user confirmation before transmitting any local file that was not generated by the current workflow.
