HIGH insecure direct object referenceadonisjsmongodb

Insecure Direct Object Reference in Adonisjs with Mongodb

Insecure Direct Object Reference in Adonisjs 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 in a URL or query parameter—and relies only on user-supplied input to locate and return that resource. In AdonisJS, this commonly arises when a route like /users/:id/profile uses the raw :id to fetch a document from MongoDB without verifying that the authenticated requesting user owns or is authorized to access that document.

AdonisJS does not inherently enforce resource-level ownership; it provides request handling, validation, and ORM-like features via Lucid ORM. When using MongoDB through the official driver or a Mongoose-like layer, an endpoint might do const profile = await Profile.find(req.params.id). If the id comes directly from the client and there is no check tying the found profile to the authenticated user’s ID (e.g., profile.userId.equals(auth.user.id)), the endpoint is vulnerable to IDOR.

The risk is compounded because MongoDB ObjectIds are predictable and globally unique. An attacker can iterate through likely ObjectIds and, if authorization is missing, retrieve or modify other users’ profiles, settings, or sensitive data. This is an unauthenticated or low-privilege attack surface when endpoints rely solely on the object identifier without contextual authorization checks.

Additionally, AdonisJS API resources and transformers can inadvertently expose references in JSON responses (e.g., embedding related resource IDs). If those references are used client-side without server-side authorization on each access, they enable horizontal privilege escalation across the application. The unauthenticated attack surface testing performed by middleBrick can surface these missing ownership checks by correlating spec definitions and runtime behavior across endpoints.

Mongodb-Specific Remediation in Adonisjs — concrete code fixes

Remediation centers on enforcing ownership or role-based access control every time you fetch a MongoDB document by user input. Below are concrete, idiomatic examples for AdonisJS using the official MongoDB driver.

1. Enforce userId ownership on profile fetch

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Database from '@ioc:Adonis/Lucid/Database'

export default class ProfilesController {
  public async show({ params, auth }: HttpContextContract) {
    const profile = await Database
      .from('profiles')
      .where('_id', params.id)
      .where('user_id', auth.user?.id) // enforce ownership
      .first()

    if (!profile) {
      return Response.badRequest({ message: 'Not found or unauthorized' })
    }

    return profile
  }
}

2. Using MongoDB driver with ObjectId and userId checks

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { ObjectId } from 'mongodb'
import db from 'App/Providers/DbProvider'

export default class DocumentsController {
  public async show({ params, auth }: HttpContextContract) {
    const collection = db.client.db('app').collection('documents')
    const userId = new ObjectId(auth.user?.id as string)

    const doc = await collection.findOne({
      _id: new ObjectId(params.id),
      userId: userId,
    })

    if (!doc) {
      return Response.unauthorized()
    }

    return doc
  }
}

3. Scoped list with tenant or role checks

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import db from 'App/Providers/DbProvider'

export default class ReportsController {
  public async index({ request, auth }: HttpContextContract) {
    const tenantId = auth.user?.tenantId
    const reports = await db.client
      .db('app')
      .collection('reports')
      .find({ tenantId, visibility: 'internal' })
      .toArray()

    return reports
  }
}

4. Validate and normalize IDs before querying

import { schema, rules } from '@ioc:Adonis/Core/Validator'
import { ObjectId } from 'mongodb'

const profileSchema = schema.create({
  id: schema.string({}, [rules.format({ type: 'mongodb_id' })]),
})

export async function validateAndFetch(ctx: HttpContextContract) {
  const payload = await ctx.validate({
    schema: profileSchema,
  })

  const normalizedId = new ObjectId(payload.id)
  // proceed with ownership-checked query as above
}

5. Middleware or policy-based authorization

Implement a lightweight policy check that runs before the route handler. For example:

import { Exception } from '@poppinss/utils'

const guardResourceAccess = async (resourceId: string, userId: string) => {
  const hasAccess = await checkUserResourceRelationship(userId, resourceId)
  if (!hasAccess) {
    throw new Exception('Forbidden', 403, 'E_FORBIDDEN')
  }
}

Use this guard inside handlers after fetching the minimal required metadata to avoid an extra round-trip when not needed.

These patterns ensure that every MongoDB query includes a user- or role-bound filter, eliminating the IDOR vector. When combined with input validation for ObjectId formats and consistent error handling, the attack surface is reduced to the authenticated boundary without changing the runtime behavior for legitimate clients.

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

How does middleBrick detect IDOR in an AdonisJS + MongoDB API?
middleBrick runs unauthenticated scans that correlate OpenAPI/Swagger specs (including $ref resolution) with runtime behavior. It checks whether endpoints accept user-supplied object identifiers (e.g., MongoDB ObjectId in path or query) and whether responses differ based on ownership or permissions. If spec definitions expose resource IDs without corresponding authorization checks in the observed responses, it flags a potential IDOR with severity and remediation guidance.
Can I rely on AdonisJS route model binding alone to prevent IDOR with MongoDB?
No. AdonisJS route model binding resolves the ObjectId and provides the record, but it does not automatically enforce that the record belongs to the requesting user or that the user has permission to access it. You must add explicit ownership or role-based checks in the handler or via a policy; otherwise IDOR remains possible.