{"record":{"id":"43da25ffc2dc3e45","repo":"Tencent/WeKnora","slug":"mcp-service-is-required","errorCode":null,"errorMessage":"MCP service is required","messagePattern":"MCP service is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/security.go","lineNumber":17,"sourceCode":"package mcp\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/Tencent/WeKnora/internal/types\"\n\tsecutils \"github.com/Tencent/WeKnora/internal/utils\"\n)\n\n// ValidateServiceOutboundURLs validates every URL that the MCP transport or\n// OAuth discovery flow may contact. It is intentionally called both at\n// 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","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/security.go#L1-L35","documentation":"ValidateServiceOutboundURLs enforces the SSRF policy on every URL an MCP service may contact. This error is returned when the function is called with a nil *types.MCPService pointer. It is a guard against validating a nonexistent service record.","triggerScenarios":"Passing a nil *types.MCPService to ValidateServiceOutboundURLs — e.g. a lookup returned no row but the code proceeded, or a JSON decode produced a nil pointer.","commonSituations":"CreateMCPService/UpdateMCPService handlers invoked with a missing/unparsed request body; imported or migrated rows failing to materialize into a service struct; test harness passing nil to check guard behavior.","solutions":["Ensure the MCPService is constructed and non-nil before calling validation (check decode/unmarshal errors from the request body).","Return a 400 Bad Request to clients that submit an empty service payload instead of reaching validation with nil.","If a lookup can miss, check for not-found before validation and return your domain not-found error.","In tests, pass a minimal valid MCPService{} rather than nil unless testing the guard itself."],"exampleFix":"// before\nvar svc *types.MCPService\n_ = json.NewDecoder(r.Body).Decode(&svc)\nif err := ValidateServiceOutboundURLs(svc); err != nil { ... }\n// after\nsvc := &types.MCPService{}\nif err := json.NewDecoder(r.Body).Decode(svc); err != nil {\n    return nil, fmt.Errorf(\"invalid MCP service payload: %w\", err)\n}\nif err := ValidateServiceOutboundURLs(svc); err != nil { ... }","handlingStrategy":"validation","validationCode":"if service == nil {\n    return fmt.Errorf(\"MCP service is required\")\n}","typeGuard":"func serviceProvided(s *types.MCPService) bool { return s != nil }","tryCatchPattern":"if err := ValidateServiceOutboundURLs(service); err != nil {\n    if strings.Contains(err.Error(), \"is required\") {\n        return httpBadRequest(\"MCP service payload missing\")\n    }\n    return err\n}","preventionTips":["Always decode request bodies into a non-nil value and surface decode errors early.","Check repository lookups for not-found before validation.","Add a nil check at handler entry for all pointer-shaped request payloads.","In tests, construct a minimal &types.MCPService{} instead of passing nil unintentionally."],"tags":["validation","ssrf","mcp","nil-pointer"],"backgroundTag":"ssrf-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}