Ssrf Server Side in Gin
How SSRF Manifests in Gin Applications
Server-Side Request Forgery (SSRF) in Gin applications typically occurs when user-controlled input is used to construct URLs for internal requests. Gin's middleware architecture and parameter binding make it particularly vulnerable to SSRF when developers accept URLs from clients and make outbound requests without proper validation.
A common Gin SSRF pattern looks like this:
func proxyHandler(c *gin.Context) {
targetURL := c.Query("url") // User-controlled input
resp, err := http.Get(targetURL) // SSRF vulnerability
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
c.Data(http.StatusOK, resp.Header.Get("Content-Type"), body)
}This handler is vulnerable because it accepts any URL from the query parameter and makes an HTTP request without validation. An attacker could supply http://localhost:8080/admin to access internal services, http://169.254.169.254/latest/meta-data/ to retrieve AWS metadata, or even file:///etc/passwd for local file access.
Another Gin-specific SSRF scenario involves binding structs with URL fields:
type ProxyRequest struct {
TargetURL string `form:"url" json:"url"`
}
func proxyEndpoint(c *gin.Context) {
var req ProxyRequest
if err := c.ShouldBind(&req); err != nil {
c.JSON(400, gin.H{"error": "Invalid input"})
return
}
resp, err := http.Get(req.TargetURL) // SSRF here
// ...
}Even with binding, the URL travels unvalidated to the HTTP client. Gin's default binding doesn't sanitize or restrict URLs, making SSRF a significant risk when handling external service integrations, webhook processing, or proxy functionality.
Gin-Specific Detection and Scanning
Detecting SSRF in Gin applications requires examining both the code structure and runtime behavior. middleBrick's SSRF scanner specifically targets Gin applications by looking for patterns where user input flows to HTTP clients.
middleBrick scans for SSRF by:
- Identifying endpoints that accept URL parameters or body fields that could contain URLs
- Testing these endpoints with SSRF payloads like
http://localhost:22,http://169.254.169.254, andfile:///etc/passwd - Analyzing HTTP client usage patterns in the codebase
- Checking for missing URL validation or allowlisting
- Detecting SSRF in OpenAPI specs by finding parameters of type
stringthat are used as URLs in request bodies - Testing for blind SSRF by measuring response time differences and error patterns
When scanning a Gin application with middleBrick, you'll receive findings that include:
SSRF Vulnerability - High Severity
Endpoint: POST /api/proxy
Parameter: url (string)
Risk: Can access internal services, metadata APIs, and local files
Remediation: Implement URL allowlisting and validationmiddleBrick's active SSRF testing goes beyond static analysis by actually making requests to internal services and measuring responses. This black-box approach works perfectly for Gin applications since it doesn't require source code access or configuration changes.
For CI/CD integration, the GitHub Action can fail builds when SSRF vulnerabilities are detected:
- name: Scan for SSRF
uses: middlebrick/middlebrick@v1
with:
target: https://your-gin-app.com
fail-on-severity: high
token: ${{ secrets.MIDDLEBRICK_TOKEN }}This ensures SSRF vulnerabilities are caught before deployment, particularly important for Gin applications that often serve as API gateways or proxy services.
Gin-Specific Remediation Techniques
Remediating SSRF in Gin applications requires a defense-in-depth approach. The most effective strategy combines URL validation, allowlisting, and safe HTTP client configuration.
First, implement strict URL validation using Go's net/url package:
func validateURL(rawURL string) (string, error) {
url, err := url.Parse(rawURL)
if err != nil {
return "", errors.New("invalid URL format")
}
// Block file:// schemes
if url.Scheme == "file" {
return "", errors.New("file scheme not allowed")
}
// Block private IP ranges
ip := net.ParseIP(url.Hostname())
if ip != nil && ip.IsPrivate() {
return "", errors.New("private IP addresses not allowed")
}
// Block localhost and loopback
if url.Hostname() == "localhost" || strings.HasPrefix(url.Hostname(), "127.") {
return "", errors.New("localhost not allowed")
}
return rawURL, nil
}
func safeProxyHandler(c *gin.Context) {
targetURL := c.Query("url")
validatedURL, err := validateURL(targetURL)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
resp, err := http.Get(validatedURL)
// ...
}For more robust protection, implement an allowlist of approved domains:
var allowedDomains = map[string]bool{
"api.example.com": true,
"webhook.example.com": true,
}
func validateURLWithAllowlist(rawURL string) (string, error) {
url, err := url.Parse(rawURL)
if err != nil {
return "", err
}
if !allowedDomains[url.Hostname()] {
return "", errors.New("domain not in allowlist")
}
return rawURL, nil
}
func allowlistProxyHandler(c *gin.Context) {
targetURL := c.Query("url")
validatedURL, err := validateURLWithAllowlist(targetURL)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
resp, err := http.Get(validatedURL)
// ...
}Additionally, configure timeouts and restrict HTTP client behavior:
var safeHTTPClient = &http.Client{
Timeout: 10 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // Block redirects
},
}
func secureProxyHandler(c *gin.Context) {
targetURL := c.Query("url")
validatedURL, err := validateURL(targetURL)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
resp, err := safeHTTPClient.Get(validatedURL)
// ...
}For Gin applications using middleware, you can create SSRF protection middleware:
func SSRFProtectionMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// Check for URL parameters in all requests
for _, param := range c.Request.URL.Query() {
if isPotentiallyDangerousURL(param) {
c.JSON(400, gin.H{"error": "SSRF attempt detected"})
c.Abort()
return
}
}
c.Next()
}
}
// Use in router
r := gin.New()
r.Use(SSRFProtectionMiddleware())These remediation techniques, combined with middleBrick's continuous scanning, provide comprehensive SSRF protection for Gin applications.