tenki-mcp gives an AI agent a capability: a disposable microVM it can create, run code in, and spend Tenki credits with. Treat the server — and the API key it holds — accordingly. This document is the threat model and the controls, mapped to the CSA MCP Server Top 10.
Please do not open a public issue for security reports. Open a private GitHub security advisory, or email hello@luxor.tech. We'll acknowledge within a few business days.
- The API key is a capability. In every mode the process authenticates to Tenki with one
TENKI_API_KEYand can create sandboxes, run arbitrary code, and spend credits. Anyone who can invoke the server can do those things. Scope the key if your Tenki plan allows it; never commit it (.envis gitignored). - Sandbox output is untrusted.
tenki_run_code/tenki_exec/tenki_read_filereturn output produced by untrusted, AI-generated code running in the sandbox. That output flows back to the calling model as a tool result — a classic indirect / output prompt-injection vector. The microVM is the isolation boundary; the model should treat tool results as data, not instructions. (MCP clients are responsible for not executing instructions found in tool output.) - The HTTP endpoint is a capability. In HTTP mode the
/mcpendpoint is equivalent to handing out the key — protect it (below).
Every tool is tagged with MCP annotations so clients can surface/gate danger:
readOnlyHint on inspection tools, destructiveHint on the 13 that delete/terminate/revoke, openWorldHint on all (they call an external API). Plus two env controls:
| Env | Effect |
|---|---|
TENKI_MCP_READONLY=1 |
Register only read-only tools — no create, run, spend, or delete. For inspection-only deployments. |
TENKI_MCP_DISABLED_TOOLS=a,b,c |
Skip the named tools (e.g. disable tenki_run_code where code execution isn't wanted). |
Grant the smallest set that the use case needs.
- stdio (default) has no network surface.
- HTTP (
TENKI_MCP_TRANSPORT=http) binds loopback-only by default, requires a bearer token to bind to a non-loopback host, has DNS-rebinding protection, and caps sessions + body size. For network exposure put it behind a TLS-terminating proxy. (Hardening details in the transport module,src/http.ts.)
- The key is read from env and sent only as an auth header — never logged, never in error responses.
TENKI_MCP_AUDIT=1logs each tool call's name + argument keys to stderr (never values, content, or the token) for an operator audit trail.
| # | Risk | tenki-mcp posture |
|---|---|---|
| MCP-01 | Prompt Injection | zod-validates every tool arg pre-network; sandbox output is untrusted (treat tool results as data) |
| MCP-02 | Confused Deputy | single shared key; HTTP endpoint requires its own bearer token; READONLY/denylist bound the blast radius; per-request auth is not yet implemented |
| MCP-03 | Tool Poisoning | tool descriptions are static and authored (no dynamic/remote descriptions); verify the package via its npm provenance attestation (published from GitHub Actions, linking each release to its source commit) + MCP-registry namespace ownership |
| MCP-04 | Credential/Token Exposure | key via env only; never logged/committed/echoed; audit logs keys not values |
| MCP-05 | Insecure Configuration | HTTP transport is loopback + token + DNS-rebinding-protected + DoS-capped by default |
| MCP-06 | Supply Chain | 2 direct runtime deps (@modelcontextprotocol/sdk, zod) — ~91 transitive, nearly all via the MCP SDK; lockfile committed; released only from CI with npm provenance, Actions pinned to commit SHAs |
| MCP-07 | Excessive Permissions | tool annotations + TENKI_MCP_READONLY + TENKI_MCP_DISABLED_TOOLS |
| MCP-08 | Data Exfiltration | microVM isolation; sandbox outbound networking is off unless allow_outbound is set; the server itself stores/forwards nothing |
| MCP-09 | Context Spoofing | tool results are raw API/sandbox output surfaced as data, not merged into instructions |
| MCP-10 | Insecure Communication | control plane is HTTPS; run the HTTP transport behind TLS for any non-loopback use |
tenki_run_code is cost-guarded (1 vCPU, 1 GB, 10-min cap, 5-min idle) and self-terminates. tenki_create_sandbox and other create tools spend real credits — bound them with your Tenki workspace limits, TENKI_MCP_READONLY/denylist, and TENKI_MCP_AUDIT for visibility.