# Variant RCA Report: CVE-2026-52830 (fast-mcp-telegram path-traversal session bypass)

## Summary

The patched `fast-mcp-telegram 0.19.1` closes the original path-traversal bearer-token bypass. This variant analysis finds a **distinct alternate traversal alias** on the vulnerable `0.19.0` version: the reserved session name `telegram` can be addressed as `./telegram` in the HTTP `Authorization` header. Because the vulnerable code only checks the exact lowercase string against a reserved-name set, the relative-path alias `./telegram` bypasses the check and resolves to the same `telegram.session` file, granting unauthorized access to the Telegram MCP tools. The alias reproduces on `0.19.0` but is blocked by the `0.19.1` whitelist, so it is **not a bypass of the fix**.

## Fix Coverage / Assumptions

The `0.19.1` fix assumes that all legitimate bearer tokens are produced by the package’s `generate_bearer_token()` helper and therefore match the strict regular expression `^[A-Za-z0-9_-]{43}$`. It enforces this assumption in a new module (`src/server_components/session_token_validation.py`) and propagates it to every token-bearing code path:

- `src/server_components/session_token_verifier.py` (FastMCP `TokenVerifier` for `/v1/mcp`)
- `src/server_components/auth_middleware.py` (URL-token middleware `/v1/url_auth/{token}/mcp`)
- `src/server_components/auth.py` (Authorization header extraction)
- `src/client/connection.py` (TelegramClient session construction and cleanup)
- `src/server_components/web_setup.py` (setup, reauthorize, and delete flows)

The fix also resolves the constructed path and verifies it is still inside the configured session directory using `is_relative_to()`.

## Variant / Alternate Trigger

**Variant:** Bearer token `./telegram` (and other relative-path aliases of the reserved name) used in the `Authorization: Bearer ./telegram` header.

**Entry point:** `POST /v1/mcp` with the JSON-RPC body `{"jsonrpc":"2.0","id":1,"method":"tools/list"}`.

**Code path:**
1. FastMCP auth layer calls `SessionFileTokenVerifier.verify_token()` in `src/server_components/session_token_verifier.py`.
2. In `0.19.0`, the verifier checks `token.lower() in RESERVED_SESSION_NAMES`. The literal string `./telegram` is not in the set, so it passes.
3. The verifier builds `session_path = self._session_directory / f"{token}.session"`. Pathlib normalizes `./telegram.session` to `telegram.session`, which exists, so the token is accepted.
4. The request is authorized as the default session and `tools/list` returns the full tool catalog.

Other equivalent aliases confirmed on `0.19.0` include `../fast-mcp-telegram/telegram` (the original reproducer) and `fast-mcp-telegram/../telegram`. The URL-token entry point (`/v1/url_auth/./telegram/mcp`) was also tested; Starlette/uvicorn normalize the `/./` segment before the vulnerable middleware sees it, so the URL path is rejected as the reserved name `telegram`. The header-based path remains exploitable with the alias.

## Impact

- **Package/component:** `fast-mcp-telegram` (PyPI), specifically `SessionFileTokenVerifier` and the FastMCP HTTP auth layer.
- **Affected versions:** `<= 0.19.0`.
- **Patched version:** `0.19.1`.
- **Risk level:** High for the vulnerable version. The impact is identical to the original CVE: a remote, unauthenticated attacker who can reach the MCP HTTP port can authenticate as the default `telegram` session and list/invoke tools.
- **Consequences:** Unauthorized access to tools such as `get_messages`, `send_message`, `send_message_to_phone`, and `invoke_mtproto` under the default session identity.

## Impact Parity

- **Disclosed/claimed maximum impact:** Authorization bypass via HTTP Bearer token path traversal (`api_remote` / `authz_bypass`).
- **Reproduced impact from this variant run:** Real HTTP auth bypass on a running `fast-mcp-telegram 0.19.0` instance using the `./telegram` alias. The reserved token `telegram` is rejected (HTTP 401), the alias `./telegram` is accepted (HTTP 200) and returns the protected `tools/list` response, and the patched `0.19.1` build rejects the alias (HTTP 401).
- **Parity:** `full` for the claimed auth-bypass surface on the vulnerable version; the variant demonstrates the same impact through a different token string. The variant does **not** achieve impact on the fixed version.
- **Not demonstrated:** Tool invocation with the bypassed session; only the `tools/list` endpoint was exercised. No Telegram credentials were configured, so no actual Telegram RPC was performed.

## Root Cause

The root cause is the same as the parent CVE: the bearer token is used as a raw filename fragment without validating that it is a safe token or normalizing the resulting path. The vulnerable `SessionFileTokenVerifier.verify_token()` only performs an exact reserved-name check:

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

This allows any relative-path alias of a reserved name (e.g., `./telegram`) to bypass the name check while still resolving to the same file. The same pattern exists in `auth_middleware.py`, `auth.py`, and `client/connection.py`, but the auth-bypass surface is most directly reached through the MCP tools endpoint.

The `0.19.1` fix replaces this logic with a strict whitelist (`^[A-Za-z0-9_-]{43}$`) and a containment check, so the alias cannot be used.

## Reproduction Steps

Run the self-contained variant script:

```bash
bash bundle/vuln_variant/reproduction_steps.sh
```

The script:

