HIGH nosql injectionadonisjsbasic auth

Nosql Injection in Adonisjs with Basic Auth

Nosql Injection in Adonisjs with Basic Auth — how this specific combination creates or exposes the vulnerability

Nosql Injection occurs when untrusted input is interpreted as part of a NoSQL query, altering query logic or enabling unauthorized data access. In Adonisjs, which supports MongoDB, CouchDB, and other NoSQL stores through its Lucid ORM extensions, improperly sanitized query parameters can lead to injection. When Basic Auth is used for authentication, the username and password are sent in an Authorization header (Base64-encoded, not encrypted). If the application derives query filters from user-supplied data while also relying on Basic Auth for identity context, two issues can align:

  • The developer may assume authentication has already validated the caller, leading to relaxed input validation on downstream NoSQL queries.
  • Basic Auth does not provide scopes or roles at the application layer; if role or tenant identifiers are bound to the authenticated identity and then concatenated into a NoSQL filter without strict allowlisting, an attacker can manipulate other parameters (e.g., userId, tenantId) to access data belonging to other users.

For example, a route handler that builds a MongoDB query by directly passing request query parameters into a where clause can be abused. Consider an endpoint GET /records that uses Basic Auth to identify a user but constructs a NoSQL filter like { userId: request.query.userId }. If userId is attacker-controlled and not validated, an injection payload such as { "$ne": "" } can be supplied, potentially returning records for all users. Adonisjs does not inherently sanitize NoSQL inputs; the framework expects developers to validate and parameterize inputs explicitly. Without explicit allowlists or schema-based validation, the combination of Basic Auth (which identifies the caller) and unchecked query inputs creates an implicit trust boundary that can be bypassed via Nosql Injection.

Common attack patterns include:

  • Boolean injection: Using operators like $ne, $exists, or $regex to manipulate result sets.
  • Field manipulation: Injecting nested operators to bypass expected query shape, e.g., { "email": { "$regex": ".*@example.com" } }.
  • Privilege escalation via tenant or role fields: If tenant isolation is implemented as a NoSQL filter, injecting a condition that omits the tenant constraint can expose cross-tenant data.

Because middleBrick tests unauthenticated attack surfaces, it can detect endpoints where query parameters are not properly constrained, even when Basic Auth is present. The scanner’s checks for Input Validation and Property Authorization highlight cases where attacker-controlled data can influence NoSQL queries, and the LLM/AI Security module ensures that prompt injection or data leakage is not occurring through any logged or returned query errors.

Basic Auth-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on strict input validation, avoidlist-based filtering, and never directly injecting user input into NoSQL queries. Even when using Basic Auth, treat all client-supplied data as untrusted. Below are concrete examples for Adonisjs using the @adonisjs/lucid extensions for a NoSQL provider.

1. Validate and type-cast inputs

Use schema validation (e.g., Yup or Joi) to enforce allowed shapes and types. For a userId that must be a string UUID:

import { schema } from '@ioc:Adonis/Core/Validator'

const recordQuerySchema = schema.create({
  userId: schema.string({}, [rules.uuid()]),
})

export async function index({ request, auth }: HttpContextContract) {
  const payload = await request.validate({ schema: recordQuerySchema })
  const records = await Record.query().where('userId', payload.userId).exec()
  return records
}

2. Use parameterized queries or builder methods

Do not concatenate strings or allow raw objects to be passed directly. Instead, use the query builder’s methods:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Record from 'App/Models/Record'

export async function index({ request, auth }: HttpContextContract) {
  const userId = request.qs().userId
  if (!userId || typeof userId !== 'string') {
    return []
  }
  // Safe: parameterized condition via builder
  const records = await Record.query()
    .where('userId', userId)
    .limit(100)
    .exec()
  return records
}

3. Enforce tenant or scope constraints server-side

Do not rely on client-supplied tenant identifiers. Derive scope from the authenticated identity (if available) or from a server-side mapping:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Record from 'App/Models/Record'

export async function index({ request, auth }: HttpContextContract) {
  const user = auth.getUserOrFail()
  // Assume user.tenantId is set after Basic Auth validation or a separate lookup
  const records = await Record.query()
    .where('tenantId', user.tenantId)
    .where((qb) => {
      const userId = request.qs().userId
      if (userId && typeof userId === 'string') {
        qb.where('userId', userId)
      }
    })
    .exec()
  return records
}

4. Reject unexpected operators

Preprocess input to detect and reject MongoDB operators in string fields:

function hasNoSqlInjection(obj: any): boolean {
  const operators = ['$', '.']
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      const val = obj[key]
      if (typeof val === 'object' && val !== null) {
        if (Array.isArray(val)) {
          for (const item of val) {
            if (!hasNoSqlInjection(item)) return false
          }
        } else if (Object.keys(val).some((k) => operators.some((o) => k.startsWith(o)))) {
          return false
        }
      }
    }
  }
  return true
}

// Usage in route
const filter = request.qs()
if (!hasNoSqlInjection(filter)) {
  throw new Error('Invalid filter')
}

5. Combine with authentication context

Even with Basic Auth, include the authenticated user’s identifier in server-side filters to enforce ownership:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Record from 'App/Models/Record'

export async function show({ params, auth }: HttpContextContract) {
  const user = auth.getUserOrFail()
  const record = await Record.query()
    .where('userId', user.id)
    .where('id', params.id)
    .firstOrFail()
  return record
}

Frequently Asked Questions

Does Basic Auth alone prevent Nosql Injection in Adonisjs?
No. Basic Auth identifies the caller but does not validate or sanitize application-level inputs. If query parameters are used to build NoSQL filters, they must be validated and parameterized independently of authentication.
Can middleBrick detect Nosql Injection in Adonisjs endpoints using Basic Auth?
Yes. middleBrick tests the unauthenticated attack surface and flags inputs that can alter NoSQL query structure. It highlights insecure input handling in categories such as Input Validation and Property Authorization, even when Basic Auth is in use.