| タイトル | dazeb markdown-downloader 3d4394b34b6c99d81af817623af55e3384df5a6a Path Traversal |
|---|
| 説明 | # Path Traversal Vulnerability in dazeb/markdown-downloader
## Identification
- **Project:** markdown-downloader
- **Repository:** https://github.com/dazeb/markdown-downloader
- **Affected Version/Commit:** 3d4394b34b6c99d81af817623af55e3384df5a6a
## CVE Description
The server accepts user-controlled directory parameters and directly uses them in filesystem path construction with `path.join(config.downloadDirectory, input, ...)`. Multiple tools then perform filesystem operations (`writeFile`, `readdir`, `ensureDir`) on these derived paths without enforcing a root-boundary check. This can allow path traversal via `../` sequences and may result in unauthorized file write/read/list operations outside the intended download directory.
## Affected Component
- **File(s):** `src/index.ts`
- **Function / Method:** `download_markdown`, `list_downloaded_files`, `create_subdirectory`
- **Entry Point:** MCP tool arguments `subdirectory` / `subdirectoryName`
## Reproduction Summary
1. Call `download_markdown` with attacker-controlled `subdirectory` (e.g. `../../tmp/poc`).
2. The server constructs `path.join(config.downloadDirectory, subdirectory, filename)` and writes output using `fs.writeFile(...)`.
3. Call `list_downloaded_files` with attacker-controlled `subdirectory` and observe `fs.readdir(...)` on joined path.
4. Call `create_subdirectory` with attacker-controlled `subdirectoryName` and observe `fs.ensureDir(...)` on joined path.
5. No strict `resolve + startsWith(allowedRoot)` boundary enforcement is applied before these operations.
## Technical Details
```ts
// src/index.ts (download_markdown)
filepath = path.join(config.downloadDirectory, subdirectory, filename);
await fs.writeFile(filepath, response.data);
```
```ts
// src/index.ts (list_downloaded_files)
const listDir = subdirectory && typeof subdirectory === 'string'
? path.join(config.downloadDirectory, subdirectory)
: config.downloadDirectory;
const files = await fs.readdir(listDir);
```
```ts
// src/index.ts (create_subdirectory)
const newSubdirectoryPath = path.join(config.downloadDirectory, subdirectoryName);
await fs.ensureDir(newSubdirectoryPath);
```
## Validation Notes
- User-controlled path segments are used directly in path.join(...).
- Filesystem calls are reached without explicit root-boundary validation.
- Behavior is consistent with path traversal risk (directory escape via crafted relative segments).
## PoC / Screenshots
- Screenshot 1: download_markdown flow (path.join + fs.writeFile)
<img width="990" height="282" alt="Image" src="https://github.com/user-attachments/assets/73977529-b3e8-4f65-9a11-cb11ffb1b052" />
- Screenshot 2: list_downloaded_files flow (path.join + fs.readdir)
<img width="987" height="213" alt="Image" src="https://github.com/user-attachments/assets/89421fa8-f352-4812-90bd-1ed7f91ac714" />
- Screenshot 3: create_subdirectory flow (path.join + fs.ensureDir)
<img width="966" height="231" alt="Image" src="https://github.com/user-attachments/assets/67f9ced1-a247-4f6b-a2d7-a5b8afb0c9b6" />
|
|---|
| ソース | ⚠️ https://github.com/dazeb/markdown-downloader/issues/12 |
|---|
| ユーザー | Anonymous User |
|---|
| 送信 | 2026年04月27日 10:42 (1 月 ago) |
|---|
| モデレーション | 2026年05月24日 11:07 (27 days later) |
|---|
| ステータス | 承諾済み |
|---|
| VulDBエントリ | 365453 [dazeb markdown-downloader 迄 3d4394b34b6c99d81af817623af55e3384df5a6a src/index.ts ディレクトリトラバーサル] |
|---|
| ポイント | 20 |
|---|