{"record":{"id":"a90e0593444921c0","repo":"Tencent/WeKnora","slug":"mcp-oauth-metadata-url-failed-ssrf-validation-w","errorCode":null,"errorMessage":"MCP OAuth metadata URL failed SSRF validation: %w","messagePattern":"MCP OAuth metadata URL failed SSRF validation: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/security.go","lineNumber":31,"sourceCode":"// persistence boundaries and immediately before client construction so stale\n// or imported rows cannot bypass the current SSRF policy.\nfunc ValidateServiceOutboundURLs(service *types.MCPService) error {\n\tif service == nil {\n\t\treturn fmt.Errorf(\"MCP service is required\")\n\t}\n\tif service.URL != nil {\n\t\tserviceURL := strings.TrimSpace(*service.URL)\n\t\tif serviceURL != \"\" {\n\t\t\tif err := secutils.ValidateURLForSSRF(serviceURL); err != nil {\n\t\t\t\treturn fmt.Errorf(\"MCP service URL failed SSRF validation: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\tif service.AuthConfig != nil {\n\t\tmetadataURL := strings.TrimSpace(service.AuthConfig.AuthServerMetadataURL)\n\t\tif metadataURL != \"\" {\n\t\t\tif err := secutils.ValidateURLForSSRF(metadataURL); err != nil {\n\t\t\t\treturn fmt.Errorf(\"MCP OAuth metadata URL failed SSRF validation: %w\", err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":13,"sourceCodeEnd":37,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/security.go#L13-L37","documentation":"ValidateServiceOutboundURLs in internal/mcp/security.go:31 wraps secutils.ValidateURLForSSRF when the MCP service's OAuth AuthServerMetadataURL fails SSRF validation. OAuth discovery fetches this metadata URL server-side, so a hostile URL could probe internal networks. The wrapped error names the concrete violation.","triggerScenarios":"CreateMCPService/UpdateMCPService/NewMCPClient/newHandler with service.AuthConfig non-nil and AuthServerMetadataURL non-empty after trimming, where the URL fails ValidateURLForSSRF (private/loopback host, non-http(s) scheme, empty hostname, blocked DNS).","commonSituations":"Configuring OAuth for an internally hosted identity provider (e.g. http://keycloak.internal/.well-known/oauth-authorization-server); using an http:// metadata URL pointing at localhost during local testing; SSRF_WHITELIST not including the internal IdP host.","solutions":["Point AuthServerMetadataURL at a public https endpoint.","Whitelist the internal IdP hostname via SSRF_WHITELIST if it is a trusted internal service.","Fix the scheme to http/https and ensure the URL has a hostname.","Inspect the wrapped error (invalid scheme / no hostname / SSRF validation failed) for the exact cause."],"exampleFix":"// before\nservice.AuthConfig.AuthServerMetadataURL = \"http://127.0.0.1:8080/.well-known/oauth-authorization-server\"\n// after\nservice.AuthConfig.AuthServerMetadataURL = \"https://auth.example.com/.well-known/oauth-authorization-server\"\n// or whitelist 'auth.internal.corp' in SSRF_WHITELIST","handlingStrategy":"validation","validationCode":"if svc.AuthConfig != nil && strings.TrimSpace(svc.AuthConfig.AuthServerMetadataURL) != \"\" {\n    if err := secutils.ValidateURLForSSRF(strings.TrimSpace(svc.AuthConfig.AuthServerMetadataURL)); err != nil {\n        return fmt.Errorf(\"unacceptable OAuth metadata URL: %w\", err)\n    }\n}","typeGuard":"func hasHTTPSMetadataURL(ac *types.MCPAuthConfig) bool {\n    return ac != nil && strings.HasPrefix(strings.TrimSpace(ac.AuthServerMetadataURL), \"https://\")\n}","tryCatchPattern":null,"preventionTips":["Prefer https metadata URLs from your IdP's well-known endpoint.","Whitelist internal IdP hostnames explicitly via SSRF_WHITELIST.","Validate OAuth config in the same form as the service URL."],"tags":["ssrf","security","oauth","mcp"],"backgroundTag":"ssrf-url-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}