← Back to Feed CACHED · 2026-10-07 04:50:03 · CACHE_KEY CVE-2026-59726
CVE-2026-59726 · CWE-78 · Disclosed 2026-07-09

Ruflo MCP Bridge Unauthenticated RCE and AI Memory Poisoning (RufRoot)

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Leaving your AI agent's brain surgery tools on an unlocked table in the hospital lobby

CVE-2026-59726, codenamed RufRoot by Noma Labs, is an unauthenticated remote code execution flaw in Ruflo, an open-source AI agent orchestration platform (~66,500 GitHub stars, ~700K lifetime npm downloads) that coordinates Claude Code and OpenAI Codex agent swarms. All versions prior to 3.16.3 ship a docker-compose.yml that binds an Express.js MCP bridge on port 3001 to 0.0.0.0 — every network interface — with zero authentication on the POST /mcp and POST /mcp/:group endpoints. This exposes 233 tools including ruflo__terminal_execute, which runs arbitrary shell commands inside the bridge container. A single curl POST is the entire exploit. The attacker gains shell access as node (UID 1000), can steal LLM provider API keys from environment variables, dump all conversations from the unauthenticated MongoDB sidecar, poison the AgentDB learning store to corrupt future AI outputs for all users, and establish persistence via index.js injection that survives docker restart.

The vendor CVSS of 10.0 is technically correct for the vulnerability mechanics — unauthenticated, network-accessible, zero-complexity, scope-changing RCE. But it overstates real-world risk for most deployments. Ruflo is a developer-oriented tool, not core enterprise infrastructure. The vast majority of instances run on developer laptops behind NAT, in ephemeral test environments, or in cloud VPCs protected by security groups. No Shodan or Censys data was found showing mass internet exposure. The EPSS score of 3.019% (~95th percentile, but still low absolute probability) and the absence of KEV listing or confirmed in-the-wild exploitation campaigns corroborate that real-world exploitation pressure is moderate, not maximum. However, for the subset of deployments in CI/CD pipelines, shared team environments, or misconfigured cloud VMs, the vulnerability is devastating — the API key theft alone extends blast radius well beyond the container, and the memory poisoning creates a supply-chain-grade integrity compromise. The vendor's CRITICAL is the right call for internet-exposed instances; for the typical deployment behind a firewall, HIGH is the honest assessment.

"Trivial unauth RCE, but most Ruflo instances sit behind NAT — still HIGH for CI/CD and shared deployments."
02 · The Attack Path

6 steps from start to impact.

STEP 01

Network reachability to MCP bridge

The attacker must reach TCP/3001 on the Ruflo host. The default docker-compose.yml binds to 0.0.0.0:3001, so any host on the same network segment — or the entire internet if firewall rules are absent — can connect. No authentication header, API key, or IP allowlist is enforced.
Conditions required:
  • Network path to target host on TCP/3001
  • Ruflo version < 3.16.3 running default docker-compose config
Where this breaks in practice:
  • Most developer workstations sit behind NAT/home routers that block inbound connections
  • Enterprise firewalls typically do not permit inbound traffic to ephemeral developer ports
  • Cloud security groups default-deny inbound on non-standard ports in AWS, GCP, Azure
