HIGH symlink attackadonisjs

Symlink Attack in Adonisjs

How Symlink Attack Manifests in Adonisjs

Symlink attacks in Adonisjs applications typically exploit the framework's file system operations, particularly when user-controlled paths are used to create or follow symbolic links. This vulnerability becomes critical when Adonisjs applications handle file uploads, serve static content, or perform file operations based on user input.

The most common manifestation occurs when Adonisjs applications use the @adonisjs/core file system utilities with untrusted input. Consider a file upload scenario where users can specify a destination path:

const { Drive } = use('Drive')

// Vulnerable code
const destination = request.input('destination') 
await Drive.put(`${destination}/uploaded-file.txt`, fileContent)

An attacker could set destination to a path containing ../ sequences or symbolic links, potentially overwriting critical files outside the intended directory. This is particularly dangerous in Adonisjs because the framework's default configuration often includes broad file system permissions.

Another Adonisjs-specific scenario involves the Storage provider, which wraps various storage drivers. When using the local driver with user-controlled paths:

const storage = storage('local')
const userPath = request.input('path') // User controlled
await storage.put(userPath, fileContent)

If userPath points to a symbolic link, the application might write data to an unintended location, potentially overwriting system files or accessing sensitive data.

Adonisjs applications also commonly use the fs module directly for various operations. A typical vulnerable pattern looks like:

const fs = require('fs/promises')
const path = require('path')

// Vulnerable code
const userPath = request.input('filePath')
const fullPath = path.join(__dirname, 'uploads', userPath)
const content = await fs.readFile(fullPath, 'utf8')

Even with path.join, if userPath contains ../ sequences or points to a symbolic link, the application could read arbitrary files on the server.

Adonisjs's middleware system can also be exploited if path resolution isn't properly handled. For example, a custom middleware that resolves file paths:

class FileAccessMiddleware {
  async handle({ request }, next) {
    const filePath = request.input('file')
    const fullPath = path.resolve('storage', filePath)
    request.fileFullPath = fullPath
    await next()
  }
}

This code is vulnerable because path.resolve will resolve symbolic links, potentially allowing access to files outside the intended directory.

Adonisjs-Specific Detection

Detecting symlink attacks in Adonisjs applications requires a combination of static analysis and runtime monitoring. The most effective approach is using middleBrick's API security scanner, which specifically tests for symlink vulnerabilities in Adonisjs applications.

middleBrick's scanner performs black-box testing by attempting to create and follow symbolic links through various API endpoints. It tests the unauthenticated attack surface by sending requests with path traversal payloads and symlink patterns. The scanner runs 12 parallel security checks, including input validation and path traversal testing specifically designed for Node.js frameworks like Adonisjs.

To manually detect symlink vulnerabilities in Adonisjs code, look for these patterns:

// Search for these patterns in your Adonisjs codebase
// 1. Direct fs module usage with user input
const fs = require('fs/promises')
const userPath = request.input('path')
await fs.readFile(userPath)

// 2. Drive provider usage with unvalidated paths
const { Drive } = use('Drive')
const destination = request.input('destination')
await Drive.put(`${destination}/file.txt`, content)

// 3. Storage provider with user-controlled paths
const storage = storage('local')
const userPath = request.input('filePath')
await storage.get(userPath)

middleBrick specifically tests for these vulnerabilities by sending requests with crafted payloads that attempt to:

  • Traverse directories using ../ sequences
  • Reference symbolic links that point to sensitive locations
  • Exploit path resolution functions like path.resolve and path.join
  • Test file operations with crafted path inputs

The scanner provides a security risk score (A–F) with prioritized findings, showing exactly which endpoints are vulnerable and what specific payloads triggered the vulnerability. For Adonisjs applications, middleBrick also checks the OpenAPI/Swagger specification to ensure that path parameters are properly validated against the runtime behavior.

