{"record":{"id":"b5ed5ae37e08a700","repo":"Tencent/WeKnora","slug":"outbound-request-blocked-request-url-is-required","errorCode":null,"errorMessage":"outbound request blocked: request URL is required","messagePattern":"outbound request blocked: request URL is required","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":746,"sourceCode":"\t\t\treturn fmt.Errorf(\"%w: %w\", ErrSSRFRedirectBlocked, err)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// SSRFValidatingRoundTripper enforces the URL policy for every outbound\n// request, including URLs discovered at runtime by SDKs (for example OAuth\n// metadata) that never passed through an application handler. Dial-time checks\n// remain necessary to pin DNS answers and cover transports that cannot accept\n// this wrapper directly.\ntype SSRFValidatingRoundTripper struct {\n\tBase http.RoundTripper\n}\n\nfunc (t *SSRFValidatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {\n\tif req == nil || req.URL == nil {\n\t\treturn nil, fmt.Errorf(\"outbound request blocked: request URL is required\")\n\t}\n\tif t == nil || t.Base == nil {\n\t\treturn nil, fmt.Errorf(\"outbound request blocked: base transport is required\")\n\t}\n\tif err := validateURLForSSRFForOutbound(req.URL.String()); err != nil {\n\t\treturn nil, fmt.Errorf(\"outbound request blocked by SSRF policy: %w\", err)\n\t}\n\treturn t.Base.RoundTrip(req)\n}\n\n// NewSSRFSafeHTTPClientWithTransport wraps a caller-supplied transport in an\n// *http.Client carrying the given timeout and the SSRF-aware redirect policy.\n// Pass a transport from NewSSRFSafeTransport (optionally shared across clients)\n// to reuse a single connection pool while keeping per-client timeouts.\nfunc NewSSRFSafeHTTPClientWithTransport(\n\tconfig SSRFSafeHTTPClientConfig, transport http.RoundTripper,\n) *http.Client {\n\tif transport == nil {","sourceCodeStart":728,"sourceCodeEnd":764,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L728-L764","documentation":"SSRFValidatingRoundTripper.RoundTrip returns this error when the incoming *http.Request is nil or has a nil URL — there is nothing to validate or send. It is a defensive precondition check before SSRF validation and transport dispatch.","triggerScenarios":"Calling RoundTrip directly (as in TestSSRFValidatingRoundTripperUsesOutboundCache) with a nil request or a request constructed without a URL, e.g. &http.Request{} with no URL field set.","commonSituations":"Hand-rolling requests in tests or custom transports, requests deserialized incorrectly, or middleware that drops the URL before the round tripper runs.","solutions":["Ensure the request has a non-nil URL before dispatch: http.NewRequest always sets it — use it instead of struct literals.","Guard callers that may pass nil requests into the transport.","If building requests manually, set req.URL = parsedURL before calling RoundTrip."],"exampleFix":"// before\nreq := &http.Request{Header: http.Header{}}\nresp, err := rt.RoundTrip(req) // URL is nil\n// after\nreq, _ := http.NewRequest(http.MethodGet, \"https://example.com\", nil)\nresp, err := rt.RoundTrip(req)","handlingStrategy":"type-guard","validationCode":"if req == nil || req.URL == nil { return errors.New(\"request and request.URL are required\") }","typeGuard":"func isSendable(req *http.Request) bool { return req != nil && req.URL != nil }","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"request URL is required\") {\n    return fmt.Errorf(\"malformed request reached transport: %w\", err)\n}","preventionTips":["Always construct requests with http.NewRequest, not struct literals.","Nil-check requests in custom middleware before transport dispatch.","Add a unit test that RoundTrip rejects nil/URL-less requests."],"tags":["http","ssrf","transport","validation"],"backgroundTag":"invalid-http-request","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}