{"record":{"id":"39f5530e77291366","repo":"Tencent/WeKnora","slug":"outbound-request-blocked-base-transport-is-requir","errorCode":null,"errorMessage":"outbound request blocked: base transport is required","messagePattern":"outbound request blocked: base transport is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":749,"sourceCode":"\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 {\n\t\ttransport = NewSSRFSafeTransport(config)\n\t}\n\treturn &http.Client{","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L731-L767","documentation":"SSRFValidatingRoundTripper.RoundTrip refuses to send the request because the wrapper's Base transport field is nil. The round tripper is purely a validation/delegation layer; without an underlying http.RoundTripper there is nowhere to forward the request, so the library fails fast instead of panicking with a nil pointer dereference. It is a construction/initialization bug, not a network or policy problem.","triggerScenarios":"Calling RoundTrip (directly or via http.Transport/Client using this as RoundTripper) on an SSRFValidatingRoundTripper value created as a zero value (&SSRFValidatingRoundTripper{}) or via a constructor path that never set Base. The test TestSSRFValidatingRoundTripperUsesOutboundCache exercises this wrapper and surfaces it when Base is unset.","commonSituations":"Declaring the round tripper as a struct literal without assigning Base; copying the wrapper by value after construction in a way that drops the field; wiring it into an http.Client before the underlying transport is initialized; refactoring that renamed/removed the field initialization.","solutions":["Set Base to a real transport, e.g. &SSRFValidatingRoundTripper{Base: http.DefaultTransport} (or a custom *http.Transport) before using it.","Use the library's constructor (e.g. NewSSRFSafeHTTPClientWithTransport / equivalent NewSSRFValidatingRoundTripper) instead of a raw struct literal so Base is always populated.","Add an init-time check in your setup code: if rt.Base == nil { return errors.New(\"round tripper not initialized\") } to fail at startup rather than at request time."],"exampleFix":"// before\nclient := &http.Client{Transport: &utils.SSRFValidatingRoundTripper{}}\n\n// after\nclient := &http.Client{Transport: &utils.SSRFValidatingRoundTripper{Base: http.DefaultTransport}}","handlingStrategy":"validation","validationCode":"if rt == nil || rt.Base == nil {\n    return fmt.Errorf(\"SSRFValidatingRoundTripper not initialized: Base transport is nil\")\n}","typeGuard":"func isReadySSRFRoundTripper(t *utils.SSRFValidatingRoundTripper) bool {\n    return t != nil && t.Base != nil\n}","tryCatchPattern":null,"preventionTips":["Always construct the round tripper through its constructor rather than a raw struct literal.","Assert Base != nil in application startup/health checks before serving traffic.","Never copy SSRFValidatingRoundTripper by value after wiring it into a client."],"tags":["ssrf","http-roundtripper","nil-pointer","initialization"],"backgroundTag":"missing-required-dependency","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}