Detection/coverage: Nuclei template CVE-2026-59726 (PR #17249 in projectdiscovery/nuclei-templates) can scan for exposed /mcp endpoints. Port scan for TCP/3001 across your estate.
STEP 02

Tool enumeration via tools/list

The attacker sends a JSON-RPC request {"method":"tools/list"} to POST /mcp. The bridge returns all 233 registered tools with their schemas, confirming the instance is vulnerable and revealing the full attack surface. No credentials are required. This step doubles as a fingerprint for the target.
Conditions required:
  • Step 1 completed — network reachability confirmed
Where this breaks in practice:
  • None once Step 1 is achieved — the endpoint is completely open
Detection/coverage: WAF or reverse proxy logging on /mcp path. Sigma rule 550d9a23-0f72-4e3a-a8c5-1d2f3b4c5d6e detects suspicious child processes.
STEP 03

Remote code execution via terminal_execute

The attacker sends {"method":"tools/call","params":{"name":"ruflo__terminal_execute","arguments":{"command":"id && hostname"}}} to POST /mcp. The bridge executes the command as the node user (UID 1000) inside the Docker container and returns stdout. The AUTOPILOT_BLOCKED_PATTERNS blocklist only applies within the autopilot flow and does NOT gate the /mcp endpoint. Exploitation is 100% reliable — no race conditions, memory corruption, or payload tuning required.
Conditions required:
  • Step 2 completed — target confirmed as vulnerable Ruflo instance
Where this breaks in practice:
  • Execution is container-scoped (node user, not host root) — limits immediate host-level damage unless container escape is chained
Detection/coverage: Monitor for node process spawning bash, sh, nc, python, or perl child processes. Sigma rule 7a3f1c82-9e4b-4d67-bc12-3e5a8f901234.
STEP 04

LLM API key theft from environment variables

The attacker runs env or printenv via terminal_execute to harvest LLM provider API keys (Anthropic, OpenAI, etc.) passed as environment variables to the container. These keys typically have broad permissions and no IP restrictions. With stolen keys the attacker can run arbitrary LLM workloads at the victim's expense, exfiltrate training data via API, or pivot to other services authenticated by the same credentials.
Conditions required:
  • Step 3 completed — shell access achieved
Where this breaks in practice:
  • Some organizations use secret managers that inject short-lived tokens rather than static API keys, limiting the window of abuse
Detection/coverage: Anomalous API usage patterns on LLM provider dashboards (unexpected regions, IP addresses, or usage spikes).
STEP 05

AgentDB memory poisoning

Using ruflo__agentdb_pattern-store, the attacker injects malicious patterns into the learning store. These patterns alter future AI agent outputs for all users of the instance — a persistent integrity compromise. Poisoned patterns survive container restarts because AgentDB is backed by MongoDB volumes. This is the supply-chain dimension of the vulnerability: downstream consumers of the AI agent's outputs receive attacker-influenced results.
Conditions required:
  • Step 3 completed — can invoke any of the 233 tools
Where this breaks in practice:
  • Impact is limited to users of this specific Ruflo instance, not a global supply-chain compromise
  • Requires the instance to be actively used by multiple consumers for the poisoning to have meaningful blast radius
Detection/coverage: Audit AgentDB pattern-store entries for unexpected or recently-modified patterns. Compare against known-good baseline.
STEP 06

Persistence via index.js backdoor

The attacker writes a beacon script to /app/beacon.js and injects a require('./beacon') line into /app/index.js. Because Docker restart policies re-execute the entrypoint, the backdoor persists across container restarts. The beacon can establish a reverse shell, exfiltrate data periodically, or serve as a staging point for lateral movement within the Docker network.
Conditions required:
  • Step 3 completed — write access to /app directory inside the container
Where this breaks in practice:
  • The fix in 3.16.3 makes the container filesystem read-only with tmpfs, eliminating this persistence vector
  • Container rebuilds from clean images destroy the backdoor
Detection/coverage: File integrity monitoring on /app/ directory inside the container. Monitor for unexpected outbound connections from the container.
03 · Compensating Control

1
HIGH 8.0→IGNORE 0.0
SEVERITY REDUCED
Firewall-block TCP/3001 and TCP/27017 at the host and network level — The entire attack chain requires network reachability to port 3001. Blocking this port at the host firewall (iptables/ufw/Windows Firewall) and any upstream network firewall eliminates the attack surface completely. Deploy within the noisgate mitigation SLA of 30 days for HIGH severity. For cloud deployments, audit security groups immediately.
2
HIGH 8.0→IGNORE 0.0
SEVERITY REDUCED
Upgrade Ruflo to ≥ 3.16.3 — The patch binds the MCP bridge to loopback by default, adds bearer token authentication, disables terminal_execute unless explicitly opted in, enables MongoDB authentication, and sets the container filesystem read-only. This is the definitive fix. Deploy within the noisgate remediation SLA of 180 days for HIGH severity.
3
HIGH 8.0→MEDIUM 5.5
SEVERITY REDUCED
Rotate all LLM provider API keys on affected instances — If any instance ran a vulnerable version with network exposure, treat API keys as compromised. Rotate Anthropic, OpenAI, and any other provider credentials immediately. Check provider dashboards for anomalous usage (unexpected regions, IP addresses, usage spikes). Do this within 48 hours of identifying an exposed instance.
4
HIGH 8.0→LOW 3.0
SEVERITY REDUCED
Audit AgentDB pattern store and rebuild containers from clean images — Inspect the agentdb_pattern-store collection in MongoDB for unexpected or recently-modified entries. Compare against a known-good baseline. If any suspicious patterns are found, wipe the learning store and rebuild all containers from a clean image rather than restarting existing ones. Check /app/index.js for injected require() statements.
5
HIGH 8.0→LOW 2.0
SEVERITY REDUCED
Deploy reverse proxy with authentication in front of MCP bridge — If remote access to the MCP bridge is operationally required, place it behind a reverse proxy (nginx, Caddy, Traefik) with mTLS or OAuth2 authentication. Never expose port 3001 directly. This provides defense-in-depth even after patching.
What doesn't work
  • Container network isolation alone — the default docker-compose creates a bridge network, but the 0.0.0.0 binding on the host bypasses container network isolation entirely. The host port mapping is the problem, not the container networking.
  • AUTOPILOT_BLOCKED_PATTERNS blocklist — this only applies within Ruflo's autopilot flow and does NOT gate the /mcp endpoint. Do not rely on it as a security control.
  • WAF rules on the MCP endpoint — generic WAFs will not inspect JSON-RPC payloads for tool invocation patterns. A custom rule matching ruflo__terminal_execute in the request body could help but is brittle and bypass-prone.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo confirmed in-the-wild exploitation. Not listed in CISA KEV. No GreyNoise tags observed. Noma Labs verified an 8-stage PoC against a default AWS EC2 deployment, but no campaigns targeting production instances have been reported as of 2026-10-07.
Proof-of-concept availabilityPublic and trivial. The exploit is a single curl one-liner published in the Noma Labs advisory and The Hacker News. A Nuclei template (PR #17249 by DhiyaneshGeek) enables mass scanning. GitHub repo HORKimhab/CVE-2026-59726 contains additional analysis.
EPSS score0.03019 (3.019%) — approximately 95th percentile. Indicates moderate but not extreme predicted exploitation probability over the next 30 days.
CISA KEV statusNot listed as of 2026-10-07.
CVSS vector interpretationCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H = 10.0. Network-accessible, zero complexity, no privileges, no user interaction, scope change (container → host environment via credential theft), full CIA impact. The vector is technically accurate for the worst-case deployment.
Affected versionsAll Ruflo versions < 3.16.3 (npm packages: ruflo, claude-flow, @claude-flow/cli). Includes v3.5.x through v3.16.2 and all pre-release tags.
Fixed version3.16.3 — released 2026-07-01, within 24 hours of responsible disclosure. Fix commits: d00a0a40cd8b and 4eb807aa7cfc (PR #2521). Binds bridge to loopback, adds bearer auth middleware, disables terminal_execute by default, enables MongoDB auth, sets container filesystem read-only.
Scanning / exposure dataNo Shodan or Censys data found documenting internet-exposed Ruflo instances. The default 0.0.0.0 binding creates exposure on local networks and misconfigured cloud VMs, but no mass internet scanning results have been published.
Disclosure timeline2026-06-30: Noma Labs responsible disclosure to maintainer Reuven Cohen. 2026-07-01: Patch released (v3.16.3). 2026-07-09: CVE published. 2026-07-29: Full public disclosure by Noma Labs.
Reporting researcherEli Ainhorn, Noma Labs (Noma Security). Codenamed the vulnerability RufRoot.

Sources.

  1. Noma Labs advisory (RufRoot)
  2. The Hacker News coverage
  3. OSV vulnerability record
  4. GitHub Security Advisory (GHSA-c4hm-4h84-2cf3)
  5. Nuclei template PR #17249
  6. SecurityArsenal detection guide
  7. GBHackers technical analysis
  8. Ruflo GitHub repository
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (8.0/10)

Why this verdict

  • Network reachability is the gating friction: The default 0.0.0.0 binding is dangerous, but most Ruflo instances run on developer laptops behind NAT, in ephemeral containers, or in cloud VPCs with security groups that default-deny inbound on port 3001. Without Shodan/Censys evidence of mass internet exposure, the effective attack surface is dramatically smaller than the CVSS vector implies.
  • Container-scoped compromise limits host-level blast radius: Initial execution is as node (UID 1000) inside a Docker container — not root on the host. Host compromise requires a container escape chain not included in this CVE. The real damage extends beyond the container via stolen API keys and memory poisoning, but those are secondary impacts, not direct host takeover.
  • EPSS and KEV corroborate moderate real-world risk: EPSS of 3.019% is elevated but not extreme. No KEV listing. No confirmed in-the-wild exploitation campaigns. The vulnerability has been public for 3 months without mass exploitation materializing, suggesting the reachable population is small.
  • Niche developer tool, not enterprise infrastructure: Ruflo has ~66,500 GitHub stars but only ~23,000 weekly npm downloads. It is not a domain controller, hypervisor, identity provider, or network edge appliance. The installed base is primarily individual developers and small teams experimenting with AI agents.
  • Role multiplier: (a) *Low-value role (developer workstation/sandbox)* — estimated ≥80% of installs. Chain succeeds if port 3001 is reachable on LAN; blast radius is single-developer credential theft and local AI poisoning. (b) *Typical role (team-shared AI agent server)* — estimated ~15% of installs. Chain succeeds if accessible on internal network; blast radius is team-wide API key compromise and shared AI memory corruption. (c) *High-value role (CI/CD-adjacent deployment orchestrating autonomous coding agents)* — estimated ~5% of installs. Chain succeeds and blast radius includes supply-chain integrity compromise (poisoned code generation patterns, stolen CI credentials). This ≥1% high-value-role threshold floors the verdict at HIGH. However, Ruflo is NOT canonically a CI/CD server (it's an orchestration layer on top), so the floor does not rise to CRITICAL.

Why not higher?

The vendor's CRITICAL 10.0 assumes direct internet exposure with full blast radius. In practice, the vast majority of Ruflo deployments are behind NAT or cloud security groups, making the network reachability prerequisite the dominant friction point. Without confirmed mass internet exposure or in-the-wild exploitation, elevating to CRITICAL would overstate the urgency for most enterprises and misallocate patching resources away from genuinely internet-facing CRITICAL vulnerabilities.

Why not lower?

Despite limited exposure, the exploit is a trivial one-liner curl command with a public Nuclei template for mass scanning. If an instance IS reachable — on a misconfigured cloud VM, a shared development server, or an internal network after initial compromise — exploitation is 100% reliable with zero authentication required. The API key theft and AI memory poisoning extend blast radius beyond the container, and the CI/CD deployment scenario creates a legitimate supply-chain risk that floors this at HIGH.

06 · Verification

Crowdsourced verification payload.

Run this script on each host where Ruflo may be deployed (developer workstations, CI/CD runners, Docker hosts). Execute as any user with access to docker commands. Example: chmod +x check_rufroot.sh && ./check_rufroot.sh

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-59726 (RufRoot) Verification Script
# Checks for vulnerable Ruflo MCP bridge instances
# Exit codes: 0 = PATCHED/not present, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

VULNERABLE=0
UNKNOWN=0

# Check 1: Is port 3001 listening on 0.0.0.0?
echo "[*] Checking for MCP bridge listening on 0.0.0.0:3001..."
if ss -tlnp 2>/dev/null | grep -q '0.0.0.0:3001'; then
  echo "[!] FOUND: Port 3001 bound to 0.0.0.0 (all interfaces)"
  VULNERABLE=1
elif ss -tlnp 2>/dev/null | grep -q ':3001'; then
  echo "[i] Port 3001 is listening but bound to loopback only (likely patched)"
else
  echo "[i] Port 3001 is not listening"
fi

# Check 2: Probe the /mcp endpoint for unauthenticated access
if command -v curl &>/dev/null; then
  echo "[*] Probing localhost:3001/mcp for unauthenticated tool listing..."
  RESP=$(curl -s -m 5 -X POST http://127.0.0.1:3001/mcp \
    -H 'Content-Type: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' 2>/dev/null || true)
  if echo "$RESP" | grep -q 'ruflo__terminal_execute'; then
    echo "[!] VULNERABLE: MCP bridge returned terminal_execute tool without auth"
    VULNERABLE=1
  elif echo "$RESP" | grep -q '"error"'; then
    echo "[i] MCP bridge returned error (likely patched or auth-gated)"
  elif [ -z "$RESP" ]; then
    echo "[i] No response from MCP bridge (not running or filtered)"
  fi
fi

# Check 3: Check installed ruflo/claude-flow version via npm
for PKG in ruflo claude-flow @claude-flow/cli; do
  if command -v npm &>/dev/null; then
    VER=$(npm list -g "$PKG" 2>/dev/null | grep "$PKG@" | head -1 | sed 's/.*@//' || true)
    if [ -n "$VER" ]; then
      echo "[*] Found $PKG@$VER installed globally"
      # Compare version - vulnerable if < 3.16.3
      MAJOR=$(echo "$VER" | cut -d. -f1)
      MINOR=$(echo "$VER" | cut -d. -f2)
      PATCH=$(echo "$VER" | cut -d. -f3 | cut -d- -f1)
      if [ "$MAJOR" -lt 3 ] 2>/dev/null || \
         ([ "$MAJOR" -eq 3 ] && [ "$MINOR" -lt 16 ] 2>/dev/null) || \
         ([ "$MAJOR" -eq 3 ] && [ "$MINOR" -eq 16 ] && [ "$PATCH" -lt 3 ] 2>/dev/null); then
        echo "[!] VULNERABLE: $PKG@$VER is below 3.16.3"
        VULNERABLE=1
      else
        echo "[i] PATCHED: $PKG@$VER is >= 3.16.3"
      fi
    fi
  fi
done

# Check 4: Check running Docker containers
if command -v docker &>/dev/null; then
  echo "[*] Checking running Docker containers for ruflo..."
  CONTAINERS=$(docker ps --format '{{.Names}} {{.Image}}' 2>/dev/null | grep -i ruflo || true)
  if [ -n "$CONTAINERS" ]; then
    echo "[!] Found ruflo containers running:"
    echo "$CONTAINERS"
    # Check if port 3001 is mapped to 0.0.0.0
    if docker ps --format '{{.Ports}}' 2>/dev/null | grep -q '0.0.0.0:3001'; then
      echo "[!] VULNERABLE: Container has 0.0.0.0:3001 port mapping"
      VULNERABLE=1
    fi
  else
    echo "[i] No ruflo containers found running"
  fi
fi

# Final verdict
echo ""
if [ "$VULNERABLE" -eq 1 ]; then
  echo "VULNERABLE — CVE-2026-59726 (RufRoot) exposure detected"
  exit 1
else
  echo "PATCHED — No CVE-2026-59726 exposure detected"
  exit 0
fi