Cors Wildcard in Gin with Hmac Signatures
Cors Wildcard in Gin with Hmac Signatures — how this specific combination creates or exposes the vulnerability
In Gin, configuring CORS with a wildcard origin (*) while also using HMAC signatures for request authentication can unintentionally weaken integrity checks and enable cross-origin credential leakage. When AllowOrigins: []string{"*"} is set, the browser may send cross-origin requests that include credentials (cookies, authorization headers) if AllowCredentials is also enabled. A wildcard origin combined with credentials effectively bypasses the same-origin policy in certain browser configurations, allowing a malicious site to make authenticated requests on behalf of a user.
HMAC signatures are typically used to ensure request integrity and authenticity by signing a canonical representation of the request (method, path, headers, body) with a shared secret. However, if CORS is wide open, an attacker can craft a request from a browser that includes the necessary headers and signature, and the Gin backend may still accept it because the signature validates correctly. The vulnerability is not in HMAC itself, but in the interaction: the wildcard CORS policy allows the attacker’s page to include custom headers and the HMAC signature obtained through prior leakage or social engineering. Additionally, preflight requests may return broad Access-Control-Allow-Origin: * headers, and if the backend mistakenly reflects the origin or allows credentials, the browser may store and reuse cookies or tokens across origins, amplifying the impact of a compromised HMAC secret or a client-side XSS vector.
Consider a Gin route that requires an X-API-Signature header generated with HMAC-SHA256. If CORS allows any origin and credentials, a malicious site can load JavaScript that collects the signature (e.g., via a request to a public endpoint that echoes the signed header) and then replay it with modified parameters. Because the signature is tied to the request content, the attacker would need to know or derive the exact canonical form; however, if the client embeds the shared secret in JavaScript (a common anti-pattern), the secret is exposed, and the HMAC provides no security. Even without secret exposure, wildcard CORS can allow cross-origin preflight caching, enabling attackers to reuse allowed headers and methods across multiple malicious domains.
To detect this using middleBrick, which scans unauthenticated attack surfaces and runs 12 security checks in parallel, you would observe findings in CORS configuration and Authentication checks. The scan highlights overly permissive origins and potential credential reflection, and maps findings to frameworks such as OWASP API Top 10 and SOC2. Note that middleBrick detects and reports these risks but does not fix or block requests; it provides remediation guidance to tighten CORS policies and HMAC usage.
For organizations using the middleBrick CLI (middlebrick scan <url>) or integrating scans into CI/CD via the GitHub Action, these issues appear as actionable items with severity and remediation steps. The Pro plan supports continuous monitoring so that changes to CORS or authentication logic are flagged before deployment. The MCP Server lets you run scans directly from AI coding assistants, helping you catch dangerous combinations early in development.
Hmac Signatures-Specific Remediation in Gin — concrete code fixes
Remediation centers on tightening CORS policy and ensuring HMAC signatures are validated in a way that is not undermined by wildcard origins. In Gin, you should explicitly set allowed origins to known frontends, disable credentials when not required, and validate HMAC headers with constant-time comparison to prevent timing attacks.
First, configure CORS with specific origins and avoid reflecting the Origin header when credentials are not needed. Here is a secure Gin CORS setup:
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
)
func main() {
router := gin.Default()
config := cors.Config{
AllowOrigins: []string{"https://app.example.com", "https://admin.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-API-Signature"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: false, // keep false unless you must support cookies across origins
MaxAge: 12 * 3600,
}
router.Use(cors.New(config))
// routes here
router.Run(":8080")
}
Second, implement HMAC signature validation with a shared secret stored securely (not in frontend code). Use crypto/hmac and crypto/sha256 to generate and verify signatures, and compare using hmac.Equal to avoid timing attacks. Below is a Gin handler example that validates X-API-Signature:
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
const sharedSecret = "super-secure-shared-secret" // load from env or secret manager
func signPayload(payload string) string {
mac := hmac.New(sha256.New, []byte(sharedSecret))
mac.Write([]byte(payload))
return hex.EncodeToString(mac.Sum(nil))
}
func verifySignature(payload, receivedSig string) bool {
expected := signPayload(payload)
return hmac.Equal([]byte(expected), []byte(receivedSig))
}
func apiHandler(c *gin.Context) {
body := c.Request.Body // in real code, read and buffer if needed
// canonical representation: method + path + sorted headers + body
canonical := c.Request.Method + " " + c.Request.URL.Path + " " + c.GetHeader("X-API-Signature")
// For this example, assume body is included; in practice, build canonical carefully
sig := c.GetHeader("X-API-Signature")
if sig == "" || !verifySignature(canonical, sig) {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
Third, rotate the shared secret periodically and scope it per service or endpoint to limit blast radius. Store the secret in environment variables or a secrets manager, and avoid embedding it in JavaScript or client-side code. Combine these practices with strict CORS and robust input validation to reduce the risk of cross-origin abuse and signature misuse.
When adopting middleBrick’s continuous monitoring (Pro plan) or using the MCP Server inside your IDE, you can catch insecure CORS-HMAC combinations before they reach production. The scanner’s checks for Authentication and BOLA/IDOR complement these code-level fixes by highlighting runtime misconfigurations that could be exploited even when signatures are correctly implemented.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |