- Published on
Validating Clawdbot Security with Shodan
- Authors

- Name
- Avasdream
- @avasdream_
Clawdbot is an AI agent framework that runs Claude as an autonomous assistant. It uses a WebSocket gateway for communication, typically on port 18789. I wanted to validate that instances in the wild are properly secured.
Finding Instances with Shodan
Clawdbot uses mDNS for local service discovery, broadcasting as _clawdbot-gw._tcp.local. Shodan indexes mDNS responses, so we can find instances with:
shodan search "clawdbot-gw"
I wrote a scraper to collect and parse the data:
def parse_mdns_txt(banner_text: str) -> Dict[str, Any]:
"""Parse mDNS TXT records from Shodan banner"""
data = {}
for match in re.finditer(r'(\w+)=([^\n]+)', banner_text):
key, value = match.groups()
data[key.lower()] = value.strip()
return data
def scrape_shodan():
api = shodan.Shodan(SHODAN_API_KEY)
instances = []
for result in api.search_cursor("clawdbot-gw"):
instance = {
"ip": result["ip_str"],
"port": result["port"],
"org": result.get("org"),
}
instance.update(parse_mdns_txt(result.get("data", "")))
instances.append(instance)
return instances
This found 200 instances, mostly on Hetzner (85%).
Testing WebSocket Authentication
Next, I probed each instance to verify authentication is required:
async def probe_websocket(ip: str, port: int) -> Dict[str, Any]:
"""Test if WebSocket requires authentication"""
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
for url in [f"wss://{ip}:{port}/gw", f"ws://{ip}:{port}/gw"]:
try:
async with websockets.connect(url, ssl=ssl_context, open_timeout=10) as ws:
msg = await asyncio.wait_for(ws.recv(), timeout=5)
if "connect.challenge" in msg:
return {"status": "auth_required"}
return {"status": "connected", "response": msg[:200]}
except:
continue
return {"status": "unreachable"}
Results
| Status | Count | Percentage |
|---|---|---|
| Unreachable | 192 | 96% |
| Auth Required | 8 | 4% |
| No Auth | 0 | 0% |
All instances are properly secured. 96% have the port firewalled, and the remaining 4% require authentication via challenge-response:
{"type":"event","event":"connect.challenge","payload":{"nonce":"..."}}
Self-Audit Script
I created a script to verify your own instance:
curl -sL https://gist.githubusercontent.com/AvasDream/020ca16d72226213aec94a3a7f2844e6/raw/self-audit.sh | bash
It checks gateway binding, external port access, mDNS status, authentication config, and file permissions:
╔══════════════════════════════════════════════════════════════╗
║ CLAWDBOT SECURITY SELF-AUDIT ║
╚══════════════════════════════════════════════════════════════╝
1️⃣ GATEWAY BINDING
✅ Gateway bound to localhost (127.0.0.1:18789)
2️⃣ EXTERNAL PORT ACCESS
✅ Port 18789 closed externally
3️⃣ mDNS
✅ Avahi not running
4️⃣ AUTHENTICATION
✅ Gateway token configured
5️⃣ FILE PERMISSIONS
✅ Config permissions: 600
SUMMARY: ✅ 5 passed | ⚠️ 0 warnings | ❌ 0 failed
Conclusion
The Clawdbot community has good security practices. Every instance tested either blocks external access or requires authentication. No unauthenticated instances were found.