AdonisJS bodyparser Path Traversal to Arbitrary File Write (CVE-2026-21440)
by k0nnect · 2026-07-05
- Severity
- Critical
- CVE
- CVE-2026-21440 (GHSA-gvq6-hvvp-h34h)
- Category
- web
- Affected product
- @adonisjs/bodyparser (AdonisJS multipart file-upload handling)
- Affected versions
- @adonisjs/bodyparser <= 10.1.1, and 11.0.0-next.1 through 11.0.0-next.5
- Disclosed
- 2026-07-05
- Patch status
- unpatched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-01 |
| Author / Researcher | k0nnect |
| CVE / Advisory | CVE-2026-21440 (GHSA-gvq6-hvvp-h34h) |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.2 (CVSS v3.1, per source) |
| Status | Weaponized |
| Tags | adonisjs, nodejs, path-traversal, arbitrary-file-write, cwe-22, file-upload, rce, bodyparser |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | @adonisjs/bodyparser (AdonisJS multipart file-upload handling) |
| Versions Affected | @adonisjs/bodyparser <= 10.1.1, and 11.0.0-next.1 through 11.0.0-next.5 |
| Language / Platform | Python (exploit script); Node.js/TypeScript AdonisJS application (target) |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
CVE-2026-21440 is a path-traversal vulnerability in @adonisjs/bodyparser’s MultipartFile.move() method. When an application calls file.move(location) without explicitly supplying a sanitized name option, the library falls back to the client-supplied original filename (clientName) and joins it onto the destination directory with path.join(), which does not strip ../ traversal sequences. Combined with a default overwrite: true behavior, a remote unauthenticated attacker can upload a file whose Content-Disposition filename contains directory-traversal sequences (e.g., ../../etc/cron.d/malicious) to write attacker-controlled content to an arbitrary path on the server’s filesystem, which can lead to remote code execution (e.g., via cron job injection, SSH key injection, or config overwrite). The PoC crafts a raw multipart/form-data HTTP request with a malicious filename and sends it directly over a socket to bypass any client-side sanitization.
Vulnerability Details
Root Cause
MultipartFile.move(location, options) computes const fileName = options?.name || this.clientName and then const filePath = path.join(location, fileName) before moving the uploaded temp file to filePath with overwrite: options?.overwrite ?? true. Because clientName is taken verbatim from the attacker-controlled multipart filename and never sanitized, and path.join resolves .. segments rather than rejecting them, an attacker-supplied filename like ../../etc/cron.d/pwned escapes the intended upload directory.
Attack Vector
- Attacker identifies an AdonisJS endpoint that accepts a file upload and calls
request.file('upload').move(location)without passing an explicitnameoption. - Attacker crafts a multipart/form-data POST request where the file part’s
filenamefield contains a path-traversal payload (e.g.,filename="../../tmp/pwned.txt"). - Attacker sends the request (via raw socket or
curl -F "file=@payload;filename=../../tmp/pwned.txt") to the vulnerable upload endpoint. - The server resolves the traversal sequence and writes the attacker-supplied file content outside the intended
tmp/uploadsdirectory, at the attacker-chosen path. - Depending on the write target (cron directory, SSH
authorized_keys, application config, etc.), this can escalate to remote code execution or further compromise.
Impact
Unauthenticated remote attackers can write arbitrary files anywhere the application process has filesystem permissions, enabling configuration tampering, persistence, and potential remote code execution.
Environment / Lab Setup
Target: AdonisJS application using @adonisjs/bodyparser <=10.1.1 / 11.0.0-next.1-5, file-upload endpoint calling file.move() without a sanitized name (Vulnerable-App/server.ts, Dockerfile — docker-compose lab)
Attacker: Python 3 with requests/requests-toolbelt/urllib3 (Exploit-PoC/exploit.py, requirements.txt)
Proof of Concept
PoC Script
See
Exploit-PoC/exploit.py(exploit),Exploit-PoC/requirements.txt(dependencies), andVulnerable-App/server.ts+Dockerfile(vulnerable lab app) in this folder.
| |
The script builds a raw multipart/form-data HTTP request over a plain socket (bypassing any client-library filename sanitization), sets the file part’s filename to the supplied traversal path, and sends it to the target upload endpoint. A 200 response with escapedUploadsDir in the JSON body confirms the file was written outside the intended uploads directory.
Detection & Indicators of Compromise
Signs of compromise:
- Files appearing outside the application’s configured upload directory (e.g., in
/etc/cron.d,~/.ssh, application config paths). - Upload requests containing
filename="../..."sequences in access/application logs. - Unexpected new cron jobs, SSH keys, or modified config files correlated with upload endpoint activity.
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade @adonisjs/bodyparser to 10.1.2 (or 11.0.0-next.6 for the next line), which sanitizes the filename used by move() |
| Interim mitigation | Always pass an explicit, generated name option (e.g., a UUID/cuid plus validated extension) to file.move() and set overwrite: false; validate uploaded filenames against an allowlist before use. |
References
Notes
Mirrored from https://github.com/k0nnect/cve-2026-21440-writeup on 2026-07-05.