HIGH injection flawsadonisjsmutual tls

Injection Flaws in Adonisjs with Mutual Tls

Injection Flaws in Adonisjs with Mutual Tls

AdonisJS is a Node.js web framework that encourages structured request handling, validation, and database interaction. When Mutual TLS (mTLS) is used for client authentication, developers may assume the transport is fully secured and overlook injection risks at the application layer. Injection flaws—such as SQL injection, command injection, and template injection—can still occur when untrusted input derived from mTLS-authenticated clients is concatenated into queries, system commands, or rendered views.

Mutual TLS verifies the client’s identity but does not sanitize or validate the data the client sends. An authenticated client can still supply malicious payloads via query parameters, JSON bodies, or headers. For example, an API endpoint that builds a SQL query by interpolating a user ID extracted from the mTLS certificate subject without parameterization remains vulnerable to SQL injection. Similarly, if the application passes client-controlled values to a shell utility to generate reports, command injection becomes possible even though the client is mTLS-authenticated.

Consider an AdonisJS route that uses the Request object and a database client:

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

export default class ReportsController {
  public async show({ request, response }: HttpContextContract) {
    const { orgId } = request.qs()
    // Risk: orgId is used directly in a raw query
    const rows = await Database.rawQuery('SELECT * FROM reports WHERE org_id = ?', [orgId])
    return response.send(rows)
  }
}

In this example, mTLS may have verified the client, but orgId is still passed as a parameterized query binding, which is safe. However, if the developer mistakenly uses string concatenation, SQL injection is introduced:

const rows = await Database.rawQuery(`SELECT * FROM reports WHERE org_id = ${orgId}`)

AdonisJS also supports Lucid ORM models. Unsafe usage with string-based dynamic queries can lead to injection even when using an ORM:

const user = await User.query().where('email', request.input('email')).first()

This is generally safe if validation is applied, but if email is used in a raw condition without sanitization, injection may occur. Template injection is another concern when rendering views with unescaped user input:

return response.view('dashboard', { username: request.input('username') })

If the view uses interpolation without escaping (e.g., in a templating engine that does not auto-escape), an attacker could inject script content. In mTLS setups, these issues are not prevented by transport security alone.

LLM/AI Security considerations intersect here because an mTLS-authenticated client could attempt prompt injection if the API interacts with an LLM endpoint. For example, a chat endpoint that includes user-controlled input in prompts without sanitization may be susceptible to prompt injection or jailbreak attempts. Output scanning is necessary to detect PII or secrets returned by the LLM, even when the client is authenticated via mTLS.

Input validation, parameterized queries, and output encoding remain essential regardless of mTLS. middleBrick scans can detect these injection risks by correlating authenticated endpoint behavior with unsafe patterns, providing findings mapped to OWASP API Top 10 and compliance frameworks.

Mutual Tls-Specific Remediation in Adonisjs

Remediation centers on treating mTLS-authenticated input as untrusted and applying secure coding practices consistently. Below are concrete fixes and code examples for AdonisJS applications using mTLS.

1. Use parameterized queries or query builder bindings

Always pass user-influenced values as bindings rather than interpolating them into raw SQL strings.

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

export default class ReportsController {
  public async show({ request, response }: HttpContextContract) {
    const orgId = request.qs().orgId
    // Safe: parameterized query
    const rows = await Database.rawQuery('SELECT * FROM reports WHERE org_id = ?', [orgId])
    return response.send(rows)
  }
}

2. Validate and sanitize inputs before using them in commands

If you must invoke system commands, validate and restrict input to a strict allowlist and avoid shell interpolation.

import { execFile } from 'child_process'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

const reportSchema = schema.create({
  reportName: schema.string({}, [rules.alpha({ allowHyphens: true })])
})

export default class ReportsController {
  public async generate({ request, response }: HttpContextContract) {
    const payload = await request.validate({ schema: reportSchema })
    // Safe: use execFile with arguments array, no shell
    execFile('generate-report', [payload.reportName], (error, stdout) => {
      if (error) return response.badRequest({ error: 'report generation failed' })
      response.send(stdout)
    })
  }
}

3. Escape output in views

Ensure your template engine auto-escapes variables or explicitly escape user-controlled data.

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

export default class DashboardController {
  public async show({ request, view }: HttpContextContract) {
    const username = request.input('username')
    // View engine should auto-escape; if not, sanitize explicitly
    return view.render('dashboard', { username })
  }
}

4. Combine mTLS with input validation and rate limiting

Even with mTLS, enforce validation schemas and rate limiting to reduce abuse surface.

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { schema, rules } from '@ioc:Adonis/Core/Validator'

const apiKeySchema = schema.create({
  apiKey: schema.string({}, [rules.minLength(32), rules.alphanumeric()])
})

export default class ApiKeyController {
  public async verify({ request, response }: HttpContextContract) {
    const { apiKey } = await request.validate({ schema: apiKeySchema })
    // Proceed with mTLS-authenticated request handling
    response.send({ valid: true })
  }
}

These practices ensure that mTLS provides identity assurance without neglecting data validation, query safety, and output encoding. middleBrick’s checks for authentication bypass and input validation help surface overlooked injection risks in mTLS-protected endpoints.

Frequently Asked Questions

Does mTLS prevent SQL injection in AdonisJS endpoints?
No. Mutual TLS authenticates the client but does not sanitize input. SQL injection can still occur if user-influenced data is concatenated into queries without parameterization or validation.
How does middleBrick handle injection flaws in authenticated endpoints?
middleBrick runs unauthenticated black-box checks that include authenticated-like probes where supported. It detects unsafe query construction, command injection patterns, and template injection risks regardless of transport-level authentication, providing severity and remediation guidance.