Ssrf in Gin with Api Keys
Ssrf in Gin with Api Keys — how this specific combination creates or exposes the vulnerability
Server-Side Request Forgery (SSRF) in a Gin application that uses API keys for outbound calls can arise when user-controlled data is used to construct HTTP requests without adequate validation or network segregation. In this scenario, API keys are often stored in environment variables or injected at runtime, and the application uses those keys to authenticate outbound requests to third-party services. If an attacker can influence the target URL of those outbound requests—such as through a parameter that controls a webhook, a redirect, or a resource identifier—they can direct the server to make requests to internal endpoints, cloud metadata services, or other sensitive internal resources.
Because the Gin application attaches API keys to these requests, the SSRF vector can become a privilege escalation or data exfiltration path. For example, if the application makes requests to a cloud metadata service (e.g., http://169.254.169.254) and includes an API key in headers, an attacker who can control the destination may learn about or misuse attached credentials. Similarly, SSRF can expose internal services that are not publicly reachable but are trusted when requests originate from the application host. The presence of API keys does not mitigate SSRF; it can amplify impact by giving the outbound request additional authentication context that internal services may trust.
In practice, this often maps to OWASP API Top 10 SSRF and can intersect with insecure consumption patterns when the application processes untrusted input before making requests. MiddleBrick’s scans detect SSRF by observing whether the API allows target URLs that point to private IP ranges or sensitive infrastructure, and it flags findings with remediation guidance that emphasizes input validation and network-level controls rather than assuming API keys provide isolation.
Api Keys-Specific Remediation in Gin — concrete code fixes
To address SSRF in Gin when API keys are used, focus on strict input validation, disallow private IP ranges and internal hostnames for user-supplied URLs, and avoid constructing outbound URLs from unchecked parameters. API keys should remain server-side and never be derived from or exposed via user input. Below are concrete code examples that demonstrate a secure approach.
1. Validate target URLs and reject private addresses
Ensure that any user-supplied URL used to make outbound requests is validated against a strict allowlist or blocked list of disallowed hosts and IP ranges.
import (
"net"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func isPrivateIP(host string) bool {
if ip := net.ParseIP(host); ip != nil {
return ip.IsPrivate()
}
return false
}
func isPrivateHostname(host string) bool {
// Block common internal/reserved hostnames
internalHosts := []string{"localhost", "127.0.0.1", "internal", "metadata"}
for _, h := range internalHosts {
if strings.EqualFold(host, h) {
return true
}
}
return false
}
func makeExternalRequest(c *gin.Context) {
var payload struct {
TargetURL string `json:"target_url"`
// other fields not used to build URLs
}
if c.BindJSON(&payload) != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
return
}
parsedURL, err := http.ParseRequestURI(payload.TargetURL)
if err != nil || isPrivateHostname(parsedURL.Hostname()) || isPrivateIP(parsedURL.Hostname()) {
c.JSON(http.StatusBadRequest, gin.H{"error": "target not allowed"})
return
}
req, _ := http.NewRequest("GET", parsedURL.String(), nil)
// API key is stored server-side and injected securely, never from user input
req.Header.Set("Authorization", "Bearer " + getServerSideApiKey())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil || resp.StatusCode >= 400 {
c.JSON(http.StatusBadGateway, gin.H{"error": "upstream failure"})
return
}
defer resp.Body.Close()
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
func getServerSideApiKey() string {
// Retrieve from secure configuration or environment, never user-controlled
return "sk-server-side-xxx"
}
2. Use allowlisted domains and avoid dynamic host assembly from user input
Instead of accepting full URLs, accept an identifier that maps to a pre-configured, allowlisted endpoint. This prevents SSRF while still enabling legitimate outbound calls authenticated with API keys.
type EndpointConfig struct {
URL string
Scopes []string
}
var allowedEndpoints = map[string]EndpointConfig{
"payment": {URL: "https://api.payments.example.com/v1/charge", Scopes: []string{"payments.write"}},
"notify": {URL: "https://notify.example.com/send", Scopes: []string{"notify.send"}},
}
func callAllowedService(c *gin.Context) {
var request struct {
Service string `json:"service"`
Amount int `json:"amount"`
}
if c.BindJSON(&request) != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
return
}
cfg, ok := allowedEndpoints[request.Service]
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "service not allowed"})
return
}
// API key is managed server-side and attached securely
req, _ := http.NewRequest("POST", cfg.URL, nil)
req.Header.Set("Authorization", "Bearer " + getServerSideApiKey())
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil || resp.StatusCode >= 400 {
c.JSON(http.StatusBadGateway, gin.H{"error": "service call failed"})
return
}
defer resp.Body.Close()
c.JSON(http.StatusOK, gin.H{"service": request.Service, "status": "completed"})
}
3. MiddleBrick integration for ongoing detection
Use the middleBrick CLI to validate that your endpoints do not expose SSRF via user-controlled URL parameters. The scanner checks unauthenticated attack surfaces and maps findings to frameworks such as OWASP API Top 10.
CLI example:
middlebrick scan https://api.example.com/openapi.json
For CI/CD, the GitHub Action can enforce a maximum risk score and fail builds if SSRF-related findings appear, while the Web Dashboard and MCP Server help track and investigate issues during development.
Related CWEs: ssrf
| CWE ID | Name | Severity |
|---|---|---|
| CWE-918 | Server-Side Request Forgery (SSRF) | CRITICAL |
| CWE-441 | Unintended Proxy or Intermediary (Confused Deputy) | HIGH |