| Название | Kira-Pgr PromptShopMCP Latest Server-Side Request Forgery |
|---|
| Описание | Summary
The generate_image_from_url and remove_background tools in Image-Toolkit-MCP-Server (PromptShopMCP) are vulnerable to Server-Side Request Forgery (SSRF). The user-supplied image_url parameter is passed directly to a shared download_image() helper, which calls Python's requests.get() without validating the destination host, IP range, or protocol. This allows an attacker to make the MCP server issue arbitrary HTTP GET requests to internal network services, cloud metadata endpoints, or any other host reachable from the server process. Post-download checks (Content-Type and image validation) occur after the outbound request is already sent, so they do not prevent SSRF; they only limit whether the response is processed further. Error messages returned to the MCP client can leak HTTP status codes and Content-Type values, enabling internal port/service probing. If an internal target returns a valid image with Content-Type: image/*, the downloaded bytes may be forwarded to remove.bg, Gemini, or freeimage.host as part of normal tool processing.
Detail
Image-Toolkit-MCP-Server provides AI programming assistants (such as Claude, Gemini, and Cursor) with image generation, editing, and background-removal capabilities via the Model Context Protocol. Two tools — generate_image_from_url and remove_background — accept a caller-supplied image URL and fetch it server-side before further processing. Both tools delegate fetching to the same unconstrained helper download_image(url), which performs an unvalidated HTTP GET on any string the caller provides.
Unlike other outbound HTTP calls in this server (Gemini API, remove.bg API, freeimage.host upload), which target hardcoded third-party endpoints, download_image() grants the caller full control over the request destination.
Vulnerable entry point: shared download_image() helper
File: server.py
def download_image(url):
"""
Download an image from a URL
...
"""
try:
headers = {
"User-Agent": "GeminiImageModifier/1.0"
}
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
content_type = response.headers.get('Content-Type', '')
if not content_type.startswith('image/'):
return False, f"Not an image: Content-Type is {content_type}"
image_data = response.content
if is_safe_image(image_data):
return True, image_data
return False, "Image failed safety checks"
return False, f"Failed to download image: HTTP {response.status_code}"
except (requests.RequestException, ValueError) as request_error:
return False, f"Error downloading image: {str(request_error)}"
The user-supplied URL is passed directly to requests.get() with no intermediate validation of scheme, hostname, or resolved IP address.
Affected tool 1: generate_image_from_url
File: server.py
@mcp.tool()
def generate_image_from_url(
image_url: str,
prompt: str,
mime_type: str = "image/jpeg",
temperature: float = 1.0,
top_p: float = 0.95,
top_k: int = 40
) -> str:
...
success, result = download_image(image_url)
if not success:
raise ValueError(f"Error downloading image from URL: {result}")
...
The tool is registered via FastMCP with an unconstrained image_url: str parameter — any string value is accepted, including internal URLs such as http://127.0.0.1:8000/ssrf-test.
Affected tool 2: remove_background
File: server.py
@mcp.tool()
def remove_background(
image_url: str,
size: str = "auto"
) -> str:
...
success, image_data = download_image(image_url)
if not success:
raise ValueError(f"Error downloading image from URL: {image_data}")
...
Proof of Concept Using MCP Inspector
Prerequisites
Install Python dependencies:
cd Image-Toolkit-MCP-Server
pip install -r requirements.txt
pip install google-genai
Start the MCP server via Inspector:
npx -y @modelcontextprotocol/[email protected] `
-e GEMINI_API_KEY=test `
-e FREEIMAGE_API_KEY=test `
-e REMOVEBG_API_KEY=test `
-- "C:\Python\Python314\Scripts\mcp.exe" run server.py
This launches the MCP Inspector web UI. Open the URL printed in the terminal (includes auth token).
In a separate terminal, start a local HTTP listener to capture SSRF requests:
python -m http.server 8000
Steps
Open the Inspector URL in a browser and click Connect.
Go to the Tools tab, click List Tools, and select remove_background (or generate_image_from_url).
Invoke the tool with the following parameters:
In generate_image_from_url:
generate_image_from_url: http://127.0.0.1:8000/ssrf-test
prompt: test
In remove_background:
generate_image_from_url: http://127.0.0.1:8000/ssrf-test
Observe the listener output — the MCP server process (not the browser) issues the request:
PS C:\Users\skywings> python -m http.server 8000
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
::ffff:127.0.0.1 - - [01/Jul/2026 10:37:55] code 404, message File not found
::ffff:127.0.0.1 - - [01/Jul/2026 10:39:25] "GET /ssrf-test HTTP/1.1" 404 -
This demonstrates that the server performed the outbound GET to the attacker-specified internal URL before rejecting the non-image response.
Impact
SSRF |
|---|
| Источник | ⚠️ https://github.com/Kira-Pgr/PromptShopMCP/issues/4 |
|---|
| Пользователь | TianyuLi (UID 99360) |
|---|
| Представление | 01.07.2026 04:55 (2 месяцы назад) |
|---|
| Модерация | 17.08.2026 06:45 (2 months later) |
|---|
| Статус | принято |
|---|
| Запись VulDB | 391204 [Kira-Pgr PromptShopMCP до 5bc0cd17358e19a5415d11a531088170d7b81452 Image-Toolkit-MCP-Server server.py download_image image_url эскалация привилегий] |
|---|
| Баллы | 20 |
|---|