HIGH insecure direct object referenceecho gomongodb

Insecure Direct Object Reference in Echo Go with Mongodb

Insecure Direct Object Reference in Echo Go with Mongodb — how this specific combination creates or exposes the vulnerability

Insecure Direct Object Reference (IDOR) occurs when an API exposes a reference to a resource—such as a MongoDB ObjectId—and allows an authenticated user to access or modify objects without verifying that the user owns that resource. In Go APIs built with the Echo framework and MongoDB, this typically surfaces when route parameters like :id are bound directly to database queries without an authorization check tied to the requester’s identity.

Consider an Echo route that fetches a user profile by ID:

GET /users/:id

If the handler uses the :id path parameter to construct a MongoDB query like usersCollection.FindOne(ctx, bson.M{"_id": id}) without confirming that the authenticated user is allowed to view that document, an attacker can enumerate valid ObjectIds and access other users’ data. This is an IDOR vector because the object reference (the MongoDB _id) is directly user-supplied and used as the sole access key.

Compounding the risk in Echo, middleware that sets a user identity (e.g., via JWT) must explicitly pass the requester’s user ID into the handler. If the handler ignores this and only uses the route parameter, the authorization boundary collapses. For example, a handler signature like func(c echo.Context) error that reads c.Param("id") and uses it as the query key provides no ownership check. Even with authentication in place, missing authorization logic turns the endpoint into an IDOR-enabled endpoint.

MongoDB ObjectIds are often predictable or enumerable, especially in sequential environments, which makes them easy to guess or iterate. An attacker does not need authentication flaws to exploit this; they only need to modify the :id value in a legitimate request. If the API returns 200 with data versus 404 or 403 when unauthorized, the difference reveals the presence of an IDOR.

In the context of the OWASP API Security Top 10, this maps to Broken Object Level Authorization. A scanner like middleBrick runs checks that correlate unauthenticated and authenticated-style probes (where session context is simulated) to detect endpoints where object references are accepted without proper ownership validation. Findings include verbose errors, absence of per-object access checks, and predictable resource identifiers.

Example of vulnerable Echo Go code with MongoDB:

func getUser(c echo.Context) error {
    id := c.Param("id")
    var user User
    err := usersCollection.FindOne(c.Request().Context(), bson.M{"_id": id}).Decode(&user)
    if err != nil {
        return c.JSON(http.StatusNotFound, map[string]string{"error": "not found"})
    }
    return c.JSON(http.StatusOK, user)
}

In this snippet, id comes directly from the route, and there is no check that the requesting user matches the user represented by the document. This allows any authenticated user to supply another user’s ID and receive that data if the ID exists.

Mongodb-Specific Remediation in Echo Go — concrete code fixes

To fix IDOR in Echo with MongoDB, enforce that every request validates the resource ownership against the authenticated subject. This means resolving the authenticated user identity from the request context and including it as a filter criterion in the MongoDB query.

First, ensure your authentication middleware places the user’s ID into the Echo context. For JWT-based setups, this is commonly done in a middleware function:

func AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        tokenString := strings.TrimPrefix(c.Request().Header.Get("Authorization"), "Bearer ")
        claims := &CustomClaims{}
        token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        _, err := jwt.ParseWithToken(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
            return []byte("your-secret"), nil
        })
        if err != nil || !token.Valid {
            return c.JSON(http.StatusUnauthorized, map[string]string{"error": "invalid token"})
        }
        c.Set("userID", claims.UserID)
        return next(c)
    }
}

Then, in the handler, retrieve the user ID from context and combine it with the resource identifier to form a compound filter. This ensures that users can only access documents that belong to them:

func getUserSecure(c echo.Context) error {
    userID := c.Get("userID")
    if userID == nil {
        return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"})
    }
    id := c.Param("id")
    // Ensure the requested ID matches the authenticated user’s ID
    if id != userID {
        return c.JSON(http.StatusForbidden, map[string]string{"error": "forbidden"})
    }
    var user User
    err := usersCollection.FindOne(c.Request().Context(), bson.M{
        "_id": id,
        "user_id": userID, // additional ownership guard
    }).Decode(&user)
    if err != nil {
        return c.JSON(http.StatusNotFound, map[string]string{"error": "not found"})
    }
    return c.JSON(http.StatusOK, user)
}

When the resource is not keyed by user ID alone—such as in a team or multi-tenant model—embed the authorization rule in the query filter. For example, if documents contain an array of member IDs:

func getTeamResource(c echo.Context) error {
    userID := c.Get("userID")
    id := c.Param("id")
    var resource Resource
    filter := bson.M{
        "_id": id,
        "member_ids": userID,
    }
    err := resourcesCollection.FindOne(c.Request().Context(), filter).Decode(&resource)
    if err != nil {
        return c.JSON(http.StatusNotFound, map[string]string{"error": "not found or access denied"})
    }
    return c.JSON(http.StatusOK, resource)
}

Always prefer parameterized queries and avoid string concatenation to build filters. Using bson.M with explicit keys prevents injection-style mistakes and ensures the query structure remains predictable.

For broader API protection, middleBrick’s scans can detect IDOR by correlating spec definitions with runtime behavior. If you use the CLI, you can run middlebrick scan <url> to validate that your endpoints enforce appropriate ownership checks. Teams on the Pro plan gain continuous monitoring, which schedules regular scans and can alert you if new IDOR risks appear after code changes.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

Can IDOR be detected without authenticated session tests?
Yes. IDOR can often be inferred from unauthenticated probes that reveal whether object references are directly mappable to data. MiddleBrick combines unauthenticated and contextual tests to highlight endpoints where references are accepted without ownership validation.
Does fixing IDOR require changing the MongoDB schema?
Not necessarily. IDOR is primarily an authorization issue. You can remediate by adding ownership filters (e.g., user_id) to queries and enforcing checks in handlers. Schema changes may help but are not required if queries consistently enforce access rules.