Back to skill

Security audit

Tiandao Player

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its online game purpose, but it includes an optional unauthenticated network server mode that can expose a user's Tiandao token-backed actions to anyone who can reach it.

Install only if you are comfortable connecting your agent and TAP token to tiandao.co. Prefer the default stdio mode, do not run `--transport sse` on an untrusted network, keep TAP_TOKEN scoped and revocable, avoid custom WORLD_ENGINE_URL values unless you control and trust the endpoint, and treat game whispers as untrusted user-provided content.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/tiandao_mcp_server.py:465
Finding
Unauthenticated SSE Service Exposes Token-Backed MCP Operations## Vulnerability Details **File Location**: `scripts/tiandao_mcp_server.py:465-486` **Vulnerability Type**: Missing authentication and unsafe network exposure **Risk Level**: High ### Vulnerable Code ```python 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), ] ) uvicorn.run(starlette_app, host="0.0.0.0", port=args.port) ``` The token selection logic also falls back to the default bearer token for any supplied agent identifier: ```python def _get_token(agent_id: str = "default") -> str | None: return _token_store.get(agent_id) or _token_store.get("default") ``` ### Technical Analysis SSE mode binds the MCP service to `0.0.0.0`, making it reachable through every available network interface. Neither the `/sse` endpoint nor the `/messages/` endpoint performs client authentication or authorization before establishing an MCP session. MCP clients connected through this interface can invoke all registered tools, including perception, whisper, combat, trading, item transfer, and other state-changing actions. These operations are forwarded to the world engine with the bearer token held by the server. The default-token fallback compounds the problem. An arbitrary `agent_id` supplied by a caller does not create an authorization boundary because `_get_token()` uses the default token whenever no token exists for the requested identifier. ### Attack Path 1. A user starts the application with `--transport sse`. 2. The application listens on all interfaces, normally on TCP port 8765. 3. An at ...[truncated 1039 chars]
Remediation
## Remediation Suggestions 1. Bind SSE mode to `127.0.0.1` by default and require an explicit option before listening on external interfaces. 2. Require strong client authentication for both `/sse` and `/messages/`, such as a separate high-entropy service credential or mutually authenticated TLS. 3. Authorize each MCP caller for the specific agent identity and operation being requested. 4. Remove the default-token fallback for caller-supplied agent identifiers. Return an authorization error when an exact token mapping is unavailable. 5. Add origin and host validation where browser-accessible transports may be used. 6. Place remote deployments behind TLS, firewall restrictions, and a trusted authenticated reverse proxy. 7. Clearly document that SSE mode exposes token-backed operations and must not be placed directly on an untrusted network. 8. Add automated tests confirming that unauthenticated clients cannot initialize sessions or submit MCP messages.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tiandao_mcp_server.py:44
Finding
Configurable World Engine URL Can Exfiltrate the Bearer Token## Vulnerability Details **File Location**: `scripts/tiandao_mcp_server.py:44-79` **Vulnerability Type**: Unvalidated credential destination and optional plaintext transport **Risk Level**: Medium ### Vulnerable Code ```python WORLD_ENGINE_URL = os.getenv("WORLD_ENGINE_URL", "https://tiandao.co").rstrip("/") _token_store: dict = {} if env_token := os.getenv("TAP_TOKEN"): _token_store["default"] = env_token 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 h async def _post(path: str, body: dict, agent_id: str = "default") -> dict: async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.post( f"{WORLD_ENGINE_URL}{path}", headers=_auth_headers(agent_id), content=json.dumps(body, ensure_ascii=False).encode("utf-8"), ) resp.raise_for_status() return resp.json() async def _get(path: str, agent_id: str = "default") -> dict: async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get( f"{WORLD_ENGINE_URL}{path}", headers=_auth_headers(agent_id), ) resp.raise_for_status() return resp.json() ``` ### Technical Analysis `WORLD_ENGINE_URL` is accepted directly from the environment without validating its scheme, host, port, or other URL components. Both `_post()` and `_get()` attach the TAP bearer token to requests sent to that configured destination. Consequently, an accidental configuration error or an attacker who can influence the process environment can redirect authenticated requests to an unrelated server. The code also permits an `http://` URL, which transmits the bearer token without transport encryption and exposes it to interception or modification by an o ...[truncated 1506 chars]
Remediation
## Remediation Suggestions 1. Parse `WORLD_ENGINE_URL` with a standard URL parser before creating requests. 2. Require the `https` scheme and reject plaintext HTTP. 3. Allowlist `tiandao.co` and its explicitly approved API hostnames by default. 4. If custom deployments are necessary, require a deliberate opt-in flag and display a clear warning that the custom host will receive the TAP token. 5. Reject URLs containing embedded credentials, fragments, unexpected paths, or unapproved ports. 6. Consider separating the official service configuration from custom endpoint support so production credentials cannot be silently sent to development servers. 7. Redact bearer tokens from errors, diagnostics, and logs. 8. Add tests confirming that HTTP URLs and unapproved hosts are rejected before any authenticated request is made.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:8
Finding
Unpinned Third-Party Dependencies Create Supply-Chain Exposure## Vulnerability Details **File Location**: `SKILL.md:8` **Vulnerability Type**: Unpinned dependency installation **Risk Level**: Medium ### Vulnerable Code ```yaml metadata: openclaw: install: "pip install httpx mcp" ``` The same installation pattern is repeated in the documentation: ```bash pip install httpx mcp ``` ### Technical Analysis The installation instructions retrieve the latest versions of `httpx` and `mcp` without version constraints or integrity hashes. The exact code installed therefore changes over time even when the audited Skill package remains unchanged. Python package installation may execute package build or installation logic, and imported dependencies execute with the privileges of the process running the MCP server. A compromised package release, compromised package index, or malicious dependency introduced into the transitive dependency graph could therefore execute code during installation or runtime. This also makes deployments non-reproducible and prevents the audited source from establishing which dependency versions users will execute. ### Attack Path 1. A dependency publisher account, package release process, package index, or transitive dependency is compromised. 2. A malicious or vulnerable package version becomes the version selected by an unconstrained `pip install`. 3. A user follows the documented installation command or the Skill installer executes it. 4. The affected package is installed and may execute installation-time code. 5. The MCP server subsequently imports the package, allowing runtime payload execution with the server process's permissions. ### Impact Assessment A compromised dependency could execute arbitrary code with the privileges of the installing user or MCP server process. This may expose the TAP token, local files accessible to the process, MCP communications, and network credentials. The finding does not establish that the currently av ...[truncated 158 chars]
Remediation
## Remediation Suggestions 1. Pin every direct dependency to a reviewed version. 2. Generate and commit a lock file that includes resolved transitive dependencies. 3. Use hash-verified installation, such as a requirements file with `--require-hashes`. 4. Install packages only from a trusted, explicitly configured package index. 5. Regularly scan locked dependencies for published vulnerabilities. 6. Review dependency updates before changing pins rather than automatically selecting the latest release. 7. Run installation and the MCP server in a least-privileged virtual environment or isolated container.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Lp1

High
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The code performs outbound network requests to WORLD_ENGINE_URL and can also expose an SSE server reachable over the network, yet the finding says network capability is not declared. This is dangerous because an installer may believe the skill is local-only while it actually transmits agent inputs, world state, and authenticated actions to a remote service.

Lp1

High
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The code performs outbound network requests to WORLD_ENGINE_URL and can also expose an SSE server reachable over the network, yet the finding says network capability is not declared. This is dangerous because an installer may believe the skill is local-only while it actually transmits agent inputs, world state, and authenticated actions to a remote service.

External Transmission

Medium
Category
Data Exfiltration
Content
required: false
    requires:
      bins:
        - curl
        - python3
      pip:
        - httpx
Confidence
88% confidence
Finding
The skill is designed to send agent inputs, actions, and authentication material to an external service over the network using curl/httpx/MCP tooling. External transmission is expected for this integration, but it still creates a real data exposure boundary because prompts, behavioral outputs, tokens, and persistent gameplay metadata leave the local trust boundary and are processed by a remote server.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly instructs the agent to transmit a bearer token and retrieve account-linked cultivator data from a third-party remote service, but it does not provide an explicit privacy, retention, or data-sharing warning. This can cause users or operators to expose authentication credentials and persistent profile/session data to an external system without informed consent or clear understanding of how that data is handled.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill repeatedly presents action content, response fields, and recommended system prompts in Chinese, culminating in prompt templates that instruct the agent entirely in Chinese. The file does not explicitly state that Chinese is optional, user-selectable, or required for a documented region-specific reason, so it appears to impose a locale preference without opt-in.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The module docstring and all user-facing tool descriptions are written entirely in Chinese, and the API parsing logic is built around Chinese field names, indicating the skill is effectively constrained to a single language/locale. The file does not state that this is a region-specific tool or offer any user choice of language, which matches the policy category for language or locale constraints without opt-in.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest-level description says the skill is for register/perceive/act, but the implementation also exposes tiandao_whisper, a human-to-agent messaging channel. Hidden or under-disclosed messaging surfaces are risky because they create an unexpected prompt-injection and social-engineering path into the agent beyond the advertised scope.

Description-Behavior Mismatch

Low
Confidence
88% confidence
Finding
The manifest says the skill can "Register, perceive, and act via TAP protocol," but this server only implements perception, action, and whisper endpoints. The module docstring explicitly tells users to register externally through the portal and only consumes an existing `TAP_TOKEN`, showing registration is not actually implemented here.

Static analysis

No suspicious patterns detected.