HIGH broken access controlgorilla muxfirestore

Broken Access Control in Gorilla Mux with Firestore

Broken Access Control in Gorilla Mux with Firestore — how this specific combination creates or exposes the vulnerability

Broken Access Control occurs when API endpoints fail to enforce proper authorization checks, allowing one user to access or modify another user's resources. Using Gorilla Mux with Firestore can unintentionally expose this vulnerability when route variables (such as user IDs) are used to construct Firestore document paths without verifying that the requesting user is permitted to access those paths.

Consider an endpoint defined as /users/{userID}/profile using Gorilla Mux. A developer might extract vars["userID"] and directly plug it into a Firestore call such as doc := client.Collection("users").Doc(userID).Get(ctx). If the handler does not compare the authenticated subject (e.g., from a session or token) with the userID in the route, an attacker can change the URL to access any user's profile simply by modifying the path parameter. Because Firestore security rules alone do not protect unauthenticated or misrouted requests, the application layer must enforce ownership checks.

In a multi-tenant scenario, this issue compounds when handlers use a common collection group query without scoping to a user or organization. For example, a handler might query client.Collection("messages").Where("roomID", "==", roomID).Documents(ctx) using a roomID from Gorilla Mux variables. Without validating that the authenticated user belongs to that room, an attacker can enumerate valid room IDs and read messages they should not see. This maps directly to the BOLA/IDOR checks performed by middleBrick, which flags endpoints where user-supplied identifiers are used without ownership verification.

Another common pattern is exposing Firestore document IDs that contain sensitive meaning. If a handler uses an object name or a sequential ID from the URL to retrieve a Firestore document, and the developer assumes obscurity provides protection, middleBrick’s Property Authorization and BOLA/IDOR checks will highlight the missing authorization logic. Real-world attack patterns such as IDOR (CWE-639) and broken access control (OWASP API Top 10 A01) are relevant here, as they describe scenarios where attackers manipulate identifiers to access unauthorized data.

Because middleBrick scans the unauthenticated attack surface, it can detect endpoints that rely solely on Firestore rules without complementary application-level authorization. The tool tests route parameters and attempts to access resources across different user contexts, surfacing gaps where access controls should be enforced. This is especially important for endpoints using HTTP methods like GET and DELETE, which may appear safe but can expose data when parameters are not tightly bound to the requester’s identity.

Firestore-Specific Remediation in Gorilla Mux — concrete code fixes

To secure Gorilla Mux routes that interact with Firestore, always bind the authenticated subject to the data access logic and avoid directly using route variables as Firestore document identifiers without validation.

Example: Safe user profile retrieval

Instead of using the route parameter as the sole identifier, retrieve the authenticated user ID from your authentication layer and compare it with the route parameter before querying Firestore.

// Assuming you have a function that returns the authenticated user ID and a validated Gorilla Mux route variable.
func getUserProfile(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    routeUserID := vars["userID"]

    // Obtain the authenticated subject from your auth middleware (e.g., JWT claims).
    authUserID, ok := r.Context().Value("userID").(string)
    if !ok || authUserID == "" {
        http.Error(w, `{"error": "unauthorized"}`, http.StatusUnauthorized)
        return
    }

    // Enforce ownership: do not proceed if the IDs do not match.
    if authUserID != routeUserID {
        http.Error(w, `{"error": "forbidden"}`, http.StatusForbidden)
        return
    }

    ctx := r.Context()
    client, err := firestore.NewClient(ctx, "your-project-id")
    if err != nil {
        http.Error(w, `{"error": "internal"}`, http.StatusInternalServerError)
        return
    }
    defer client.Close()

    doc, err := client.Collection("users").Doc(authUserID).Get(ctx)
    if err != nil {
        http.Error(w, `{"error": "not found"}`, http.StatusNotFound)
        return
    }
    // Marshal and return doc.Data()
}

Example: Scoped room messages with user membership check

When querying collections that imply multi-tenant relationships, validate membership before retrieving data. This prevents IDOR across collections such as messages or records.

func getRoomMessages(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    routeRoomID := vars["roomID"]

    authUserID, ok := r.Context().Value("userID").(string)
    if !ok || authUserID == "" {
        http.Error(w, `{"error": "unauthorized"}`, http.StatusUnauthorized)
        return
    }

    // Verify that the user is a member of the room (pseudo-check).
    isMember := checkRoomMembership(ctx, authUserID, routeRoomID)
    if !isMember {
        http.Error(w, `{"error": "forbidden"}`, http.StatusForbidden)
        return
    }

    ctx := r.Context()
    client, err := firestore.NewClient(ctx, "your-project-id")
    if err != nil {
        http.Error(w, `{"error": "internal"}`, http.StatusInternalServerError)
        return
    }
    defer client.Close()

    iter := client.Collection("messages").Where("roomID", "==", routeRoomID).Documents(ctx)
    defer iter.Stop()
    var messages []map[string]interface{}
    for {
        doc, err := iter.Next()
        if err == iterator.Done {
            break
        }
        if err != nil {
            http.Error(w, `{"error": "internal"}`, http.StatusInternalServerError)
            return
        }
        messages = append(messages, doc.Data())
    }
    // Marshal and return messages
}

These examples ensure that Firestore document paths are derived from authenticated identities and validated against route inputs, mitigating BOLA/IDOR risks. middleBrick’s checks for Property Authorization and BOLA/IDOR will validate that such controls are present and consistent with the API specification.

Frequently Asked Questions

Why does using route parameters directly with Firestore increase risk?
Using route parameters directly as Firestore document identifiers without verifying that the authenticated subject matches the parameter allows attackers to access or modify other users' data, leading to BOLA/IDOR vulnerabilities. Authorization checks must bind the authenticated user to the data access logic.
Can Firestore security rules alone prevent broken access control in Gorilla Mux APIs?
Firestore rules provide a useful layer but do not replace application-level authorization. Rules cannot verify application session context or enforce multi-tenant relationships reliably when identifiers are user-supplied. Combining rules with server-side ownership checks is essential.