Request Smuggling in Fiber
How Request Smuggling Manifests in Fiber
Request smuggling in Fiber applications occurs when the server misinterprets the boundaries between HTTP requests, allowing attackers to hide malicious payloads in HTTP message framing. This vulnerability is particularly relevant in Fiber because of its HTTP/2 support and middleware processing pipeline.
The most common manifestation in Fiber is through HTTP/2 request smuggling. When Fiber upgrades connections to HTTP/2 (which it does automatically when clients support it), the framing layer can be manipulated. An attacker might send a request where the Content-Length header conflicts with the actual payload size, causing Fiber to process the next request's headers as part of the current request's body.
Consider this Fiber endpoint:
app.Post("/api/upload", func(c *fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
// Process uploaded file
return c.JSON(fiber.Map{"message": "File uploaded successfully"})
})
An attacker could exploit this by sending a malformed HTTP/2 request where the Content-Length header is manipulated. If Fiber's HTTP/2 parser doesn't properly validate the frame boundaries, the attacker's payload could be interpreted as part of the next request, potentially bypassing authentication middleware or accessing restricted endpoints.
Another Fiber-specific scenario involves the ctx.BodyParser() method. If an endpoint uses this method to parse request bodies without proper size validation:
app.Post("/api/data", func(c *fiber.Ctx) error {
var payload MyStruct
if err := c.BodyParser(&payload); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
}
// Process payload
return c.JSON(fiber.Map{"status": "success"})
})
An attacker could send a request with a large Content-Length header that exceeds the actual payload size. Fiber's parser might wait for more data, creating a timing window where subsequent requests could be processed incorrectly, potentially leading to BOLA (Broken Object Level Authorization) or IDOR vulnerabilities.
Middleware order is also critical in Fiber. If authentication middleware is placed after body parsing middleware, a request smuggling attack could bypass authentication by manipulating the request framing to make the authentication middleware process the wrong request context.
Fiber-Specific Detection
Detecting request smuggling in Fiber requires both manual testing and automated scanning. middleBrick's black-box scanning approach is particularly effective because it tests the actual HTTP/2 framing without requiring access to source code.
When scanning a Fiber API with middleBrick, the scanner sends specially crafted requests with conflicting Content-Length and Transfer-Encoding headers. For HTTP/2 endpoints, it manipulates the frame headers to test how Fiber's HTTP/2 parser handles boundary conditions.
Here's what middleBrick tests for in Fiber applications:
CL.TE: Content-Length: 5
Transfer-Encoding: chunked
Body: GET /admin HTTP/1.1...
TE.CL: Transfer-Encoding: chunked
Content-Length: 6
Body: 0
GET /admin HTTP/1.1...
CL.CL: Content-Length: 3
Content-Length: 7
Body: G
The scanner also tests Fiber's HTTP/2 upgrade mechanism by sending HTTP/1.1 requests with Upgrade: h2c headers and then attempting to smuggle requests once the upgrade is complete.
For Fiber applications using middleware, middleBrick analyzes the middleware chain to identify potential smuggling points. It specifically looks for:
- Body parsing before authentication
- Streaming endpoints without proper boundary validation
- WebSocket upgrade endpoints that might be vulnerable to framing attacks
- Endpoints using
ctx.Fasthttp.Request.Body()directly without size validation
The scanner generates a report showing which endpoints are vulnerable, the specific smuggling technique that worked, and the potential impact. For example:
{
"endpoint": "/api/upload",
"vulnerability": "CL.TE smuggling",
"impact": "Bypass authentication, access admin panel",
"severity": "high",
"remediation": "Validate Content-Length and Transfer-Encoding headers"
}Fiber-Specific Remediation
Remediating request smuggling in Fiber requires a multi-layered approach. The first step is to ensure proper HTTP header validation across all endpoints.
For all Fiber endpoints, implement strict Content-Length validation:
app.Use(func(c *fiber.Ctx) error {
contentLength := c.Get("Content-Length")
if contentLength != "" {
if _, err := strconv.Atoi(contentLength); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid Content-Length"})
}
}
transferEncoding := c.Get("Transfer-Encoding")
if transferEncoding != "" && transferEncoding != "chunked" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid Transfer-Encoding"})
}
return c.Next()
})
For endpoints that accept file uploads or large payloads, implement strict size limits:
app.Post("/api/upload", func(c *fiber.Ctx) error {
// Limit file size to 10MB
c.Context().Request.Body = http.MaxBytesReader(c.Context(), c.Context().Request.Body, 10*1024*1024)
file, err := c.FormFile("file")
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
}
// Process uploaded file
return c.JSON(fiber.Map{"message": "File uploaded successfully"})
})
For HTTP/2 endpoints, explicitly disable HTTP/2 if not needed, or ensure the HTTP/2 server implementation is up to date:
import "github.com/valyala/fasthttp"
// Create custom server with HTTP/2 disabled
server := &fasthttp.Server{
Handler: app.New().Handler(),
DisableHTTP2: true, // Disable HTTP/2 if not needed
MaxRequestBody: 10 * 1024 * 1024, // 10MB limit
}
app.Listener = server
Implement strict middleware ordering to ensure authentication happens before any request processing:
app.Use(authMiddleware)
app.Use(requestValidationMiddleware)
app.Use(bodyParsingMiddleware)
app.Post("/api/protected", func(c *fiber.Ctx) error {
// Authentication already applied
return c.JSON(fiber.Map{"status": "authenticated"})
})
For streaming endpoints, implement proper boundary detection:
app.Post("/api/stream", func(c *fiber.Ctx) error {
// Read exact number of bytes specified in Content-Length
contentLength, _ := strconv.Atoi(c.Get("Content-Length"))
body := make([]byte, contentLength)
if _, err := io.ReadFull(c.Context().Request.Body, body); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Incomplete request"})
}
// Process body
return c.JSON(fiber.Map{"status": "success"})
})