Skip to content

v3.16.3 β€” Security release (GHSA-c4hm-4h84-2cf3, ADR-166 MCP bridge RCE)

Choose a tag to compare

@ruvnet ruvnet released this 01 Jul 14:34

πŸ”’ Security release

Advisory: GHSA-c4hm-4h84-2cf3 β€” CVSS 9.8 critical
ADR: ADR-166: MCP Bridge Unauthenticated RCE β€” Coordinated Disclosure Remediation

What was vulnerable

The MCP bridge shipping in ruflo/docker-compose.yml exposed POST /mcp with no authentication. The docker-compose defaults bound the bridge and MongoDB to all interfaces. Combined, an unauthenticated network attacker could invoke tools/call β†’ terminal_execute inside the bridge container, obtain a shell, read every provider API key from the container env, spawn attacker-controlled swarms on the victim's keys, and persist a poisoned pattern into the AgentDB learning store that steers future AI outputs.

What's fixed in 3.16.3

  • MCP bridge binds 127.0.0.1 by default. Public bind requires MCP_AUTH_TOKEN or the process exits β‰ 0 at boot with a FATAL message.
  • Bearer auth middleware with timingSafeEqual constant-time compare.
  • Server-side executeTool gate for terminal_execute (opt-in via MCP_ENABLE_TERMINAL=true) β€” enforced identically on /mcp, /mcp/:group, and autopilot. This was the missing link that made the disclosed RCE chain reach shell.
  • docker-compose.yml: read_only bridge rootfs, MongoDB --auth on by default, MONGO_INITDB_ROOT_PASSWORD required to boot.
  • CORS allowlist wiring via MCP_CORS_ORIGIN.
  • Static + runtime regression locks (12/12 static, 12/12 runtime green) + CI workflow.

⚠️ Operators of any exposed instance MUST

  1. Firewall :3001 and :27017 immediately if you were running the previous default docker-compose on a public IP.
  2. Rotate OPENAI, GOOGLE, OPENROUTER, ANTHROPIC keys.
  3. Audit the AgentDB pattern store for injected agentdb_pattern-store entries and purge them. A patched redeploy alone does NOT undo the AI-supply-chain poisoning vector.
  4. Audit MongoDB for tampering.

Breaking change (correct one, for security)

docker-compose.yml now refuses to start without MONGO_INITDB_ROOT_PASSWORD. Generate one:

echo "MONGO_INITDB_ROOT_PASSWORD=$(openssl rand -base64 32)" >> .env

For the optional public-bind deployment pattern, additionally:

echo "MCP_BIND_HOST=0.0.0.0" >> .env
echo "MCP_AUTH_TOKEN=$(openssl rand -base64 32)" >> .env
docker compose -f docker-compose.yml -f docker-compose.public.yml up -d

Credit

Coordinated disclosure by an external security researcher (name to be published with the CVE) and Dragan Spiridonov (ADR-166 co-author). The end-to-end 8-step PoC drove the choice to bind loopback by default rather than paper over with token-only auth β€” thank you.

Verification

  • @claude-flow/cli@3.16.3 β€” npm view @claude-flow/cli@latest version β†’ 3.16.3
  • claude-flow@3.16.3 β€” npm view claude-flow@latest version β†’ 3.16.3
  • ruflo@3.16.3 β€” npm view ruflo@latest version β†’ 3.16.3
  • All three dist-tags (latest, alpha, v3alpha) point at 3.16.3

πŸ€– Generated with RuFlo