Obot: Server-Side Request Forgery via Remote MCP Server URL
Obot let privileged users register a remote MCP server pointing at any internal address, including the cloud metadata service, causing Obot to silently fetch it server-side and leak the response in…
The problem
Obot accepted the URL field of a remote MCP server registration after only checking that the scheme was http or https. No validation was done on the resolved IP address.
The server then contacted that URL automatically during reconciliation to fetch OAuth discovery metadata. The only existing guard, DisallowLocalhostMCP, was off by default and was not applied to the OAuth metadata fetch path at all. Because Obot reflected the fetched response body in its error messages, the SSRF was non-blind: an attacker with Power User or higher role could read full responses from internal services, including cloud IAM credentials from 169.254.169.254.
Proof of concept
A working proof-of-concept for this issue in github.com/obot-platform/obot, with the exact payload below.
POST /api/mcp-servers HTTP/1.1
Host: <obot-instance>
Authorization: Bearer <power-user-token>
Content-Type: application/json
{
"name": "ssrf-probe",
"remoteConfig": {
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}
}The patch (PR #6935) introduced three new dial-time blocklist flags, DisallowLocalhostMCP, DisallowPrivateIPMCP, and DisallowLinkLocalMCP, all defaulting to true. Their absence before v0.23.0 is what made the attack work: any IP that resolved from the attacker-supplied URL was dialed without restriction.
The fix resolves the hostname to its IP at dial time and rejects the connection if it falls inside loopback (127.0.0.0/8), link-local (169.254.0.0/16, fe80::/10), RFC1918 private ranges, or IPv6 ULA. This chokepoint is applied uniformly to both the remote-MCP client and the OAuth metadata client, closing the metadata-fetch path that the old DisallowLocalhostMCP flag never covered.
Root cause is CWE-918 (SSRF) combined with CWE-1188 (insecure default: the loopback guard existed but was disabled by default and incomplete in scope).
The fix
Upgrade to Obot v0.23.0 or later. The three egress guards are enabled by default in that release and require no extra configuration. Avoid setting OBOT_SERVER_DISALLOW_LOCALHOST_MCP=false, OBOT_SERVER_DISALLOW_PRIVATE_IPMCP=false, or OBOT_SERVER_DISALLOW_LINK_LOCAL_MCP=false unless the Obot server genuinely needs to reach internal services, and scope that access with additional network-layer controls.
Reported by HE WEI (ギカク).
Related research
- high · 8.8Obot: OAuth Dynamic Client Registration Enables API Token Theft via Audience Confusion
- high · 8.8Komari: Management Interface CSRF Leading to Remote Code Execution
- highCVE-2026-55245CVE-2026-55245: Bifrost isPublicIP SSRF Deny-List Bypass via NAT64, 6to4, and CGNAT
- high · 8.4CVE-2026-55581CVE-2026-55581: mcp-shell Secure Mode Allowlist Bypass via /bin/bash -c