Clickjacking in Gin with Basic Auth
Clickjacking in Gin with Basic Auth — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redress attack where an attacker tricks a user into interacting with invisible or disguised controls inside an embedded frame. When Basic Authentication is used in a Gin application, the browser may send credentials automatically via the Authorization header when the page is loaded in a frame, which can combine with missing anti-clickjacking defenses to create a severe risk.
In Gin, if an endpoint that requires Basic Auth does not set Content Security Policy (CSP) frame-ancestors or X-Frame-Options, an attacker can embed the endpoint in an <iframe> and overlay interactive elements. Because the browser includes the Basic Auth credentials with the request in the same-origin context, the victim may unknowingly perform actions while authenticated. This is particularly dangerous for state-changing operations that do not require additional confirmation, as the user’s authenticated session and credentials are automatically supplied by the browser.
For example, an endpoint defined as GET /admin/delete-account with Basic Auth could be loaded invisibly inside an attacker’s page. The user’s browser sends the Authorization header automatically, and a hidden form or JavaScript triggers the request. Without frame controls, there is no mechanism in Gin itself to prevent this embedding, and the security boundary relies entirely on browser enforcement of CSP and X-Frame-Options.
middleBrick’s scanning approach checks for these missing frame-ancestor protections during unauthenticated scans. If an endpoint protected by Basic Auth lacks CSP frame-ancestors or X-Frame-Options, the scan reports a finding with severity and remediation guidance. This is one of the 12 parallel security checks, ensuring that authentication mechanisms like Basic Auth are evaluated alongside framing risks rather than in isolation.
To validate the presence of this issue, a scanner can attempt to detect whether an endpoint is embeddable by inspecting response headers for CSP frame-ancestors or X-Frame-Options. The absence of these headers in combination with Basic Auth indicates a potential vector, and remediation must focus on explicit frame restrictions rather than relying on authentication alone.
Basic Auth-Specific Remediation in Gin — concrete code fixes
Remediation for clickjacking in Gin with Basic Auth requires both frame-protection headers and secure handling of credentials. The following code examples show how to apply X-Frame-Options and CSP frame-ancestors in a Gin application while preserving Basic Auth safely.
Example 1: Global middleware with X-Frame-Options and CSP frame-ancestors
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Global middleware to prevent framing
r.Use(func(c *gin.Context) {
c.Writer.Header().Set("X-Frame-Options", "DENY")
c.Writer.Header().Set("Content-Security-Policy", "frame-ancestors 'none'")
})
r.GET("/public", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "public endpoint"})
})
// Protected endpoint with Basic Auth
r.GET("/admin", gin.BasicAuth(gin.Accounts{
"alice": "secret1",
"bob": "secret2",
}), func(c *gin.Context) {
c.JSON(200, gin.H{"message": "admin area"})
})
r.Run(":8080")
}
Example 2: Per-route frame protection with allowlist
package main
import (
"github.com/gin-gonic/gin"
)
func allowEmbed() gin.HandlerFunc {
return func(c *gin.Context) {
// Allow embedding only from specific origins
c.Writer.Header().Set("Content-Security-Policy", "frame-ancestors 'self' https://trusted.example.com")
c.Writer.Header().Set("X-Frame-Options", "ALLOW-FROM https://trusted.example.com")
}
}
func main() {
r := gin.Default()
r.Use(gin.BasicAuth(gin.Accounts{
"alice": "secret1",
}))
// Public read-only endpoint with strict framing
r.GET("/public", allowEmbed(), func(c *gin.Context) {
c.JSON(200, gin.H{"data": "safe to embed"})
})
// Admin endpoint with deny framing
r.GET("/admin/settings", func(c *gin.Context) {
c.Writer.Header().Set("X-Frame-Options", "DENY")
c.Writer.Header().Set("Content-Security-Policy", "frame-ancestors 'none'")
c.JSON(200, gin.H{"admin": "settings"})
})
r.Run(":8080")
}
In these examples, Basic Auth is applied at the route or global level, while frame-protection headers are set independently. Using DENY or 'none' for frame-ancestors is recommended for sensitive endpoints. For pages that must be embeddable, use a strict allowlist with specific origins and avoid exposing state-changing actions inside frames.
middleBrick’s GitHub Action can be used to add API security checks to your CI/CD pipeline, ensuring that new endpoints include these headers before deployment. This complements runtime scanning via the CLI tool, which outputs findings in JSON for integration into scripts.