Broken Access Control in Fiber with Mongodb
Broken Access Control in Fiber with Mongodb — how this specific combination creates or exposes the vulnerability
Broken Access Control (BOLA/IDOR) in a Fiber application that uses Mongodb often occurs when route parameters are used to form database queries without validating that the requesting user is authorized to access the targeted document. For example, an endpoint like /users/:userId/profile may take the userId from the URL, directly construct a Mongodb filter such as { _id: ObjectId(req.params.userId) }, and return the document without confirming the caller belongs to that user or has the required role. Because the query does not include a tenant or user ownership check, an attacker can iterate through valid ObjectIds or guess predictable identifiers to access or modify other users’ data.
In a typical Fiber app, middleware may set user claims into context (e.g., via JWT), but if the route handler does not combine those claims with the query, the authorization boundary is effectively bypassed on the server side. The API surface exposed by unauthenticated or weakly authenticated probing (as performed by middleBrick in black-box scans) can reveal whether userId-based endpoints are vulnerable: a 200 response for another user’s ID indicates BOLA/IDOR. Additionally, if the schema embeds sensitive fields (e.g., roles, tokens, PII) and the projection is not explicitly limited, the API might unintentionally expose more data than intended, compounding the access control issue.
Using an OpenAPI spec can highlight these risks when paths rely on parameters that map directly to database keys without scope restrictions. During a scan, middleBrick cross-references the spec definitions with runtime behavior and can detect endpoints where responses differ based on identifier manipulation, flagging the absence of per-request authorization checks. This aligns with the OWASP API Top 10 Broken Access Control category and can intersect with data exposure when sensitive documents are returned due to missing filters or incorrect default projections in Mongodb queries.
Mongodb-Specific Remediation in Fiber — concrete code fixes
To fix BOLA/IDOR in Fiber with Mongodb, ensure every query incorporates the requester’s identity or role from authentication/authorization context and avoid exposing raw user-controlled IDs as direct database keys without validation. Below are concrete code examples that demonstrate a secure pattern.
First, include a user ID claim in the JWT during login, and ensure the token is verified on each request. Then, in the route handler, combine the authenticated subject with the resource identifier instead of trusting the URL parameter alone.
// Secure Fiber handler with Mongodb (using the official MongoDB Go driver)
package main
import (
"context"
"errors"
"github.com/gofiber/fiber/v2"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Assume UserClaims is populated after JWT verification and contains Subject (user ID)
type UserClaims struct {
Subject string `json:"sub"`
Roles []string `json:"roles"`
}
func getUserProfile(c *fiber.Ctx) error {
// Extract claims set by prior auth middleware
claims, ok := c.Locals("claims").(UserClaims)
if !ok {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
}
// Use request parameter only as a candidate; validate ownership via claims
requestedID := c.Params("userId")
if requestedID == "" {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "userId is required"})
}
// Build query that enforces ownership: only allow the document matching the authenticated subject
var filter bson.M
// If your schema stores user ID as a string
filter = bson.M{"_id": requestedID, "user_id": claims.Subject}
// If using ObjectID:
// objID, err := primitive.ObjectIDFromHex(requestedID)
// if err != nil { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid userId"}) }
// filter = bson.M{"_id": objID, "user_id": claims.Subject}
collection := c.Locals("mongoCollection").(*mongo.Collection)
var result bson.M
err := collection.FindOne(c.Context(), filter, options.FindOne().SetProjection(bson.M{"name": 1, "email": 1, "_id": 0})).Decode(&result)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "access denied"})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "server error"})
}
return c.JSON(result)
}
Key points in this remediation:
- The query includes both the resource identifier from the route and the authenticated subject (
claims.Subject), ensuring users can only access their own document. - Projection explicitly limits returned fields to avoid accidental data exposure (e.g., omitting password hashes or tokens).
- Input validation for the
userIdparameter guards against malformed identifiers and injection attempts. - If roles are needed for authorization, check
claims.Rolesbefore proceeding and enforce least privilege per endpoint.
For endpoints that should allow administrative access (e.g., fetching any user by admin role), incorporate role-based checks before relaxing the filter, and always log suspicious patterns without exposing details to the caller.