# fast-mcp-telegram: Bearer token path traversal bypasses reserved Telegram session protection

fast-mcp-telegram joins raw Bearer tokens into session file paths, so token `../fast-mcp-telegram/telegram` authenticates as the reserved default Telegram session.

- Payout: Research
- Severity: critical
- Program: fast-mcp-telegram
- Found by: DavidCarliez
- Disclosed: 2026-07-02
- CVE: CVE-2026-52830
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-rxw2-pc8j-vxwm
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-rxw2-pc8j-vxwm
- Tags: area:ai domain:ai domain:web impact:ato impact:data-leak kind:research platform:ghsa sev:critical tech:python technique:source-review vuln:access-control vuln:auth-bypass vuln:path-traversal

**Target:** HTTP Bearer token auth / session file loader in MCP server
**Root cause:** SessionFileTokenVerifier rejects only exact reserved names then appends `.session` to the raw token without rejecting path separators or verifying the resolved path stays inside the session directory.
**Steps:**
1. Observe verifier rejects exact token `telegram` via `if token.lower() in RESERVED_SESSION_NAMES: return None`
2. Note path built as `self._session_directory / f"{token}.session"` with no traversal check
3. Send Bearer token `../fast-mcp-telegram/telegram`; it resolves to `~/.config/fast-mcp-telegram/telegram.session`
4. Verifier accepts since file exists; client builder uses same path and loads default session
5. Call account-prefixed MCP tools (e.g. `defaultalice_send_message`) as the default Telegram account
**How found:** Code review of token verification: noticed reserved-name blocklist checks exact string only, then raw token is concatenated into a filesystem path, prompting a traversal alias test against the documented default session name.
**Exploitation:** Unauthenticated HTTP client supplies traversal token as Bearer credential; server resolves it to the default legacy `telegram.session` file and authenticates the request as that Telegram account, granting message read/send and MTProto tool access.
**Escalation:** Account-prefix middleware downstream of auth exposes the default account's prefixed tools to the attacker, extending access to full tool surface of that session.
**Insight:** When a blocklist guards a name that is later used as a filesystem path component, test traversal aliases (`../dir/name`) that resolve to the same blocked file; blocklists on raw strings miss path normalization.

## Proof of concept (copied exactly from the original report)

**Traversal token authenticating as default session**

```
{
  "reserved_default_token_denied": true,
  "normal_random_token_allowed": true,
  "missing_traversal_token_denied": true,
  "traversal_alias_to_reserved_default_allowed": true,
  "traversal_access_token_value": "../fast-mcp-telegram/telegram",
  "client_builder_used_default_session_file": true,
  "prefixed_tool_listed_for_traversal_token": "defaultalice_send_message",
  "prefixed_tool_call_reached_handler_as": "send_message",
  "unprefixed_tool_call_denied_when_prefix_resolved": true
}
```

**Vulnerable token-to-path construction**

```
session_path = self._session_directory / f"{token}.session"
if not session_path.is_file():
    return None
```

**Client builder session path construction**

```
session_path = SESSION_DIR / f"{token}.session"
client = await _build_telegram_client_for_token(session_path, token)
```

