HIGH api key exposureginsaml

Api Key Exposure in Gin with Saml

Api Key Exposure in Gin with Saml — how this specific combination creates or exposes the vulnerability

When an API built with the Gin web framework uses Security Assertion Markup Language (SAML) for authentication, improper handling of API keys can expose both the keys and the SAML flow. API keys are typically bearer tokens meant for service-to-service authorization, whereas SAML assertions are usually used for user identity and roles. If an endpoint mixes both—for example, accepting an API key in a header while also processing a SAML response or assertion—misconfiguration can lead to unintended exposure.

In Gin, this often occurs when middleware extracts an API key from Authorization: Bearer <key> and then passes the request into SAML processing without ensuring the caller is authorized for that SAML context. Because SAML responses can contain attributes and assertions intended for identity providers and service providers, exposing API keys alongside SAML metadata (such as endpoints or certificates) can give an attacker information about integration points, token formats, or signing keys.

Another scenario involves logging or error messages. Gin applications that log the full request context—including headers containing API keys—while processing SAML bindings (e.g., POST bindings with SAMLResponse parameters) may inadvertently write sensitive material to logs or responses. If an attacker can trigger error conditions during SAML validation, they might observe whether an API key was accepted, leading to enumeration or token leakage.

Additionally, if the SAML service provider configuration in Gin exposes metadata at an unauthenticated endpoint (e.g., /saml/metadata) and that endpoint also validates API keys without strict scoping, it may return metadata that references key usage or integration patterns. Middleware that does not enforce strict separation between authentication flows (SAML) and authorization mechanisms (API keys) increases the risk of cross-context confusion, where an API key intended for machine access is treated as a valid credential for SAML-based sessions.

Real-world attack patterns include an attacker probing endpoints that accept both an API key and SAML parameters, attempting to replay captured SAML responses with modified headers, or exploiting verbose error messages to distinguish valid API keys during SAML processing. These behaviors align with API2: Broken Authentication and API10: Improper Assets Management in the OWASP API Security Top 10, where insufficient controls around authentication vectors and exposed integrations amplify exposure risks.

Saml-Specific Remediation in Gin — concrete code fixes

To reduce the risk of API key exposure when using SAML in Gin, enforce strict separation between authentication and authorization layers, validate inputs before processing SAML assertions, and ensure API keys are never logged or reflected in SAML-related responses.

// Example: Gin middleware that validates API key before allowing SAML processing
package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "strings"
)

const expectedAPIKey = "s3cr3t-api-k3y-2024"

func apiKeyAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        auth := c.GetHeader("Authorization")
        if auth == "" || !strings.HasPrefix(auth, "Bearer ") {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing or invalid authorization header"})
            return
        }
        key := strings.TrimPrefix(auth, "Bearer ")
        if key != expectedAPIKey {
            c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "invalid api key"})
            return
        }
        c.Next()
    }
}

// Example: Dedicated SAML metadata endpoint with no API key requirement
func samlMetadata() gin.HandlerFunc {
    return func(c *gin.Context) {
        metadata := `<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://idp.example.com/metadata"
  validUntil="2025-12-31T00:00:00Z">
  <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data>
          <ds:X509Certificate>MIIC...</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.example.com/sso"/>
  </md:IDPSSODescriptor>
</md:EntityDescriptor>`
        c.Data(http.StatusOK, "application/xml", []byte(metadata))
    }
}

// Example: SAML assertion consumer with strict input validation
func samlConsumer(c *gin.Context) {
    samlResponse := c.PostForm("SAMLResponse")
    relayState := c.PostForm("RelayState")
    if samlResponse == "" || !isValidSAMLResponse(samlResponse) {
        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid SAML response"})
        return
    }
    // Process SAML assertion safely without exposing API keys
    c.JSON(http.StatusOK, gin.H{"relay": relayState, "status": "processed"})
}

func isValidSAMLResponse(response string) bool {
    // Implement proper SAML validation, signature checks, and audience restrictions
    return len(response) > 100
}

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

    // Public SAML endpoints do not require API keys
    r.GET("/saml/metadata", samlMetadata())
    r.POST("/saml/consumer", samlConsumer())

    // Protected API routes requiring API keys
    protected := r.Group("/api")
    protected.Use(apiKeyAuth())
    {
        protected.GET("resource", func(c *gin.Context) {
            c.JSON(http.StatusOK, gin.H{"data": "protected resource"})
        })
    }

    r.Run(":8080")
}

Ensure that SAML metadata and endpoints are isolated from API key validation logic. Do not reflect API keys in SAML responses or error messages, and avoid logging full request headers when processing SAML bindings. Rotate signing keys regularly and validate SAML responses against expected audiences and issuers to prevent token misuse.

Frequently Asked Questions

Can SAML metadata be exposed without API keys?
Yes, SAML metadata is typically public and can be served without API key validation. Ensure it does not reference or leak API keys and is served over HTTPS.
How can I prevent API keys from appearing in logs during SAML processing?
Filter or redact Authorization headers containing API keys in Gin middleware before logging, and avoid including raw headers in error responses.