Fix SSRF (Server Side Request Forgery) in Gin
SSRF (Server Side Request Forgery) in Go/Gin applications occurs when an attacker controls the destination of a server-side HTTP request. This allows them to scan internal ports, exfiltrate cloud metadata (like AWS/GCP credentials), or pivot into internal microservices. In Gin, this usually happens when query parameters are piped directly into the net/http client without IP-level validation.
The Vulnerable Pattern
func ProxyHandler(c *gin.Context) { // DANGER: Taking a raw URL from the user and fetching it targetURL := c.Query("url")resp, err := http.Get(targetURL) if err != nil { c.JSON(500, gin.H{"error": "request failed"}) return } defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) c.Data(200, "application/octet-stream", data)
}
The Secure Implementation
To properly mitigate SSRF, you cannot rely on simple string blacklists. The secure implementation uses a custom 'net.Dialer' with a 'Control' function. This allows the server to validate the resolved IP address *after* DNS resolution but *before* the connection is established, preventing DNS Rebinding attacks. We explicitly block loopback (127.0.0.1), private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), and link-local addresses (169.254.169.254). Additionally, we disable automatic redirects to ensure an attacker cannot redirect a 'safe' domain to an 'internal' IP.
func SecureProxyHandler(c *gin.Context) { rawURL := c.Query("url") parsedURL, err := url.Parse(rawURL) if err != nil || (parsedURL.Scheme != "http" && parsedURL.Scheme != "https") { c.AbortWithStatus(400) return }// Define a hardened transport to block internal IP ranges transport := &http.Transport{ DialContext: (&net.Dialer{ Timeout: 5 * time.Second, Control: func(network, address string, c syscall.RawConn) error { host, _, _ := net.SplitHostPort(address) ip := net.ParseIP(host) if ip != nil && (ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified()) { return fmt.Errorf("access to internal IP %s is blocked", host) } return nil }, }).DialContext, } client := &http.Client{ Transport: transport, Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse // Block redirects to prevent bypass }, } resp, err := client.Get(parsedURL.String()) if err != nil { c.AbortWithStatus(502) return } defer resp.Body.Close() io.Copy(c.Writer, resp.Body)
}
Your Gin API
might be exposed to SSRF (Server Side Request Forgery)
74% of Gin 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.