Crlf Injection in Gin (Go)
Crlf Injection in Gin with Go
Crlf Injection occurs when an attacker can inject a carriage return (CR, \r) and line feed (LF, \n) sequence into an HTTP header or the status line, causing header splitting. In Go, the Gin framework does not inherently sanitize user-controlled data before writing it into headers or the response status. If you directly use values from query parameters, headers, or form fields in header-setting functions or status code paths, you can inadvertently allow an attacker to inject additional headers or perform response splitting. This can lead to HTTP response smuggling, cache poisoning, or XSS when the malicious output is later reflected into a browser context.
For example, if you read a query parameter page and use it to set a custom header without validation, an attacker-supplied value like home\r\nX-Injected: true will be interpreted by the underlying HTTP server as a second header. Similarly, setting the status code with unvalidated input can corrupt the response line. These behaviors are not Gin-specific but arise from how Go’s net/http writes headers and status; Gin’s convenience methods simply expose them when untrusted input is passed through.
In the context of an automated scanner like middleBrick, which runs black-box checks including Input Validation and Security Misconfiguration, Crlf Injection is flagged because it indicates that user input reaches protocol-level constructs without canonicalization or rejection of disallowed characters. The scanner does not alter your runtime but highlights where untrusted data improperly influences headers or status, which aligns with findings mapped to OWASP API Top 10 and broader web security references.
Go-Specific Remediation in Gin
To remediate Crlf Injection in Gin, ensure that any user-controlled data used in headers or the status line is strictly validated and sanitized. Reject or encode CR and LF characters, and avoid passing raw input to functions that set headers or status. Below are concrete Go examples for Gin handlers.
1. Safe custom header setting with rejection of CR/LF
Do not use c.Header() with untrusted strings directly. Validate the value before assignment:
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/set-header", func(c *gin.Context) {
userValue := c.Query("value")
// Reject if value contains CR or LF
if strings.ContainsAny(userValue, "\r\n") {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid header value"})
return
}
c.Header("X-Custom", userValue)
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
// r.Run()
}
2. Safe status code handling
Status codes must be integers within the valid range. Do not derive the status code from user input; if you must map input to a status, use a controlled mapping:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/status", func(c *gin.Context) {
codeStr := c.Query("code")
var code int
switch codeStr {
case "ok":
code = http.StatusOK
case "not_found":
code = http.StatusNotFound
default:
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "unknown status"})
return
}
c.Status(code)
c.JSON(http.StatusOK, gin.H{"result": "sent"})
})
// r.Run()
}
3. Using middleware to normalize/validate headers early
You can add Gin middleware to sanitize or log suspicious header-like input before it reaches business logic:
package main
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func sanitizeHeaderMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// Example: inspect a header-like query param and reject injections
if val := c.Query("x_name"); val != "" && strings.ContainsAny(val, "\r\n") {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "invalid characters"})
return
}
c.Next()
}
}
func main() {
r := gin.Default()
r.Use(sanitizeHeaderMiddleware())
r.GET("/profile", func(c *gin.Context) {
name := c.Query("name")
c.Header("X-Profile", name)
c.JSON(http.StatusOK, gin.H{"name": name})
})
// r.Run()
}
These patterns ensure that CR and LF characters are not interpreted as header separators, aligning with secure handling practices and helping scans from tools like middleBrick return clearer findings for Input Validation and Security Misconfiguration checks.