Skip to content

fix: SSRF protection missing on MCP OAuth metadata fetch and remote transport data plane #3034

@ronan-thibaut-glitch

Description

@ronan-thibaut-glitch

Summary

Two code paths in docker-agent issue outbound HTTP requests without the
SSRF guard provided by httpclient.NewSafeClient / NewSSRFSafeTransport.
Both were identified during the audit that led to PR #3031.

FINDING-005 -- pkg/tools/mcp/oauth_login.go OAuth metadata fetch (HIGH)

PerformOAuthLogin uses an unguarded &http.Client{Timeout: 5s} as
oauth.metadataClient for authorization server metadata discovery.

Attack path: the MCP server returns a /.well-known/oauth-protected-resource
response whose authorization_servers field is attacker-controlled. The
metadataClient follows that URL unconditionally, reaching any internal
host the attacker specifies (e.g. http://169.254.169.254/).

Fix: replace with httpclient.NewSafeClient(5s, false). PR pending.

FINDING-006 -- pkg/tools/mcp/remote.go data plane transport (LOW)

headerTransport() returns http.DefaultTransport unconditionally.
The allowPrivateIPs flag controls the OAuth helper client only -- it
has no effect on the data channel connection.

This is a contract inconsistency rather than a direct SSRF attack path:
the MCP server URL is operator-supplied (not attacker-supplied), so
pointing it at an internal address is self-inflicted. However, when
allowPrivateIPs: false is set, the documented behaviour is that private
addresses are blocked -- the data plane does not honour that contract.

Fix: make headerTransport() return httpclient.NewSSRFSafeTransport()
when allowPrivateIPs is false. Separate PR, lower urgency.

References

Metadata

Metadata

Labels

area/mcpMCP protocol, MCP tool servers, integrationarea/securityAuthentication, authorization, secrets, vulnerabilities

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions