T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/tiandao_mcp_server.py:54- Finding
Unauthenticated Network Exposure of Privileged MCP Tools
- Content
View full analysis
Vulnerability Details
File Location:
scripts/tiandao_mcp_server.py, lines 54–69 and 461–478
Vulnerability Type: Missing authentication and authorization on a network-accessible MCP service
Risk Level: HighVulnerable Code
python _token_store: dict = {} if env_token := os.getenv("TAP_TOKEN"): _token_store["default"] = env_tokenpython def _get_token(agent_id: str = "default") -> str | None: return _token_store.get(agent_id) or _token_store.get("default") def _auth_headers(agent_id: str = "default") -> dict: h = {"Content-Type": "application/json; charset=utf-8"} tok = _get_token(agent_id) if tok: h["Authorization"] = f"Bearer {tok}" return hpython sse_transport = SseServerTransport("/messages/") async def handle_sse(request): async with sse_transport.connect_sse( request.scope, request.receive, request._send ) as streams: await server.run( streams[0], streams[1], server.create_initialization_options() ) starlette_app = Starlette( routes=[ Route("/sse", endpoint=handle_sse), Mount("/messages/", app=sse_transport.handle_post_message), ] ) print(f"Tiandao MCP Server started in SSE mode at http://0.0.0.0:{args.port}/sse") uvicorn.run(starlette_app, host="0.0.0.0", port=args.port)Technical Analysis
When the documented
--transport ssemode is selected, the MCP service binds to all network interfaces through0.0.0.0. The/sseand/messages/routes do not enforce client authentication or authorization before creating an MCP session and accepting tool requests.The server stores the operator's
TAP_TOKENunder thedefaultkey. Token lookup accepts a caller-providedagent_id, but an unknown identifier automatically falls back to this default credential:python return _token_store.get(agent_id) or _token_store.get("def ...[truncated 2329 chars]- Remediation
View remediation
Remediation Suggestions
-
Bind SSE mode to loopback by default:
python uvicorn.run(starlette_app, host="127.0.0.1", port=args.port)Require an explicit, security-conscious option before listening on non-loopback interfaces.
-
Enforce authentication before accepting
/sseconnections or/messages/submissions. Use a strong, independently generated service credential rather than reusingTAP_TOKENas the client-facing secret. -
Protect remote deployments with TLS. Prefer a trusted reverse proxy that provides HTTPS, client authentication, request limits, and network access controls.
-
Bind each authenticated MCP session to a specific authorized Tiandao identity. Do not allow the caller to select arbitrary
agent_idvalues independently of its session identity. -
Remove default-token fallback for unknown identifiers:
python def _get_token(agent_id: str) -> str | None: return _token_store.get(agent_id)Reject requests when no exact authorized mapping exists.
-
Apply per-tool authorization. Require stronger authorization or explicit confirmation for destructive or costly actions such as transfers, sales, item disposal, combat, donations, and treasury withdrawals.
-
Add rate limiting, connection limits, structured security logging, and monitoring for failed authentication and sensitive tool invocations.
-
Document that SSE mode must not be exposed directly to untrusted networks without authentication and encrypted transport.
-
