T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/gen.py:115- Finding
Undocumented Arbitrary Local File Upload to a Configurable Remote Endpoint
- Content
View full analysis
Vulnerability Details
File Location:
scripts/gen.py:115-141, 203-224
Vulnerability Type: Arbitrary local file disclosure through undocumented image-editing functionality
Risk Level: HighVulnerable Code
python # Image file img_data = image_path.read_bytes() img_mime = "image/jpeg" if image_path.suffix.lower() in (".jpg", ".jpeg") else "image/png" parts.append( ( f"--{boundary}\r\n" f'Content-Disposition: form-data; name="image"; filename="{image_path.name}"\r\n' f"Content-Type: {img_mime}\r\n\r\n" ).encode("utf-8") + img_data + b"\r\n" ) parts.append(f"--{boundary}--\r\n".encode("utf-8")) body = b"".join(parts) req = urllib.request.Request( url, method="POST", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": f"multipart/form-data; boundary={boundary}", }, data=body, )python if args.input: # Edit mode input_path = args.input.strip() if input_path.startswith("http"): print(f"Downloading input image...", file=sys.stderr) local_input = download_to_temp(input_path) else: local_input = Path(input_path) print(f"Editing image with model={args.model} format={response_format}...", file=sys.stderr) response = request_edit( base_url=base_url, api_key=api_key, prompt=args.prompt, model=args.model, image_path=local_input, response_format=response_format, size=args.size, aspect_ratio=args.aspect_ratio, count=args.count, )Technical Analysis
The
--inputargument accepts an arbitrary local path. The selected file is read in full withPath.read_bytes()and included in a multipart request to${VAPI_BASE_URL}/images/edits.The implementation does not:
- Restrict files to an approved media directory.
- Verify that the selected file is an image by inspe ...[truncated 1942 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove edit mode if it is not part of the intended and documented Skill functionality.
- If editing is required, document clearly that the selected image and prompt are transmitted to the configured API provider.
- Require explicit user approval immediately before uploading a local file.
- Resolve the path with
Path.resolve()and constrain it to one or more user-approved media directories. - Reject symlinks or validate their fully resolved targets to prevent directory-boundary bypass.
- Validate image content using a trusted image decoder rather than relying on the filename extension.
- Allow only explicitly supported image formats and enforce conservative file-size and pixel-count limits.
- Reject sensitive locations, device files, sockets, and other non-regular files.
- Display the resolved destination host and local source path before transmission.
- Keep edit functionality separate from generation functionality so generation does not require broad local-file access.
