HIGH ssrfginapi keys

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 IDNameSeverity
CWE-918Server-Side Request Forgery (SSRF) CRITICAL
CWE-441Unintended Proxy or Intermediary (Confused Deputy) HIGH

Frequently Asked Questions

Do API keys by themselves prevent SSRF in Gin applications?
No. API keys provide authentication for outbound requests but do not restrict where a request can be sent. SSRF must be mitigated through input validation, allowlisting of hosts, and network controls.
How can I safely test for SSRF without exposing internal infrastructure?
Use the middleBrick CLI to scan your OpenAPI specification and runtime endpoints in an unauthenticated, black-box manner. This detects whether user-influenced parameters can reach private IP ranges or metadata services without requiring production traffic.