GitHub Security Advisory: GHSA-6h2f-wjhf-4wjx
Package: pyrofork (PIP)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Vulnerable versions: <= 2.3.68
Patched in: 2.3.69

Summary: Pyrofork has a Path Traversal in download_media Method

Details:
## Summary

The `download_media` method in Pyrofork does not sanitize filenames received from Telegram messages before using them in file path construction. This allows a remote attacker to write files to arbitrary locations on the filesystem by sending a specially crafted document with path traversal sequences (e.g., `../`) or absolute paths in the filename.

---

## Details

When downloading media, if the user does not specify a custom filename (which is the common/default usage), the method falls back to using the `file_name` attribute from the media object. This attribute originates from Telegram's `DocumentAttributeFilename` and is controlled by the message sender.

### Vulnerable Code Path

**Step 1**: In `pyrogram/methods/messages/download_media.py` (lines 145-151):

```python
media_file_name = getattr(media, "file_name", "")  # Value from Telegram message

directory, file_name = os.path.split(file_name)    # Split user's path parameter
file_name = file_name or media_file_name or ""     # Falls back to media_file_name if empty
```

When a user calls `download_media(message)` or `download_media(message, "downloads/")`, the `os.path.split()` returns an empty filename, causing the code to use `media_file_name` which is attacker-controlled.

**Step 2**: In `pyrogram/client.py` (line 1125):

```python
temp_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + ".temp"
```

The `os.path.join()` function does not prevent path traversal. When `file_name` contains `../` sequences or is an absolute path, it allows writing outside the intended download directory.

### Why the existing `isabs` check is insufficient

The check at line 153 in `download_media.py`:

```python
if not os.path.isabs(file_name):
    directory = self.PARENT_DIR / (directory or DEFAULT_DOWNLOAD_DIR)
```

This check only handles absolute paths by skipping the directory prefix, but:
1. For relative paths with `../`, `os.path.isabs()` returns `False`, so the check doesn't catch it
2. For absolute paths, `os.path.join()` in the next step will still use the absolute path directly

---

## PoC

The following Python script demonstrates the vulnerability by simulating the exact code logic from `download_media.py` and `client.py`:

```python
#!/usr/bin/env python3
"""
Path Traversal PoC for Pyrofork download_media
Demonstrates CWE-22 vulnerability in filename handling
"""

import os
import shutil
import tempfile
from pathlib import Path
from dataclasses import dataclass

@dataclass
class MockDocument:
    """Simulates a Telegram Document with attacker-controlled file_name"""
    file_id: str
    file_name: str  # Attacker-controlled!

@dataclass  
class MockMessage:
    """Simulates a Telegram Message"""
    document: MockDocument

DEFAULT_DOWNLOAD_DIR = "downloads/"

def vulnerable_download_media(parent_dir, message, file_name=DEFAULT_DOWNLOAD_DIR):
    """
    Simulates the vulnerable logic from:
    - pyrogram/methods/messages/download_media.py (lines