SSRF

SSRF in Go (Gin): Remediation [Mar 2026] [CVE-2026-32236]

[Updated March 2026] Updated CVE-2026-32236

Overview

CVE-2026-32236 describes a Server-Side Request Forgery (SSRF) vulnerability in Backstage's plugin-auth-backend. In that exploit, the CIMD metadata fetch validates the initial client_id hostname against private IP ranges but fails to apply the same validation after HTTP redirects. This means a request that starts at a trusted private or external host could be redirected to an internal resource. The practical impact in that context is limited (the attacker cannot read the response body, cannot control request headers or method, and the feature is gated behind an experimental flag). The patch for Backstage was applied in plugin-auth-backend version 0.27.1. The vulnerability is categorized under CWE-918 (SSRF). In Go (Gin) applications the same pattern can arise if a server-side fetch accepts user-provided URLs and validates only the initial host, not every redirect, potentially enabling access to internal services during redirects. This guide explains how the vulnerability manifests in Go (Gin) apps, references the CVE, and shows concrete fixes in Go code. See CVE-2026-32236 for the affected Backstage component and patch details (0.27.1).

Affected Versions

Backstage plugin-auth-backend < 0.27.1

Code Fix Example

Go (Gin) API Security Remediation
package main

import (
  "errors"
  "io"
  "net/http"
  "net/url"
  "time"
)

var allowedHosts = map[string]bool{
  "example.com":     true,
  "api.example.com": true,
}

func isAllowed(target string) bool {
  u, err := url.Parse(target)
  if err != nil {
    return false
  }
  host := u.Hostname()
  if host == "" {
    return false
  }
  return allowedHosts[host]
}

// Vulnerable pattern: fetch using user-supplied URL with no host validation or redirect control
func fetchVulnerable(target string) ([]byte, error) {
  resp, err := http.Get(target)
  if err != nil {
    return nil, err
  }
  defer resp.Body.Close()
  return io.ReadAll(resp.Body)
}

// Safe pattern: validate host, disable redirects, and enforce a strict timeout
func fetchSafe(target string) ([]byte, error) {
  if !isAllowed(target) {
    return nil, errors.New("host is not allowed")
  }

  client := &http.Client{
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
      // Do not follow redirects to prevent SSRF to internal destinations
      return http.ErrUseLastResponse
    },
    Timeout: 5 * time.Second,
  }

  resp, err := client.Get(target)
  if err != nil {
    return nil, err
  }
  defer resp.Body.Close()
  return io.ReadAll(resp.Body)
}

func main() {
  // example usage (omitted): call fetchVulnerable or fetchSafe with a user-supplied URL
}

CVE References

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