Ssrf Server Side in Chi (Go)
Ssrf Server Side in Chi with Go — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a Go HTTP router such as Chi occurs when user-controlled input is used to make outbound HTTP requests without adequate validation or network segregation. Chi is a lightweight, idiomatic router that does not impose a default client or restrict how you build requests, so the risk is introduced by application code that passes untrusted data into the request flow. For example, if an endpoint accepts a target URL from a client and forwards it using http.NewRequest or a custom http.Client, an attacker can supply internal addresses, cloud metadata endpoints (169.254.169.254), or service-specific schemes to probe internal infrastructure.
Chi’s pattern-matching and route parameters can inadvertently become sources of SSRRF when developers forward those parameters without strict allowlisting. Common patterns include using chi.URLParam to capture an ID or host segment and then concatenating it into a request URI, or using query parameters to decide where to proxy. Because SSRF exploits often rely on the server’s network position, SSRF in Chi with Go can expose metadata services, internal APIs, and restricted cloud endpoints. Attack patterns such as IMDS version confusion, Redis protocol injection via forwarded connections, or abuse of cloud instance metadata are realistic when the server acts as an unrestricted proxy.
In secure designs, the server should not follow arbitrary user-supplied URLs. Instead, use a strict allowlist of domains or use service-specific connectors that do not rely on dynamic host resolution from client input. middleBrick detects SSRF as one of its 12 parallel security checks, examining how the runtime behavior aligns with the OpenAPI specification and whether the unauthenticated attack surface permits request redirection to sensitive internal endpoints.
Go-Specific Remediation in Chi — concrete code fixes
Remediation focuses on preventing arbitrary URL resolution and ensuring outbound requests are constrained to known services. Below are Go-specific examples using Chi that demonstrate insecure patterns and their fixes.
Insecure pattern: forwarding a user-supplied URL
// INSECURE: directly using user input as the request target
func insecureProxy(w http.ResponseWriter, r *http.Request) {
target := r.URL.Query().Get("url")
resp, err := http.Get(target) // attacker-controlled destination
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
Secure pattern 1: strict allowlist with net/url
// SECURE: allowlist-based forwarding
var allowedHost = "api.example.com"
func secureProxy(w http.ResponseWriter, r *http.Request) {
target := r.URL.Query().Get("url")
parsed, err := url.Parse(target)
if err != nil || parsed.Host != allowedHost {
http.Error(w, "invalid target", http.StatusBadRequest)
return
}
// Ensure scheme is HTTPS to prevent SSRF via unexpected schemes
if parsed.Scheme != "https" {
http.Error(w, "unsupported scheme", http.StatusBadRequest)
return
}
req, _ := http.NewRequestWithContext(r.Context(), "GET", target, nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
Secure pattern 2: using a service client instead of generic forwarding
// SECURE: call a known internal service via a dedicated client
type WeatherClient struct {
BaseURL *url.URL
Client *http.Client
}
func (c *WeatherClient) Current(w http.ResponseWriter, r *http.Request) {
u, _ := c.BaseURL.Parse("/v1/current")
req, _ := http.NewRequestWithContext(r.Context(), "GET", u.String(), nil)
resp, err := c.Client.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
func main() {
base, _ := url.Parse("https://api.weather.example.com/")
client := &WeatherClient{
BaseURL: base,
Client: &http.Client{Timeout: 5 * time.Second},
}
r := chi.NewRouter()
r.Get("/weather", client.Current)
http.ListenAndServe(":8080", r)
}
Additional mitigations include disabling unnecessary redirect following (use a custom CheckRedirect policy), setting timeouts, and avoiding the use of http.DefaultClient in production. When integrating with external APIs, prefer typed clients and configuration-based endpoints rather than runtime URL assembly. middleBrick’s LLM/AI Security checks can also surface prompt-injection attempts that try to manipulate SSRF behavior, complementing these Go-level defenses.