Additional detection methods include runtime monitoring with Node.js's fs.realpath to detect when paths resolve to unexpected locations, and using security-focused middleware that validates all file paths before operations are performed.

Adonisjs-Specific Remediation

Remediating symlink attacks in Adonisjs requires a defense-in-depth approach using the framework's built-in security features and Node.js best practices. The primary strategy is input validation combined with safe path handling.

First, implement strict path validation using Adonisjs's validation system:

const { schema } = use('@adonisjs/core')

const pathSchema = schema.create({
  destination: schema.string({}, [
    rules.required(),
    rules.regex(/^[a-zA-Z0-9_-]+$/), // Only allow safe characters
    rules.maxLength(255)
  ])
})

// In your controller
const payload = await request.validate({ schema: pathSchema })
const safePath = path.join('uploads', payload.destination)

This validation ensures that user input cannot contain path traversal characters or symbolic link references.

For file operations, use Adonisjs's built-in security features:

const { Drive } = use('Drive')
const path = require('path')

async storeFile({ request, response }) {
  const destination = request.input('destination', 'default-folder')
  const fileName = request.input('fileName', 'uploaded-file.txt')
  
  // Validate and sanitize
  const sanitizedDestination = path.basename(destination)
  const sanitizedFileName = path.basename(fileName)
  
  // Use Drive with explicit path
  const safePath = path.join('uploads', sanitizedDestination, sanitizedFileName)
  
  // Check if path is within allowed directory
  const resolvedPath = path.resolve('uploads', sanitizedDestination)
  const uploadsDir = path.resolve('uploads')
  
  if (!resolvedPath.startsWith(uploadsDir)) {
    return response.status(400).send('Invalid path')
  }
  
  // Now it's safe to perform file operations
  await Drive.put(safePath, fileContent)
}

Another effective approach is using a whitelist of allowed paths:

const allowedPaths = ['uploads', 'documents', 'images']

async safeFileOperation({ request }) {
  const userPath = request.input('path')
  const [firstSegment] = userPath.split(path.sep)
  
  if (!allowedPaths.includes(firstSegment)) {
    throw new Error('Access denied')
  }
  
  // Proceed with file operation
}

For Adonisjs applications using the Storage provider, implement wrapper functions that validate paths:

const storage = storage('local')

async safeStoragePut(filePath, content) {
  const resolvedPath = path.resolve('storage', filePath)
  const storageDir = path.resolve('storage')
  
  if (!resolvedPath.startsWith(storageDir)) {
    throw new Error('Path traversal attempt detected')
  }
  
  return storage.put(filePath, content)
}

Consider using Node.js's fs.realpath to resolve symbolic links before operations:

const fs = require('fs/promises')
const path = require('path')

async safeReadFile(filePath) {
  const resolvedPath = await fs.realpath(filePath)
  const baseDir = path.resolve('safe-directory')
  
  if (!resolvedPath.startsWith(baseDir)) {
    throw new Error('Access outside base directory')
  }
  
  return fs.readFile(resolvedPath, 'utf8')
}

Finally, integrate middleBrick's continuous monitoring into your development workflow using the GitHub Action or CLI tool to catch symlink vulnerabilities before they reach production.

Frequently Asked Questions

How can I test my Adonisjs application for symlink vulnerabilities?
Use middleBrick's API security scanner which specifically tests for symlink attacks by sending crafted path traversal payloads to your endpoints. The scanner runs in 5–15 seconds and provides a detailed security report with severity levels and remediation guidance. You can also manually test by attempting to access files using '../' sequences and checking if your application properly validates and sanitizes all file paths.
Does Adonisjs provide built-in protection against symlink attacks?
Adonisjs doesn't provide automatic symlink protection, but it offers validation rules and file system utilities that you can use to implement protection. The framework's validation system allows you to create strict rules for path inputs, and the Drive/Storage providers can be used with carefully validated paths. You need to implement the security checks yourself using Adonisjs's features combined with Node.js best practices for path handling.