Fix SSRF (Server Side Request Forgery) in Chi
SSRF (Server-Side Request Forgery) in Go/Chi applications allows attackers to abuse the server's network identity to scan internal ports, hit cloud metadata services (169.254.169.254), or bypass firewalls. If your Chi handler fetches a URL provided by a user without strict validation, your backend is a proxy for the attacker. To mitigate this, you must implement a multi-layered defense: protocol enforcement, domain allowlisting, and IP-level validation to block private address ranges.
The Vulnerable Pattern
func (s *Server) VulnerableHandler(w http.ResponseWriter, r *http.Request) {
targetURL := r.URL.Query().Get("url")
// CRITICAL: Blindly fetching user-provided URL
resp, err := http.Get(targetURL)
if err != nil {
http.Error(w, "Failed to fetch", 500)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
The Secure Implementation
The secure implementation introduces three critical checks. First, it enforces the 'http' and 'https' schemes to prevent protocol smuggling (e.g., file:// or gopher://). Second, it uses a strict domain allowlist to ensure the server only communicates with known entities. Finally, it performs a DNS lookup and inspects the resulting IP addresses. By checking 'ip.IsPrivate()' and 'ip.IsLoopback()', the code prevents the server from connecting to its own localhost or internal network segments (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). For production-grade security, consider using a custom 'http.Transport' with a 'DialContext' that validates IPs after DNS resolution to prevent DNS rebinding attacks.
func isSafe(urlStr string) (string, error) { u, err := url.Parse(urlStr) if err != nil || (u.Scheme != "http" && u.Scheme != "https") { return "", errors.New("invalid scheme") } allowedDomains := map[string]bool{"api.trusted.com": true, "images.trusted.com": true} if !allowedDomains[u.Hostname()] { return "", errors.New("domain not allowed") } addrs, err := net.LookupHost(u.Hostname()) if err != nil { return "", err } for _, addr := range addrs { ip := net.ParseIP(addr) if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { return "", errors.New("internal IP detected") } } return u.String(), nil }
func (s *Server) SecureHandler(w http.ResponseWriter, r *http.Request) { target := r.URL.Query().Get(“url”) validatedURL, err := isSafe(target) if err != nil { http.Error(w, “Forbidden: “+err.Error(), 403) return } client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Get(validatedURL) if err != nil { http.Error(w, “Request failed”, 502) return } defer resp.Body.Close() io.Copy(w, resp.Body) }
Your Chi API
might be exposed to SSRF (Server Side Request Forgery)
74% of Chi apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.