HIGH out of bounds writefiberbasic auth

Out Of Bounds Write in Fiber with Basic Auth

Out Of Bounds Write in Fiber with Basic Auth

An Out Of Bounds Write in a Fiber service using HTTP Basic Authentication occurs when user-controlled input is used to index or size a buffer, array, or slice without proper validation, enabling writes beyond allocated memory boundaries. This note explains how the combination of Fiber, Basic Auth, and unchecked input can expose or amplify the risk.

Basic Authentication in Fiber is typically implemented by inspecting the Authorization header and decoding the base64-encoded credentials. Because this happens before request body parsing, developers may assume the identity is established safely and then process untrusted input without additional constraints. For example, an endpoint may accept a numeric index or a size parameter from the URL, a form body, or JSON, and use that value to index into a fixed-size array or to allocate a buffer. If the parameter is not validated, an attacker can supply a large or negative integer, causing a write past the end of the slice or into memory not intended for user data.

Consider a handler that reads an index from a query parameter and writes user data into a fixed-length array:

// Unsafe: index from query parameter without validation
var buffer [64]byte
c.Get("/write", func(c *fiber.Ctx) error {
    idxStr := c.Query("idx")
    var idx int
    if _, err := fmt.Sscanf(idxStr, "%d", &idx); err != nil {
        return c.Status(fiber.StatusBadRequest).SendString("invalid idx")
    }
    // Potential out-of-bounds write if idx < 0 or idx >= len(buffer)
    buffer[idx] = 'X'
    return c.SendStatus(fiber.StatusOK)
})

In this scenario, Basic Auth may be enforced via middleware that sets c.Locals("user", user) after verifying credentials. However, the authentication step does not protect the bounds check on buffer. An authenticated attacker can still manipulate idx to write outside the array, potentially corrupting adjacent memory, including other variables or internal runtime structures. In a managed language like Go with a runtime, the immediate effect is typically a panic (index out of range), but in environments that allow unsafe memory access or when interacting with C via cgo, such writes can lead to arbitrary code execution or information disclosure.

Another pattern involves decoding a JSON body into a struct that includes a slice field, then using a user-supplied value to determine the length of a backing array or to copy data into a destination buffer:

type Payload struct {
    Data []byte `json:"data"
}

c.Post("/upload", func(c *fiber.Ctx) error {
    var p Payload
    if err := c.BodyParser(&p); err != nil {
        return c.Status(fiber.StatusBadRequest).SendString("invalid body")
    }
    // Use a query parameter to decide how many bytes to copy
    nStr := c.Query("n")
    var n int
    if _, err := fmt.Sscanf(nStr, "%d", &n); err != nil || n < 0 || n > len(p.Data) {
        return c.Status(fiber.StatusBadRequest).SendString("invalid n")
    }
    dst := make([]byte, 10)
    // Out-of-bounds write if n > 10 or n < 0
    copy(dst, p.Data[:n])
    return c.JSON(fiber.Map{"written": n})
})

Even with a check for n >= 0, failing to ensure n <= len(dst) allows writing beyond the destination slice. Basic Auth may protect this endpoint via a middleware that validates credentials, but it does not mitigate the need to validate n against the destination size. The combination of authenticated access and unchecked input increases the likelihood that malicious payloads reach production handlers, especially if logging or error handling inadvertently exposes sensitive data through out-of-bounds reads.

Remediation focuses on strict input validation and avoiding assumptions about trust boundaries. Authentication confirms identity; it does not imply that input conforms to safety constraints. Always validate numeric indices and sizes against the actual length of buffers or slices, and prefer using slices with dynamic growth or explicit bounds checks before indexing. When copying data, ensure source ranges are strictly limited by the destination capacity.

Basic Auth-Specific Remediation in Fiber

Remediation for Basic Auth scenarios centers on validating all user-controlled data independently of authentication. Below are concrete, safe patterns for implementing Basic Auth in Fiber and preventing out-of-bounds writes.

Secure Basic Auth middleware with strict input validation:

func BasicAuthMiddleware(c *fiber.Ctx) error {
    // Extract and validate Authorization header format
    auth := c.Get("Authorization")
    if len(auth) < 6 || auth[:6] != "Basic " {
        return c.Status(fiber.StatusUnauthorized).SendString("auth required")
    }
    payload, err := base64.StdEncoding.DecodeString(auth[6:])
    if err != nil {
        return c.Status(fiber.StatusUnauthorized).SendString("invalid auth")
    }
    // Expect "username:password"
    parts := bytes.SplitN(payload, []byte(":"), 2)
    if len(parts) != 2 || !validUser(string(parts[0]), string(parts[1])) {
        return c.Status(fiber.StatusUnauthorized).SendString("invalid credentials")
    }
    c.Locals("authenticated", true)
    return c.Next()
}

func validUser(user, pass string) bool {
    // Compare securely in constant time in production
    return user == "admin" && pass == "secret"
}

Validated handler with bounds-safe operations:

c.Post("/safe-write", func(c *fiber.Ctx) error {
    // Ensure authentication has passed
    if ok := c.Locals("authenticated"); !ok {
        return c.Status(fiber.StatusUnauthorized).SendString("unauthorized")
    }
    idxStr := c.Query("idx")
    var idx int
    if _, err := fmt.Sscanf(idxStr, "%d", &idx); err != nil {
        return c.Status(fiber.StatusBadRequest).SendString("invalid idx")
    }
    buffer := [64]byte{}
    // Explicit bounds check before write
    if idx < 0 || idx >= len(buffer) {
        return c.Status(fiber.StatusBadRequest).SendString("idx out of range")
    }
    buffer[idx] = 'X'
    return c.JSON(fiber.Map{"ok": true})
})

Safe slice handling with length checks:

c.Post("/safe-copy", func(c *fiber.Ctx) error {
    if ok := c.Locals("authenticated"); !ok {
        return c.Status(fiber.StatusUnauthorized).SendString("unauthorized")
    }
    var p Payload
    if err := c.BodyParser(&p); err != nil {
        return c.Status(fiber.StatusBadRequest).SendString("invalid body")
    }
    nStr := c.Query("n")
    var n int
    if _, err := fmt.Sscanf(nStr, "%d", &n); err != nil || n < 0 {
        return c.Status(fiber.StatusBadRequest).SendString("invalid n")
    }
    dst := make([]byte, 10)
    // Validate source slice bounds against destination capacity
    if n > len(dst) || n > len(p.Data) {
        return c.Status(fiber.StatusBadRequest).SendString("n exceeds buffer limits")
    }
    copy(dst, p.Data[:n])
    return c.JSON(fiber.Map{"written": n})
})

These patterns ensure that authentication and input validation are independent concerns. Basic Auth provides identity, but every numeric index, size, or length must be checked against the actual capacity of buffers and slices before use.

Frequently Asked Questions

Does Basic Authentication prevent out-of-bounds writes in Fiber?
No. Basic Authentication confirms identity before request processing, but it does not validate user-controlled input such as query parameters, headers, or body fields. Out-of-bounds writes require explicit bounds checks on buffers, arrays, and slices regardless of authentication.
What validation is required when using numeric indices with a fixed buffer in Fiber with Basic Auth?
Always parse the input into an integer, then verify that the value is non-negative and strictly less than the length of the buffer or slice before indexing. Do not rely on authentication or error messages to prevent out-of-bounds access; perform explicit length checks.