SSRF

SSRF in Go Gin: Secure Coding Guide [Apr 2026] [GHSA-mvvv-v22x-xqwp]

[Updated Apr 2026] Updated GHSA-mvvv-v22x-xqwp

Overview

SSRF occurs when a Go (Gin) server accepts a URL from a client and fetches it from the server side. In real-world services this can enable attackers to reach internal or private resources, cloud metadata endpoints, or admin interfaces that should not be exposed, potentially leaking data, performing port scans, or pivoting to additional resources. Attackers may abuse HTTP proxy routes, or endpoints that proxy content, by supplying a carefully crafted URL to trigger requests to sensitive targets. This class of vulnerability is heightened in containerized or cloud environments where internal services are accessible from the same host or VPC, increasing the blast radius if not mitigated. Go (Gin) applications commonly exhibit SSRF when an endpoint proxies user-supplied URLs or when the server fetches remote resources based on query parameters or form fields without proper validation. Impact ranges from information disclosure and service disruption to lateral movement within an infrastructure, including access to private services, internal dashboards, and cloud metadata endpoints. If an attacker can access metadata services (for example, AWS or GCP instance metadata), they may retrieve tokens or credentials that facilitate further compromise. Without proper restrictions, SSRF can also enable attackers to enumerate internal networks, probe for open ports, or test defenses, all through a single vulnerable endpoint. In Gin-based Go services, SSRF typically manifests as an HTTP handler that uses net/http to request a URL supplied by a client without restricting destinations, schemes, or redirects. This guide describes how this vulnerability manifests in Go with the Gin framework, including common patterns (proxy endpoints, fetchers, or redirectors) and the necessary safeguards to prevent SSRF. It also covers enforcing destination allowlists, implementing strict HTTP client configurations, validating input, and adding tests to prevent regressions. Even without CVEs at hand, these mitigations align with established SSRF protections for Go and modern web frameworks.

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "io/ioutil"
  "net/http"
  "net/url"
  "time"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()

  // Vulnerable: user-controlled URL fetched directly
  r.GET("/fetch-vuln", func(c *gin.Context) {
    u := c.Query("url")
    resp, err := http.Get(u)
    if err != nil { c.String(500, "upstream error"); return }
    defer resp.Body.Close()
    b, _ := ioutil.ReadAll(resp.Body)
    c.Data(resp.StatusCode, resp.Header.Get("Content-Type"), b)
  })

  // Secure: validate and whitelist destinations
  r.GET("/fetch-secure", func(c *gin.Context) {
    raw := c.Query("url")
    parsed, err := url.ParseRequestURI(raw)
    if err != nil { c.String(400, "invalid url"); return }
    if parsed.Scheme != "http" && parsed.Scheme != "https" { c.String(400, "unsupported scheme"); return }
    host := parsed.Hostname()
    allowed := map[string]bool{"example.com": true, "api.example.com": true}
    if !allowed[host] { c.String(403, "host not allowed"); return }
    client := &http.Client{ Timeout: 5 * time.Second }
    resp, err := client.Get(parsed.String())
    if err != nil { c.String(502, "upstream error"); return }
    defer resp.Body.Close()
    b, _ := ioutil.ReadAll(resp.Body)
    c.Data(resp.StatusCode, resp.Header.Get("Content-Type"), b)
  })

  r.Run()
}

CVE References

Choose which optional cookies to allow. You can change this any time.