Nosql Injection in Adonisjs with Mutual Tls
Nosql Injection in Adonisjs with Mutual Tls
Nosql Injection is a class of injection that targets databases such as MongoDB, where untrusted input is interpreted as part of a database query rather than data. In Adonisjs, which uses Lucid ORM and often works with MongoDB or other NoSQL stores, dynamic query building can become unsafe if raw request values are directly embedded into query objects without validation or sanitization.
When Mutual Tls (mTLS) is enabled, the transport layer is authenticated via client certificates, which may create a false sense of security. Operators sometimes assume mTLS alone is sufficient protection and reduce other security controls, such as input validation or rate limiting. However, mTLS does not prevent logical attacks originating from an authenticated client. A compromised or malicious client with a valid certificate can still submit crafted payloads to endpoints that build NoSQL queries from user-controlled data.
In Adonisjs, a typical pattern is to read request inputs via the useRequest helper or controller request object and pass them into query scopes or aggregation pipelines. If these inputs are merged directly into objects that become pipeline stages or filter documents, an attacker can inject operators such as $where, $eval, or modify logical structure to bypass intended filters. For example, a search endpoint that builds a MongoDB filter like { username: request.input('username') } can be abused if the username field contains JSON operators that change query semantics.
Consider an endpoint that retrieves user data based on a role parameter. Without proper sanitization, an attacker might supply a role value like { "$ne": null }, which could unintentionally expose records that should be restricted. In an mTLS-enabled environment, the request presents a valid client certificate, so the application may skip additional authorization checks, inadvertently amplifying the impact of the injection.
Adonisjs does not inherently sanitize NoSQL query inputs. Developers must explicitly validate and whitelist fields used in query construction, regardless of transport protections. Even with mTLS, you should treat authenticated clients as untrusted for data inputs. Combine mTLS with strict schema validation, operator allowlisting, and server-side schema checks to ensure that user-controlled values cannot alter query structure.
The OWASP API Top 10 category API1:2023 Broken Object Level Authorization and API10:2023 Injection are relevant here. Although mTLS helps authenticate the client, it does not mitigate injection risks. Findings from scans that test for NoSQL injection often highlight missing input validation on endpoints that build database queries dynamically. Remediation guidance typically includes using validation schemas, avoiding direct concatenation of user input into query objects, and applying the principle of least privilege to database connections.
Mutual Tls-Specific Remediation in Adonisjs
Mutual Tls in Adonisjs is typically handled at the infrastructure or server layer, for example by configuring an HTTPS server that requests and verifies client certificates. The application code consumes the established identity, often via request metadata. Below are concrete patterns and code examples that show how to enable mTLS and safely integrate it with input handling to reduce injection risks.
First, configure an HTTPS server in Adonisjs that requests client certificates. In the start/server.ts (or the relevant configuration file depending on your Adonisjs version), you set up the server to require client certificates and map them to application-level identities.
import { HttpServer } from '@adonisjs/core'
import { defineConfig } from '@adonisjs/core/app'
export default defineConfig({
https: {
enabled: true,
cert: '/path/to/server-cert.pem',
key: '/path/to/server-key.pem',
ca: '/path/to/ca-cert.pem',
requestCert: true,
rejectUnauthorized: true,
},
})
This configuration ensures that only clients presenting certificates signed by the trusted CA can establish a connection. The server will reject connections where the client certificate cannot be verified, reducing the attack surface from unauthenticated sources.
Next, in your controllers or middleware, you can access the client certificate details to perform additional authorization or logging. Adonisjs exposes the underlying Node.js request object, which contains the verified certificate information under request.socket.getPeerCertificate(). Use this data to enforce policies, but never rely on it for data validation.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UserController {
public async show({ request, response }: HttpContextContract) {
const tlsSocket = request.socket
const cert = tlsSocket.getPeerCertificate()
if (!cert || !cert.subject) {
return response.unauthorized('Client certificate missing or invalid')
}
const commonName = cert.subject.CN
// Use CN or other certificate fields for authorization checks, not for query building
const user = await User.query()
.where('username', request.input('username'))
.preload('roles')
.firstOrFail()
return response.ok(user)
}
}
To prevent NoSQL Injection, validate and sanitize all inputs used in query building regardless of mTLS status. Use validation schemas to define allowed structures and operators. For MongoDB-like query objects, avoid passing raw user input into query scopes. Instead, map validated inputs to safe query fragments.
import { schema, rules } from '@ioc:Adonis/Core/Validator'
const userQuerySchema = schema.create({
username: schema.string({ trim: true, escape: false }, [rules.minLength(1), rules.maxLength(120)]),
role: schema.optional(
schema.string({}, [rules.in(['admin', 'user', 'guest'])])
),
})
export default class UserController {
public async index({ request, response }: HttpContextContract) {
const payload = await request.validate({ schema: userQuerySchema })
const query = User.query()
if (payload.username) {
query.where('username', payload.username)
}
if (payload.role) {
query.where('role', payload.role)
}
const results = await query.exec()
return response.ok(results)
}
}
This approach ensures that even with mTLS protecting the channel, the application treats each request’s data with the same scrutiny. Combine mTLS with robust validation, operator allowlisting, and server-side checks to achieve defense in depth. MiddleBrick scans can help identify endpoints where NoSQL injection risks persist despite mTLS by testing authenticated and unauthenticated attack surfaces.