# REPRO-2026-00218: fast-mcp-telegram <=0.19.0 allows bearer token path traversal to authenticate as the default telegram.session, bypassing reserved session name protections and enabling unauthorized access to Telegram MCP tools. ## Summary Status: published Severity: critical Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00218 CVE: CVE-2026-52830 ## Package Name: fast-mcp-telegram Ecosystem: pip Affected: <= 0.19.0 Fixed: 0.19.1 ## Root Cause # RCA Report: CVE-2026-52830 (fast-mcp-telegram path-traversal session bypass) ## Summary fast-mcp-telegram <= 0.19.0 uses the raw HTTP Bearer token as a file-name fragment when building a session-file path. It checks the token against a set of reserved names (e.g. `telegram`) but never rejects path separators or normalizes the result. A token such as `../fast-mcp-telegram/telegram` therefore resolves to the same reserved `telegram.session` file that the exact name check is meant to protect, while bypassing the name check. A remote HTTP client who knows the target session directory layout can authenticate as the default account and list or invoke the exposed Telegram MCP tools. ## Impact - **Package/component:** fast-mcp-telegram (PyPI), specifically `src.server_components.session_token_verifier.SessionFileTokenVerifier` and `src.server_components.auth_middleware.UrlTokenMiddleware`. - **Affected versions:** `<= 0.19.0`. - **Patched version:** `0.19.1`. - **Risk level:** High. A remote, unauthenticated attacker can bypass bearer-token authentication and gain access to the victim's Telegram MCP tools as the default session without any Telegram credentials. - **Consequences:** Unauthorized access to tools such as `get_messages`, `send_message`, `send_message_to_phone`, `invoke_mtproto`, etc., under the identity of the default `telegram` session. ## Impact Parity - **Disclosed/claimed maximum impact:** Authorization bypass via HTTP Bearer token path traversal (`api_remote` / `authz_bypass`). - **Reproduced impact from this run:** Real HTTP auth bypass on a running `fast-mcp-telegram` 0.19.0 instance. The reserved token `telegram` is rejected (HTTP 401), while the traversal alias `../fast-mcp-telegram/telegram` is accepted (HTTP 200) and returns the protected `tools/list` response. The patched 0.19.1 build rejects the same traversal token (HTTP 401). - **Parity:** `full` for the claimed auth-bypass surface; the reproduction exercises the actual remote HTTP API and reaches the authenticated MCP path. - **Not demonstrated:** We did not demonstrate actual Telegram message exfiltration or message sending, because no real Telegram session credentials are configured. However, the auth layer is clearly bypassed and the tool list is exposed, proving the claimed authorization bypass. ## Root Cause In `src/server_components/session_token_verifier.py` (0.19.0), `verify_token()` does: ```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 return AccessToken(token=token, ...) ``` The reserved-name check is exact and case-insensitive, but the token string is then inserted directly into the path with only a `.session` suffix. Because `pathlib.Path` does not normalize `..` in the operand, the token `../fast-mcp-telegram/telegram` yields: ``` /../fast-mcp-telegram/telegram.session ``` When `session_dir` is the default `~/.config/fast-mcp-telegram`, this resolves to `~/.config/fast-mcp-telegram/telegram.session`, the same default session file the exact-name check is trying to protect. The same vulnerable path construction is also present in `UrlTokenMiddleware`, which rewrites the URL token into the `Authorization` header. The 0.19.1 fix introduces `src/server_components/session_token_validation.py`. It validates the token against a strict `^[A-Za-z0-9_-]{43}$` pattern and uses `session_file_path()`, which resolves the constructed path and verifies it is still inside `session_dir` with `is_relative_to()`. Any traversal sequence or reserved name is rejected before the file existence check. ## Reproduction Steps Run the self-contained script: ```bash bash bundle/repro/reproduction_steps.sh ``` The script: 1. Reads `bundle/project_cache_context.json` and uses the provided `project_cache_dir` for persistent Python venvs. 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 three different bearer tokens on the vulnerable server: - `telegram` (reserved, expected 401) - `../fast-mcp-telegram/telegram` (traversal alias, expected 200) - `invalid-token` (no matching session file, expected 401) 6. Sends the same traversal token to the fixed server (expected 401). 7. Writes `bundle/repro/runtime_manifest.json` and exits 0 only when the expected statuses are observed. ### Expected evidence - `repro/artifacts/http_vuln_reserved.txt` and `http_vuln_noauth.txt`: HTTP 401 response body. - `repro/artifacts/http_vuln_traversal.txt`: HTTP 200 SSE event containing the full `tools/list` result. - `repro/artifacts/http_fixed_traversal.txt`: HTTP 401 response body from the patched version. - `logs/server_vuln.log` and `logs/server_fixed.log`: server startup logs showing mode `http-auth` and the session directory. ## Evidence Captured artifacts: - `bundle/repro/artifacts/http_vuln_traversal.txt` (HTTP 200, tools list returned) - `bundle/repro/artifacts/http_vuln_reserved.txt` (HTTP 401, reserved token rejected) - `bundle/repro/artifacts/http_vuln_noauth.txt` (HTTP 401, invalid token rejected) - `bundle/repro/artifacts/http_fixed_traversal.txt` (HTTP 401, traversal token rejected on 0.19.1) - `bundle/logs/server_vuln.log` - `bundle/logs/server_fixed.log` - `bundle/repro/runtime_manifest.json` - `bundle/logs/reproduction_steps.log` - `bundle/logs/reproduction_steps_run2.log` Key excerpt from the vulnerable traversal response (first line only for brevity): ``` 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 only the traversal token. The fixed server log confirms the same traversal token now returns HTTP 401: ``` {"error": "invalid_token", "error_description": "Authentication failed..."} ``` 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 `repro/fakehome/.config/fast-mcp-telegram`. ## Recommendations / Next Steps - **Upgrade** to `fast-mcp-telegram >= 0.19.1`, which enforces a strict token format and resolves/session-directory containment checks. - **Network-level mitigation** until patched: restrict access to the MCP HTTP port so only trusted clients can reach it. - **Detection:** monitor authentication logs for tokens containing path separators or unusual patterns. - **Testing recommendation:** add regression tests that attempt tokens such as `../session`, `..\\session`, `telegram`, and `/etc/passwd` and assert they are rejected before any file existence check. ## Additional Notes - The script was run twice consecutively from a clean project-cache state; both runs exited 0 and produced the same status sequence (401, 200, 401 on vulnerable; 401 on fixed), confirming idempotency. - The GitHub source repository for fast-mcp-telegram 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. ## Reproduction Details Reproduced: 2026-07-03T15:53:44.941Z Duration: 1071 seconds Tool calls: 186 Turns: Unknown Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00218 pruva-verify CVE-2026-52830 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00218&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00218/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-52830 - Source: https://nvd.nist.gov/vuln/detail/CVE-2026-52830 ## Artifacts - bundle/repro/reproduction_steps.sh (reproduction_script, 7369 bytes) - bundle/repro/rca_report.md (analysis, 7790 bytes) - bundle/vuln_variant/reproduction_steps.sh (reproduction_script, 9204 bytes) - bundle/vuln_variant/rca_report.md (analysis, 11252 bytes) - bundle/ticket.md (ticket, 3145 bytes) - bundle/ticket.json (other, 4316 bytes) - bundle/repro/artifacts/http_vuln_reserved.txt (other, 301 bytes) - bundle/repro/artifacts/http_vuln_traversal.txt (other, 12901 bytes) - bundle/repro/artifacts/http_vuln_noauth.txt (other, 301 bytes) - bundle/repro/artifacts/http_fixed_traversal.txt (other, 301 bytes) - bundle/repro/fakehome/.config/fast-mcp-telegram/telegram.session (other, 0 bytes) - bundle/repro/runtime_manifest.json (other, 712 bytes) - bundle/repro/validation_verdict.json (other, 730 bytes) - bundle/logs/pip_0.19.0.log (log, 60325 bytes) - bundle/logs/pip_0.19.1.log (log, 57789 bytes) - bundle/logs/server_vuln.log (log, 1848 bytes) - bundle/logs/server_fixed.log (log, 1728 bytes) - bundle/logs/reproduction_steps.log (log, 50304 bytes) - bundle/logs/reproduction_steps_run2.log (log, 50304 bytes) - bundle/logs/variant_reproduction_steps_run1.log (log, 13489 bytes) - bundle/logs/server_vuln_variant.log (log, 2135 bytes) - bundle/logs/server_fixed_variant.log (log, 2327 bytes) - bundle/logs/variant_reproduction_steps_run2.log (log, 13503 bytes) - bundle/vuln_variant/fakehome/.config/fast-mcp-telegram/telegram.session (other, 0 bytes) - bundle/vuln_variant/artifacts/http_vuln_reserved.txt (other, 301 bytes) - bundle/vuln_variant/artifacts/http_vuln_dot_slash.txt (other, 12901 bytes) - bundle/vuln_variant/artifacts/http_vuln_original.txt (other, 12901 bytes) - bundle/vuln_variant/artifacts/http_vuln_invalid.txt (other, 301 bytes) - bundle/vuln_variant/artifacts/http_vuln_url_dot_slash.txt (other, 74 bytes) - bundle/vuln_variant/artifacts/http_fixed_dot_slash.txt (other, 301 bytes) - bundle/vuln_variant/artifacts/http_fixed_original.txt (other, 301 bytes) - bundle/vuln_variant/artifacts/http_fixed_url_dot_slash.txt (other, 74 bytes) - bundle/vuln_variant/runtime_manifest.json (other, 1106 bytes) - bundle/vuln_variant/patch_analysis.md (documentation, 5576 bytes) - bundle/vuln_variant/variant_manifest.json (other, 3280 bytes) - bundle/vuln_variant/validation_verdict.json (other, 1094 bytes) - bundle/vuln_variant/source_identity.json (other, 819 bytes) - bundle/vuln_variant/root_cause_equivalence.json (other, 1488 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00218 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00218/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00218 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev