HIGH container escapeadonisjsmutual tls

Container Escape in Adonisjs with Mutual Tls

Container Escape in Adonisjs with Mutual Tls

A container escape in an AdonisJS application that uses mutual TLS (mTLS) typically arises when strong transport-layer authentication is present but the application runtime, container boundaries, and server configuration are not hardened. mTLS ensures that both the client and server present valid certificates, which reduces the risk of spoofed clients. However, it does not limit what an authenticated request can do inside the container or host if the application or its dependencies are compromised.

One common scenario involves an AdonisJS route that accepts an uploaded certificate file as part of an mTLS handshake or as user input for dynamic configuration. If the application deserializes or evaluates this file content insecurely—such as using dynamic imports or child processes based on attacker-controlled data—an authenticated client can execute code at the host level, leading to container escape. For example, an endpoint that passes a user-supplied filename to Node.js require() or to a shell utility can allow an authenticated attacker to break out of the container filesystem.

Another vector involves container runtime socket exposure. If the AdonisJS process runs with elevated privileges inside the container and the Docker socket (/var/run/docker.sock) is mounted, an authenticated API endpoint that executes Docker commands (e.g., via child processes) can enable an authenticated user to create new containers with host filesystem mounts, effectively escaping the original container boundary. This is a container escape path that leverages valid mTLS client certificates to gain trusted execution context, then abuses host integration features.

Server misconfiguration can also contribute. If the AdonisJS server binds to 0.0.0.0 inside the container but the container’s network policy does not restrict inbound sources, or if the TLS configuration does not enforce strong cipher suites and certificate validation, an authenticated channel may still be used to probe internal endpoints or trigger unsafe behavior. For instance, an endpoint that spawns a subprocess to manage certificates or keys without input validation can be tricked into reading or writing files outside the container’s intended scope.

These patterns align with OWASP API Top 10 controls around authentication abuse and server-side request forgery, and they map to real-world exploit techniques such as those seen in CVE-2021-22945 (F5 BIG-IP path traversal concepts) and container breakout patterns involving mounted sockets. middleBrick’s LLM/AI Security and Server Side Request Forgery checks can help detect risky endpoint behaviors, while the Inventory Management and Unsafe Consumption checks highlight dangerous runtime integrations.

Mutual Tls-Specific Remediation in Adonisjs

Remediation focuses on strict certificate validation, minimizing runtime privileges, and avoiding dynamic execution of user-influenced data. Below are concrete code examples for secure mTLS setups in AdonisJS.

1) Configure an HTTPS server with strict mTLS using the built-in https module and AdonisJS provider:

// start/server.js
const fs = require('fs');
const https = require('https');
const { Ignitor } = require('@adonisjs/ignitor');

const server = new Ignitor(require('@adonisjs/fold'));

server
  .httpServer()
  .start((error) => {
    if (error) {
      console.error('Server start error:', error);
      process.exit(1);
    }
    console.log('AdonisJS server with mTLS running on https://0.0.0.0:3333');
  });

// In your provider or a dedicated TLS setup file, create an HTTPS server with mTLS options
const tlsOptions = {
  key: fs.readFileSync('/etc/ssl/certs/server.key'),
  cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
  ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),
  requestCert: true,
  rejectUnauthorized: true,
};

const httpsServer = https.createServer(tlsOptions, (req, res) => {
  // AdonisJS request handling can be integrated here or via a proxy
  // This is a low-level example; in production, use AdonisJS CLI hooks or a custom server module
});

httpsServer.listen(3333, '0.0.0.0', () => {
  console.log('mTLS HTTPS server listening on port 33MC');
});

2) Validate client certificates explicitly in middleware to enforce mTLS policies:

// start/middleware/mtls-validate.js
const fs = require('fs');
const caCerts = fs.readFileSync('/etc/ssl/certs/ca.crt').toString();
const allowedSubjects = ['CN=trusted-client.example.com', 'CN=api-gateway.example.com'];

class MtlsValidateMiddleware {
  async handle({ request }, next) {
    const socket = request.socket;
    if (!socket.authorized) {
      throw new Error('Client certificate not authorized');
    }
    const cert = socket.getPeerCertificate();
    if (!cert.subject) {
      throw new Error('Client certificate missing subject');
    }
    if (!allowedSubjects.includes(cert.subject)) {
      throw new Error('Client certificate subject not allowed');
    }
    // Optionally verify CA chain is already enforced by rejectUnauthorized
    await next();
  }
}

module.exports = MtlsValidateMiddleware;

3) Avoid runtime execution of user-influenced file paths or commands. If dynamic imports are required, whitelist allowed modules:

// Example safe dynamic import resolver
const path = require('path');
const allowedModules = new Set(['@app/validators/cert-utils', '@app/handlers/tls-handler']);

function safeRequire(moduleName) {
  if (!allowedModules.has(moduleName)) {
    throw new Error('Module not allowed');
  }
  return require(path.resolve(__dirname, '..', moduleName));
}

// Usage in a controller — only pre-approved modules can be loaded
try {
  const module = safeRequire(userSuppliedModuleName);
  const result = module.process();
} catch (err) {
  console.error('Safe require failed:', err);
}

4) Do not mount the Docker socket inside containers that run AdonisJS APIs unless absolutely necessary. If required, run the process as a non-root user and restrict capabilities. For example, in Dockerfile:

FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 3333
CMD ["node", "server.js"]

By combining strict mTLS configuration, input validation, and least-privilege execution, you reduce the impact of authenticated requests and mitigate container escape risks in AdonisJS applications.

Frequently Asked Questions

Does mTLS alone prevent container escape in AdonisJS?
No. Mutual TLS ensures authenticated clients, but it does not restrict what an authenticated request can do inside the container. Runtime privileges, file permissions, and unsafe integrations still need hardening.
How does middleBrick help detect risks related to mTLS and container escape?
middleBrick’s LLM/AI Security checks can flag prompt injection or data exfiltration attempts via authenticated channels, while the Server Side Request Forgery and Inventory Management checks highlight risky runtime integrations that may enable container escape.