1. Reads `bundle/project_cache_context.json` and uses the provided `project_cache_dir` for persistent Python venvs (or installs them locally if absent).
2. Creates two virtual environments, installing `fast-mcp-telegram==0.19.0` (vulnerable) and `==0.19.1` (fixed).
3. Creates a controlled `HOME` and default session directory `~/.config/fast-mcp-telegram`, then touches `telegram.session` so the default session exists.
4. Starts each version in `http-auth` mode on a different localhost port and waits for `/health` to return 200.
5. Sends a JSON-RPC `tools/list` request to `POST /v1/mcp` with several bearer tokens on the vulnerable server:
   - `telegram` (reserved, expected 401)
   - `./telegram` (alternate traversal alias, expected 200)
   - `../fast-mcp-telegram/telegram` (original traversal, expected 200)
   - `invalid-token` (no matching session file, expected 401)
6. Also sends the `./telegram` token via the URL-auth entry point (`/v1/url_auth/./telegram/mcp`) on the vulnerable server to document the normalization behavior (expected 401).
7. Sends the `./telegram` and `../fast-mcp-telegram/telegram` tokens to the fixed server (expected 401 for both).
8. Writes `bundle/vuln_variant/runtime_manifest.json` and exits 1 (the variant is an alternate trigger on the vulnerable version, not a bypass of the fix).

### Expected evidence

- `vuln_variant/artifacts/http_vuln_reserved.txt`: HTTP 401 response body.
- `vuln_variant/artifacts/http_vuln_dot_slash.txt`: HTTP 200 SSE event containing the full `tools/list` result.
- `vuln_variant/artifacts/http_vuln_original.txt`: HTTP 200 SSE event from the original traversal token (sanity check).
- `vuln_variant/artifacts/http_vuln_invalid.txt`: HTTP 401 response body.
- `vuln_variant/artifacts/http_vuln_url_dot_slash.txt`: HTTP 401 response body (URL normalization/middleware rejection).
- `vuln_variant/artifacts/http_fixed_dot_slash.txt` and `http_fixed_original.txt`: HTTP 401 response bodies from the patched version.
- `logs/server_vuln_variant.log` and `logs/server_fixed_variant.log`: server startup logs.

## Evidence

Captured artifacts:

- `bundle/vuln_variant/artifacts/http_vuln_dot_slash.txt` (HTTP 200, tools list returned)
- `bundle/vuln_variant/artifacts/http_vuln_reserved.txt` (HTTP 401, reserved token rejected)
- `bundle/vuln_variant/artifacts/http_vuln_original.txt` (HTTP 200, original traversal still works)
- `bundle/vuln_variant/artifacts/http_vuln_invalid.txt` (HTTP 401, invalid token rejected)
- `bundle/vuln_variant/artifacts/http_vuln_url_dot_slash.txt` (HTTP 401, URL entry point rejected)
- `bundle/vuln_variant/artifacts/http_fixed_dot_slash.txt` (HTTP 401, alias blocked on 0.19.1)
- `bundle/vuln_variant/artifacts/http_fixed_original.txt` (HTTP 401, original traversal blocked on 0.19.1)
- `bundle/vuln_variant/artifacts/http_fixed_url_dot_slash.txt` (HTTP 401, alias blocked on 0.19.1)
- `bundle/logs/server_vuln_variant.log`
- `bundle/logs/server_fixed_variant.log`
- `bundle/logs/variant_reproduction_steps_run2.log`
- `bundle/vuln_variant/runtime_manifest.json`

Key excerpt from the vulnerable `./telegram` response (first line):

```
event: message\r\n
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"search_messages_globally", ...
```

This demonstrates that the protected `tools/list` endpoint returned successfully using the `./telegram` alias.

The fixed server log confirms the same alias now returns HTTP 401 (token rejected by the whitelist before any file existence check).

Environment details captured in the logs: Python 3.14, uvicorn, fastmcp-slim 3.4.2, fast-mcp-telegram 0.19.0 / 0.19.1, session directory `bundle/vuln_variant/fakehome/.config/fast-mcp-telegram`.

## Recommendations / Next Steps

- **Upgrade** to `fast-mcp-telegram >= 0.19.1`; the whitelist and containment check close this variant as well as the original traversal.
- **Regression tests:** add test cases for relative-path aliases (`./telegram`, `telegram/../telegram`, `../fast-mcp-telegram/telegram`) and confirm they are rejected before any file existence check.
- **Network-level mitigation:** restrict access to the MCP HTTP port to trusted clients until patched.
- **Detection:** monitor authentication logs for tokens containing path separators or unusual patterns.
- **Hardening:** ensure the session directory is not writable by the server process except through the intended setup flows, and avoid placing other sensitive files in the same directory tree.

## Additional Notes

- The script was run twice consecutively; both runs produced the same status sequence (401, 200, 200, 401, 401 on vulnerable; 401, 401, 401 on fixed), confirming idempotency.
- The GitHub source repository was not directly reachable in this environment, so the reproduction relies on the official PyPI wheels. The relevant source code is visible in the installed site-packages and confirms the vulnerable `Path` concatenation in 0.19.0 and the new `session_token_validation.py` containment check in 0.19.1.
- No real Telegram credentials or network connectivity to Telegram are required for the reproduction; the bypass is demonstrated purely against the local authentication layer.
- The URL-token entry point (`/v1/url_auth/...`) does not provide a practical variant for `./telegram` because Starlette/uvicorn normalize the `/./` path segment before the vulnerable middleware can extract the alias. The URL-token path is documented in the reproduction script to show that the alternate input form was considered.
- The variant is an **alternate trigger**, not a **fix bypass**: `./telegram` succeeds on `0.19.0` but is rejected by the `0.19.1` whitelist.
