HIGH sandbox escapeadonisjsmutual tls

Sandbox Escape in Adonisjs with Mutual Tls

Sandbox Escape in Adonisjs with Mutual Tls — how this specific combination creates or exposes the vulnerability

A sandbox escape in AdonisJS when Mutual TLS (mTLS) is in use typically arises not from a flaw in AdonisJS itself, but from a mismatch between the application’s trust boundaries and the way mTLS is configured. AdonisJS runs in a Node.js environment and may expose endpoints that perform sensitive operations, such as file system access, dynamic imports, or interaction with internal services. If mTLS is used to authenticate clients but the application does not re-validate authorization intent (e.g., which client certificate maps to which internal permission), an authenticated client may leverage an over-privileged route or a template injection to break out of the intended runtime constraints.

Mutual TLS binds client identity to TLS-level certificates. In AdonisJS, this is commonly enforced via a reverse proxy (such as Nginx or Traefik) or a dedicated mTLS middleware that checks client certificates before requests reach the framework. A sandbox escape can occur when the application trusts the mTLS proxy to enforce authorization, but then uses raw certificate fields (e.g., Common Name or Subject Alternative Name) in an unsafe way. For example, if the application uses the certificate’s subject to dynamically construct file paths, shell commands, or module imports, an attacker with a valid client certificate may traverse directories or invoke restricted modules.

Consider an endpoint that uses the certificate’s Common Name to locate a user-specific configuration file:

const fs = require('fs');
const crypto = require('crypto');

Route.get('/config/:cn', async ({ request }) => {
  const cn = request.param('cn'); // derived from certificate subject
  const filePath = `/safe/configs/${cn}.json`;
  return fs.readFileSync(filePath, 'utf-8');
});

If the reverse proxy terminates mTLS and passes the CN via a header without strict validation, an attacker with a valid certificate could supply a CN like ../../../etc/passwd and read arbitrary files. Even with mTLS, the application must treat certificate-derived inputs as untrusted and apply strict allowlists and path normalization. Another scenario involves dynamic imports or child processes driven by certificate claims, which may allow command injection or module resolution outside the intended sandbox.

Furthermore, if AdonisJS routes rely on mTLS for authentication but lack route-specific authorization checks (e.g., verifying scope or role claims extracted from the certificate), an attacker may use a low-privilege certificate to access administrative endpoints. This is not a weakness of mTLS, but a design flaw where the framework’s route guards do not align with the identity asserted by the TLS layer. The sandbox breaks when the application conflates authentication (mTLS) with authorization (RBAC/ABAC).

To detect such patterns, scanning tools perform unauthenticated and authenticated checks against endpoints that use certificate-derived parameters, looking for path traversal, command injection, or insecure dynamic imports. They correlate findings with the presence of mTLS configurations to highlight where trust boundaries are incorrectly defined.

Mutual Tls-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on ensuring that mTLS authentication and application-level authorization are independently enforced and that any data derived from certificates is strictly validated.

  • Validate certificate fields explicitly: Do not rely on proxy headers alone. If you must use headers passed by the proxy, treat them as untrusted input and validate against the certificate presented to the proxy.
  • Use allowlists for certificate-derived values: Map certificate subjects to application roles or permissions via a lookup table rather than using raw subject fields in filesystem or command paths.

Secure route example with explicit validation and RBAC:

const Route = use('Route');
const fs = require('fs').promises;
const path = require('path');

// Assume certificate claims are mapped by middleware into request.auth.cert
Route.get('/config/:name', async ({ request, auth }) => {
  const cert = auth.cert; // { subject: { CN: 'alice' }, validScopes: ['read-config'] }
  const allowedNames = new Set(['alice', 'bob']); // allowlist
  const normalizedName = path.normalize(request.param('name')).replace(/^(\/|\.\.)/, '');

  if (!cert || !allowedNames.has(cert.subject.CN)) {
    throw new Error('Unauthorized');
  }
  if (!cert.validScopes.includes('read-config')) {
    throw new Error('Insufficient scope');
  }
  const filePath = path.join('/safe/configs', `${normalizedName}.json`);
  return fs.readFile(filePath, 'utf-8');
});

When using a reverse proxy for mTLS, configure it to strip or rewrite potentially dangerous headers before they reach AdonisJS. For example, in Nginx you can specify:

location /api/ {
  ssl_verify_client on;
  ssl_verify_depth 2;
  proxy_pass http://adonis_app;
  # Only pass a validated mapping, not raw client-supplied headers
  proxy_set_header X-Client-CN $ssl_client_s_dn_CN;
  proxy_set_header X-Client-Verified $ssl_client_verify;
}

In AdonisJS middleware, validate the proxy header against the certificate presented to the proxy (if the proxy does not strip sensitive fields). Do not trust headers that can be set by the client:

class MtlsAuthMiddleware {
  async handle({ request, auth, response }, next) {
    const clientCn = request.header('x-client-cn');
    const tlsCn = request.$ssl && request.$ssl.client_cn; // framework-specific field when TLS is terminated at edge
    if (!tlsCn || clientCn !== tlsCn) {
      response.status(401).send('Invalid client certificate mapping');
      return;
    }
    // proceed with RBAC checks
    await next();
  }
}

For dynamic imports or child processes, resolve identifiers against a strict allowlist and avoid interpolating certificate fields into system commands. Prefer parameterized APIs or internal service calls instead of constructing shell commands.

Frequently Asked Questions

Does mTLS prevent all injection attacks in AdonisJS?
No. mTLS provides strong client authentication but does not prevent injection flaws (path traversal, command injection, template injection) if the application uses certificate-derived data unsafely. Always validate and sanitize certificate-derived inputs.
How does middleBrick handle mTLS-enabled endpoints?
middleBrick scans the unauthenticated attack surface and can test endpoints that rely on mTLS when provided with appropriate client certificates. Findings highlight where certificate-derived data reaches sensitive operations, with remediation guidance mapped to OWASP API Security and compliance frameworks.