HIGH container escapeadonisjstypescript

Container Escape in Adonisjs (Typescript)

Container Escape in Adonisjs with Typescript — how this specific combination creates or exposes the vulnerability

Adonisjs, a Node.js framework written in Typescript, provides a structured way to build server-side applications. When deployed in containerized environments (e.g., Docker), misconfigurations in file system permissions, privileged container execution, or insecure volume mounts can lead to container escape — where an attacker breaks out of the container to gain unauthorized access to the host system. In Adonisjs applications, this risk is amplified when:

  • The application runs as root inside the container (common in development Dockerfiles that inherit from node:latest without dropping privileges).
  • Volume mounts expose sensitive host paths (e.g., /var/run/docker.sock, /sys, or /proc) to the container, which Adonisjs routes may inadvertently expose via file upload or static file serving.
  • Typescript’s structural typing and compile-time safety do not prevent runtime misconfigurations; they only catch type errors, not insecure Dockerfile directives or volume mounts.
  • An Adonisjs route that serves user-uploaded files without proper path validation (e.g., using path.join without sanitization) could allow an attacker to write a malicious script to a mounted host directory, which is then executed with host privileges.

For example, if a developer mounts the host’s /app directory into the container at /var/www and the Adonisjs application writes user avatars to /var/www/uploads, a path traversal flaw could let an attacker write a file to /app/../../etc/passwd — effectively escaping the container’s intended scope. middleBrick detects such risks by scanning for exposed internal endpoints (like /upload or /file) and testing for path traversal, insecure file permissions, and signs of privileged container execution (e.g., processes running as UID 0). It does not require agents or configuration — just the API URL — and reports findings with severity and remediation guidance.

Typescript-Specific Remediation in Adonisjs — concrete code fixes

To mitigate container escape risks in an Adonisjs application written in Typescript, focus on secure coding practices that prevent file system abuse, combined with secure container configuration. Below are specific, actionable fixes:

// Start: Secure file upload handler in Adonisjs (using @ioc:Adonis/Core/Drive)
import Drive from '@ioc:Adonis/Core/Drive'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { fileURLToPath } from 'url'
import { dirname, join, resolve } from 'path'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

// Define a safe, isolated upload directory INSIDE the container (not mounted host paths)
const UPLOAD_DIR = resolve(__dirname, '..', 'tmp', 'uploads')

// Ensure the directory exists and is isolated
import { mkdir } from 'fs/promises'
await mkdir(UPLOAD_DIR, { recursive: true, mode: 0o700 })

export default class FileUploadController {
  public async handle({ request, response }: HttpContextContract) {
    const upload = request.file('avatar', {
      size: '2mb',
      extnames: ['jpg', 'png', 'gif']
    })

    if (!upload) {
      return response.badRequest({ error: 'No file uploaded' })
    }

    // Generate a safe, random filename to prevent path manipulation
    const fileName = `${crypto.randomUUID()}.${upload.extname}`
    const filePath = join(UPLOAD_DIR, fileName)

    // Explicitly validate the resolved path is within UPLOAD_DIR
    const resolvedPath = resolve(filePath)
    if (!resolvedPath.startsWith(UPLOAD_DIR)) {
      return response.badRequest({ error: 'Invalid file path' })
    }

    await upload.move(UPLOAD_DIR, {
      name: fileName,
      overwrite: false
    })

    if (!upload.moved()) {
      return response.badRequest({ error: upload.errors.messages })
    }

    return response.ok({ message: 'File uploaded securely', filePath: `/tmp/uploads/${fileName}` })
  }
}

This code prevents path traversal by:

  • Using a fixed, isolated upload directory (tmp/uploads) inside the container — never relying on environment variables or user input for the base path.
  • Generating a cryptographically random filename to eliminate predictable paths.
  • Validating that the resolved file path starts with the intended base directory using path.resolve and startsWith — a critical Typescript/runtime check.
  • Setting restrictive directory permissions (0o700) to limit access even if the container is compromised.

Complement this with secure container practices:

  • Run the Adonisjs process as a non-root user in Dockerfile: USER node (assuming the node user exists).
  • Avoid mounting host sockets or sensitive directories: never use -v /var/run/docker.sock:/var/run/docker.sock or -v /sys/fs/cgroup:/sys/fs/cgroup:ro in production.
  • Use read_only: true and drop unnecessary Linux capabilities (CAP_SYS_ADMIN, etc.) via security_context in Kubernetes or --cap-drop in Docker.

middleBrick helps validate these fixes by scanning the running API for exposed file endpoints, testing for path traversal and excessive privileges, and reporting if the container is running as root or has dangerous mounts — all without needing internal access or agents.

Frequently Asked Questions

Can middleBrick detect if my Adonisjs application is running as root inside a container?
Yes. middleBrick performs black-box scanning of the unauthenticated attack surface and can infer privilege levels from runtime behavior, such as responses from endpoints that leak process information (e.g., /debug or misconfigured health checks) or by analyzing file system access patterns during testing. It does not require internal access — only the public API URL — and will flag if the application appears to be running with elevated privileges based on observable behaviors like successful access to protected system paths.

Does using Typescript in Adonisjs eliminate the risk of container escape?
No. Typescript provides compile-time type safety but does not prevent runtime misconfigurations such as insecure Dockerfile directives, excessive volume mounts, or path traversal flaws in file handling code. Container escape risks stem from deployment and runtime configuration, not language-level types. Secure coding practices (like validating file paths) and container hardening (non-root users, read-only filesystems, dropped capabilities) are essential regardless of whether the application is written in Typescript or JavaScript.