PoC Archive PoC Archive
Critical CVE-2026-21440 (GHSA-gvq6-hvvp-h34h) unpatched

AdonisJS bodyparser Path Traversal to Arbitrary File Write (CVE-2026-21440)

by k0nnect · 2026-07-05

CVSS 9.2/10
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

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-01
Author / Researcherk0nnect
CVE / AdvisoryCVE-2026-21440 (GHSA-gvq6-hvvp-h34h)
Categoryweb
SeverityCritical
CVSS Score9.2 (CVSS v3.1, per source)
StatusWeaponized
Tagsadonisjs, nodejs, path-traversal, arbitrary-file-write, cwe-22, file-upload, rce, bodyparser
RelatedN/A

Affected Target

FieldValue
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 / PlatformPython (exploit script); Node.js/TypeScript AdonisJS application (target)
Authentication RequiredNo
Network Access RequiredYes

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

  1. Attacker identifies an AdonisJS endpoint that accepts a file upload and calls request.file('upload').move(location) without passing an explicit name option.
  2. Attacker crafts a multipart/form-data POST request where the file part’s filename field contains a path-traversal payload (e.g., filename="../../tmp/pwned.txt").
  3. Attacker sends the request (via raw socket or curl -F "file=@payload;filename=../../tmp/pwned.txt") to the vulnerable upload endpoint.
  4. The server resolves the traversal sequence and writes the attacker-supplied file content outside the intended tmp/uploads directory, at the attacker-chosen path.
  5. 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), and Vulnerable-App/server.ts + Dockerfile (vulnerable lab app) in this folder.

1
2
3
cd Exploit-PoC
pip install -r requirements.txt
python exploit.py --url http://target:3333/upload --path "../../../tmp/pwned.txt" --content "pwned"

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

ActionDetail
Primary fixUpgrade @adonisjs/bodyparser to 10.1.2 (or 11.0.0-next.6 for the next line), which sanitizes the filename used by move()
Interim mitigationAlways 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.