Ssrf Server Side in Fiber with Jwt Tokens
Ssrf Server Side in Fiber with Jwt Tokens — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a Fiber service that uses JWT tokens for authentication can occur when an endpoint that accepts external input (e.g., a URL or host header) makes an internal HTTP request, and the request is augmented with credentials derived from JWT tokens. In this combination, trusting user-supplied URLs while having access to token material increases the potential for an attacker to coerce the server into making requests to internal or restricted services. For example, if a user-controlled parameter is used to construct a request with an Authorization header parsed from a JWT, the server may inadvertently reach internal metadata services, cloud instance metadata endpoints, or internal APIs that are not exposed publicly.
SSRF in this context does not require bypassing JWT validation if the application decodes the token to extract claims (such as roles or permissions) and then uses those claims to decide whether to attach authorization information to an outgoing request. Attackers may provide a malicious hostname in a parameter while the application uses the JWT’s payload to add an Authorization header, effectively chaining token usage to SSRF. Because Fiber is a fast, expressive web framework for Go, developers may inadvertently write handlers that resolve user input into HTTP calls without adequate validation of the target host, port, or scheme, which can lead to unintended network interactions.
Consider a handler that receives a URL from a client, decodes a JWT to enrich the outgoing request, and then performs an HTTP GET. Even with JWT-based routing or claims checks, if the target URL is not strictly restricted to a whitelist of allowed domains or IP ranges, an attacker can supply an internal address (e.g., http://169.254.169.254/latest/meta-data/) and cause the server to leak sensitive cloud metadata. MiddleBrick’s scans detect such patterns by correlating OpenAPI/Swagger specifications (including $ref resolution) with runtime behavior, identifying endpoints that accept external URLs and use authorization data in requests.
In practice, SSRF with JWT tokens can expose internal services, bypass firewall rules, or facilitate further attacks like Redis injection or SSRF-to-RCE if the backend runtime is misconfigured. The presence of JWTs does not mitigate SSRF; it can inadvertently increase the scope by providing the request with additional headers or tokens that make internal services more reachable or more informative to an attacker. Security checks that examine both input validation and authorization flows are important for identifying these cross-cutting risks.
Jwt Tokens-Specific Remediation in Fiber — concrete code fixes
To reduce SSRF risk in Fiber applications that use JWT tokens, validate and sanitize all user-controlled input before using it in HTTP requests, and avoid injecting authorization data into requests to untrusted endpoints. Do not automatically forward decoded JWT claims to outbound calls. Instead, enforce allowlists for hostnames and ports, and remove or limit sensitive headers when calling external services.
Example of a vulnerable Fiber handler in Go that combines user input with JWT-derived authorization:
// Vulnerable example: user-controlled URL and JWT-based Authorization header forwarding
package main
import (
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
)
func unsafeProxy(c *fiber.Ctx) error {
rawUrl := c.FormValue("url")
tokenString := c.Get("Authorization")
// decode JWT to extract claims (for illustration; do not forward tokens)
token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil || !token.Valid {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid token"})
}
req, err := http.NewRequest("GET", rawUrl, nil)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request"})
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
if sub, ok := claims["sub"].(string); ok && sub != "" {
req.Header.Set("Authorization", "Bearer "+ tokenString)
}
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "request failed"})
}
defer resp.Body.Close()
// forward response (simplified)
return c.SendStream(resp.Body, resp.StatusCode)
}
Remediation with strict hostname allowlist and no token forwarding:
// Secure approach: restrict target host, do not forward JWT tokens
package main
import (
"net/http"
"net/url"
"strings"
"github.com/gofiber/fiber/v2"
)
var allowedHosts = map[string]bool{
"api.example.com": true,
"internal.service.local": true,
}
func safeProxy(c *fiber.Ctx) error {
parsed, err := url.ParseRequestURI(c.Query("url"))
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid URL"})
}
if !allowedHosts[parsed.Host] {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "host not allowed"})
}
// Optionally enforce scheme
if parsed.Scheme != "https" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "only HTTPS allowed"})
}
req, err := http.NewRequest("GET", parsed.String(), nil)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid request"})
}
// Do not set Authorization from JWT; use API keys or other safe mechanisms if needed
resp, err := http.DefaultClient.Do(req)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "request failed"})
}
defer resp.Body.Close()
return c.SendStream(resp.Body, resp.StatusCode)
}
Additional measures include using a service-to-service token mechanism that is separate from user-presented JWTs, implementing network-level egress filtering, and logging outbound requests for audit. In CI/CD, the GitHub Action can enforce a maximum risk score threshold to prevent deployments with unresolved SSRF findings.