HIGH api key exposuregin
Api Key Exposure in Gin
How Api Key Exposure Manifests in Gin
Remediating API key exposure in Gin requires a multi-layered approach. Start with robust authentication middleware that validates keys before any business logic executes:
package middleware
import (
"github.com/gin-gonic/gin"
"net/http"
"github.com/yourapp/auth"
)
func APISecureAuth() gin.HandlerFunc {
return func(c *gin.Context) {
key := c.GetHeader("X-API-Key")
if key == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "API key required",
})
c.Abort()
return
}
// Validate key against your auth system
if !auth.ValidateAPIKey(key) {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Invalid API key",
})
c.Abort()
return
}
// Key is valid, set user context
c.Set("user_id", auth.GetUserIDFromKey(key))
c.Next()
}
}
Implement key rotation and secure storage using environment variables with proper validation:
package config
import (
"os"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
var APIKeys = map[string]string{}
func LoadAPIKeys() error {
keys := os.Getenv("API_KEYS")
if keys == "" {
return errors.New("API_KEYS environment variable not set")
}
// Parse keys in format: key1:desc1,key2:desc2
for _, kv := range strings.Split(keys, ",") {
parts := strings.SplitN(kv, ":", 2)
if len(parts) != 2 {
return errors.Errorf("invalid key format: %s", kv)
}
APIKeys[parts[0]] = parts[1]
}
return nil
}
func ValidateAPIKey(key string) bool {
_, exists := APIKeys[key]
return exists
}
Secure your Gin router configuration to ensure authentication middleware applies to all sensitive routes:
package main
import (
"github.com/gin-gonic/gin"
"your-app/middleware"
"your-app/handlers"
)
func main() {
r := gin.New()
// Apply security middleware globally
r.Use(middleware.APISecureAuth())
r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
// Custom logger that redacts API keys
return fmt.Sprintf("%s - [%s] "%s %s %s %d %s "%s" %s"
param.ClientIP,
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
"REDACTED" // Hide headers that might contain keys
)
}))
r.Use(gin.Recovery())
// Public routes (no auth needed)
public := r.Group("/public")
{
public.GET("/status", handlers.Status)
}
// Protected routes (auth required)
api := r.Group("/api/v1")
{
api.GET("/users/:id", handlers.GetUser)
api.POST("/data", handlers.CreateData)
}
r.Run(":8080")
}
Implement comprehensive input validation and rate limiting to prevent API key brute force attacks:
package middleware
import (
"time"
"github.com/gin-gonic/gin"
"github.com/ulule/limiter/v3"
"github.com/ulule/limiter/v3/drivers/middleware/gin"
"github.com/ulule/limiter/v3/drivers/store/memory"
)
func RateLimiter() gin.HandlerFunc {
rate := limiter.Rate{
Period: 1 * time.Minute,
Limit: 100, // 100 requests per minute
}
store := memory.NewStore()
l := limiter.New(store, rate)
return ginLimiter.New(l)
}
func SecureHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-Frame-Options", "DENY")
c.Header("X-XSS-Protection", "1; mode=block")
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
c.Next()
}
}
Finally, implement comprehensive testing for API key exposure:
package handlers_test
import (
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"your-app/handlers"
"your-app/middleware"
)
func TestAPIKeys(t *testing.T) {
// Test missing API key
w := performRequest(handlers.GetUser, "GET", "/api/v1/users/1", "")
assert.Equal(t, 401, w.Code)
// Test invalid API key
w = performRequest(handlers.GetUser, "GET", "/api/v1/users/1", "invalid-key")
assert.Equal(t, 401, w.Code)
// Test valid API key
w = performRequest(handlers.GetUser, "GET", "/api/v1/users/1", "valid-api-key")
assert.Equal(t, 200, w.Code)
// Verify no sensitive data in response
var response map[string]interface{}
json.Unmarshal(w.Body.Bytes(), &response)
assert.NotContains(t, response, "sensitive_data")
}
func performRequest(handler http.HandlerFunc, method string, path string, apiKey string) *httptest.ResponseRecorder {
req, _ := http.NewRequest(method, path, nil)
if apiKey != "" {
req.Header.Set("X-API-Key", apiKey)
}
w := httptest.NewRecorder()
handler(w, req)
return w
}
Frequently Asked Questions
How does middleBrick's scanning differ from other API security tools when testing Gin applications?
middleBrick performs black-box scanning that tests your Gin API endpoints without requiring source code access or credentials. Unlike static analysis tools that only examine code, middleBrick actively sends requests to your running API, testing for API key exposure, BOLA vulnerabilities, and other runtime security issues. The scanner specifically checks if your Gin application exposes sensitive data through unauthenticated endpoints or improperly validated API keys. For AI-powered Gin endpoints, middleBrick's unique LLM security module tests for prompt injection, system prompt leakage, and excessive agency patterns that no other self-service scanner offers.
Can middleBrick detect API key exposure in Gin applications that use custom authentication schemes?
Yes, middleBrick's scanning engine is designed to detect API key exposure regardless of the authentication implementation. The scanner tests endpoints by attempting requests with and without API keys, analyzing responses for sensitive data exposure. It identifies endpoints that should require authentication but don't properly validate keys, endpoints that return excessive data without proper authorization checks, and API keys that appear in error responses or logs. The scanning process takes 5-15 seconds and provides a security risk score with specific findings and remediation guidance tailored to your Gin application's vulnerabilities.