Container Escape in Adonisjs
How Container Escape Manifests in Adonisjs
Container escape vulnerabilities in Adonisjs applications typically emerge through improper handling of system-level operations and file system access. Adonisjs developers often leverage Node.js's built-in modules like fs, child_process, or process to implement functionality such as file uploads, system monitoring, or external command execution. When these operations aren't properly sandboxed within container boundaries, attackers can exploit them to break out of the container isolation.
A common manifestation occurs in file upload handlers where developers use fs.rename() or fs.mkdir() without validating paths. Consider this vulnerable Adonisjs controller:
class FileUploadController { async upload({ request, response }) { const file = request.file('document', { size: '2mb' }); await file.move('uploads/', { name: file.clientName }); response.send('Upload successful'); } } The issue here is that file.clientName could contain path traversal sequences like ../../, allowing an attacker to write files outside the intended directory. In a containerized environment, this could enable writing to mounted volumes or even the container's root filesystem.
Another Adonisjs-specific vector involves the use of Event listeners and custom service providers. Developers might create service providers that execute system commands based on configuration files:
class SystemMonitorProvider { async boot() { const config = await fs.readFile('config/system.json', 'utf8'); const commands = JSON.parse(config).startupCommands; commands.forEach(cmd => { exec(cmd); }); } } If an attacker can modify system.json (perhaps through a separate vulnerability), they could execute arbitrary commands that escape the container, especially if the container runs with elevated privileges or has mounted host directories.
Adonisjs-Specific Detection
Detecting container escape vulnerabilities in Adonisjs requires examining both the application code and runtime behavior. middleBrick's black-box scanning approach is particularly effective here, as it tests the unauthenticated attack surface without requiring access to source code or credentials.
middleBrick scans for several Adonisjs-specific indicators of container escape risk:
- Unsafe file operations: The scanner tests for path traversal vulnerabilities by submitting filenames containing
../sequences to file upload endpoints and monitoring responses for successful writes outside intended directories. - Command injection patterns: middleBrick sends payloads designed to trigger system command execution through various input vectors, looking for signs that commands are being executed with elevated privileges.
- Environment exposure: The scanner checks if the application inadvertently exposes container-specific information like environment variables, container IDs, or host system details through error messages or API responses.
- LLM security checks: For Adonisjs applications using AI/ML features, middleBrick tests for prompt injection vulnerabilities that could lead to data exfiltration or unauthorized system access.
For developers who have access to source code, additional detection can be performed using static analysis tools that look for:
import { existsSync, mkdirSync, renameSync } from 'fs'; import { execSync } from 'child_process'; // Dangerous patterns to flag if (existsSync(path)) { mkdirSync(path); } // Path traversal risk execSync(`command ${userInput}`); // Command injection riskmiddleBrick's OpenAPI spec analysis also helps by cross-referencing documented endpoints with runtime behavior, identifying discrepancies that might indicate hidden functionality or undocumented capabilities that could be exploited for container escape.
Adonisjs-Specific Remediation
Securing Adonisjs applications against container escape requires a defense-in-depth approach. Here are Adonisjs-specific remediation strategies:
1. Secure File Operations
Always validate and sanitize file paths using Adonisjs's built-in validation features:
import { schema } from '@adonisjs/core/validator'; class SecureUploadController { async upload({ request, response }) { const uploadSchema = schema.create({ file: schema.file({ size: '2mb', extnames: ['pdf', 'doc', 'docx'] }) }); const payload = await request.validate(uploadSchema); const file = payload.file; const safeName = path.basename(file.clientName); const uploadDir = 'uploads/' + safeName; await file.move(Application.tmpPath('uploads'), { name: safeName }); response.send('Upload successful'); } } The key changes are using path.basename() to strip directory components and validating file extensions and sizes through Adonisjs's schema validation.
2. Command Execution Safety
Never use exec() or execSync() with user input. Instead, use Adonisjs's config system and whitelist allowed commands:
import { config } from '@adonisjs/core'; class SafeCommandController { async runCommand({ request, response }) { const allowedCommands = config.get('system.allowedCommands', []); const { command } = request.qs(); if (!allowedCommands.includes(command)) { return response.status(400).send('Invalid command'); } try { const result = await new Promise((resolve, reject) => { exec(command, (error, stdout, stderr) => { if (error) reject(error); else resolve(stdout); }); }); response.send(result); } catch (error) { response.status(500).send('Command execution failed'); } } } 3. Container Runtime Hardening
Configure your container to minimize attack surface:
# Dockerfile FROM node:18-alpine USER node:node WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3333 # Drop capabilities --cap-drop ALL # Add back only necessary capabilities # (none for most Adonisjs apps) # Run as non-root user CMD ["node", "ace", "serve", "--prod"]4. Use Adonisjs Middleware for Security
Create custom middleware to sanitize inputs before they reach your controllers:
class SecurityMiddleware { async handle({ request, response }, next) { const sanitizedData = this.sanitizeInput(request.all()); request.body(sanitizedData); await next(); } sanitizeInput(data) { // Remove or escape dangerous characters // Prevent path traversal // Validate against allowed patterns return data; } } export default SecurityMiddleware;5. Implement Rate Limiting
Use Adonisjs's rate limiting to prevent brute force attacks that could be used to discover container escape vectors:
Route.post('upload', 'FileUploadController.upload').middleware(['throttle:60,5']); // 60 requests per 5 minutesBy combining these Adonisjs-specific remediation techniques with proper container configuration and continuous scanning with middleBrick, you can significantly reduce the risk of container escape vulnerabilities in your applications.