HIGH symlink attackadonisjsjwt tokens

Symlink Attack in Adonisjs with Jwt Tokens

Symlink Attack in Adonisjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability

A Symlink Attack in AdonisJS involving JWT tokens typically occurs when file uploads or user-controlled paths are handled insecurely, and JWT tokens are used for session or identity management without proper validation. In AdonisJS, applications often rely on JWT tokens for stateless authentication, especially in APIs. If an endpoint accepts user-supplied file paths or directories for upload, download, or extraction, an attacker can craft a path containing directory traversal sequences or symbolic links (e.g., ../../../etc/passwd) that resolves outside the intended directory. When the server writes or reads files based on this malicious path, the JWT token—used to identify the user—can be leveraged to escalate impact, such as overwriting critical configuration files or accessing unauthorized resources.

For example, consider an AdonisJS route that uses JWT middleware to authenticate a request and then processes an uploaded file using a user-provided destination path:

import { schema } from '@ioc:Adonis/Core/Validator'
import Drive from '@ioc:Adonis/Core/Drive'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class FilesController {
  public async store({ request, auth }: HttpContextContract) {
    const payload = request.validate({
      schema: schema.create({
        destination: schema.string()
      })
    })
    const user = auth.use('api').user! // JWT-authenticated user
    await Drive.put('uploads/' + payload.destination, request.file('file').stream)
    return { ok: true }
  }
}

If the destination value is not strictly sanitized, an attacker authenticated with a valid JWT token can supply a path like ../../../config/app, causing the file to be written outside the intended uploads folder. This can overwrite application settings or even inject malicious configuration. Because JWT tokens authenticate the request, the operation may be logged under a legitimate user, bypassing naive path-based access controls. This combination weakens isolation between user identity and file system boundaries, enabling unauthorized file manipulation.

Additionally, if the application serves uploaded files through a route that resolves paths without canonicalization, an attacker can use symbolic links in shared or temporary directories to redirect reads or writes. The JWT token may not be directly involved in the file resolution, but it ensures the request is treated as authenticated, potentially relaxing logging or monitoring checks. In AdonisJS, failure to validate and sanitize file paths—especially when tied to JWT-based authentication—creates conditions where a Symlink Attack can compromise integrity or confidentiality.

Jwt Tokens-Specific Remediation in Adonisjs — concrete code fixes

To remediate Symlink Attack risks in AdonisJS when using JWT tokens, focus on strict input validation, path sanitization, and avoiding direct use of user-controlled values in file operations. Ensure that file destination paths are resolved relative to a controlled base directory, and never concatenate user input directly into paths. Use AdonisJS built-in validators and Drive utilities safely.

First, validate and sanitize the destination using a strict schema that only allows safe characters and prohibits path traversal sequences:

import { schema } from '@ioc:Adonis/Core/Validator'
import Drive from '@ioc:Adonis/Core/Drive'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class FilesController {
  public async store({ request, auth, response }: HttpContextContract) {
    const payload = request.validate({
      schema: schema.create({
        destination: schema.string({}, [
          (value, pointer, tree) => {
            if (value.includes('..') || value.includes('/') || value.includes('\\')) {
              tree.report(
                'Invalid destination: path traversal not allowed',
                pointer,
                'invalid_path'
              )
            }
          }
        ])
      })
    })

    const user = auth.use('api').user!
    const safeDestination = `uploads/${Date.now()}_${payload.destination}`
    await Drive.put(safeDestination, request.file('file').stream)
    return response.ok({ ok: true, path: safeDestination })
  }
}

Second, when serving files, resolve paths using Drive methods that prevent directory traversal and avoid symbolic link resolution:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Drive from '@ioc:Adonis/Core/Drive'

export default class FilesController {
  public async show({ request, response }: HttpContextContract) {
    const fileName = request.qs().file as string
    // Use Drive.getStream with a resolved, safe path
    const stream = await Drive.getStream(`uploads/${encodeURIComponent(fileName)}`)
    return response.type('application/octet-stream').body(stream)
  }
}

Third, ensure JWT middleware is properly scoped and does not inadvertently authorize unsafe operations. Combine role-based checks with path validation:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { schema } from '@ioc:Adonis/Core/Validator'

export default class FilesController {
  public async destroy({ auth, request, response }: HttpContextContract) {
    const user = auth.use('api').user!
    const fileName = request.qs().file as string

    // Enforce ownership or role-based policy before deletion
    if (!user.canDelete(fileName)) {
      return response.forbidden({ error: 'Access denied' })
    }

    const safePath = `uploads/${encodeURIComponent(fileName)}`
    await Drive.delete(safePath)
    return response.noContent()
  }
}

These practices reduce the attack surface by ensuring JWT tokens authenticate requests but do not implicitly trust user-supplied path components. Always canonicalize and validate paths server-side and avoid symbolic link resolution in file operations.

Frequently Asked Questions

How does middleBrick detect risks related to symlinks and JWT usage?
middleBrick runs 12 parallel security checks including Input Validation and Unsafe Consumption. It analyzes OpenAPI specs and runtime behavior to identify path traversal patterns, missing canonicalization, and JWT-authenticated endpoints that accept unsanitized file paths, reporting findings with severity and remediation guidance.
Can the GitHub Action prevent symlink-based deployments when JWT-related endpoints are exposed?
Yes. The GitHub Action can fail builds if the scan’s risk score drops below your configured threshold, flagging high-severity findings such as unvalidated path handling in JWT-protected routes before deployment.