Back to posts
Research Archive

Detecting OpenClaw Gateways with Nuclei over mDNS

Detecting OpenClaw, Clawdbot, and Moltbot gateway exposure by listening for mDNS service advertisements with a JavaScript-protocol Nuclei template.

openclawnucleiexposuremdnsudpdetectionai-security

OpenClaw is having its moment. The autonomous AI agent — you may know it as Clawdbot or Moltbot, depending on when you first ran into it — has rocketed up the GitHub charts over the past few weeks, and people are standing instances up everywhere. As of this past week it's also having its first real security moment: CVE-2026-25253 dropped, a 1-click RCE, with a patch landing only days ago. If you run these, or you're responsible for a network where someone might, now is the time to find out where they are.

Quick background

OpenClaw wires LLMs (Claude, GPT-4, Google's models) into your machine and into a real browser, and lets an agent get work done on your behalf — chatting over Telegram/Slack, driving web tasks, running commands. The component this template cares about is the gateway service, which advertises itself for local discovery via multicast DNS (mDNS) on port 5353/UDP.

A naming note, because the matchers depend on it: the project is OpenClaw now, but it shipped as Clawdbot and, earlier, Moltbot — same codebase, and the mDNS service names still carry the old branding (_clawdbot-gw, _openclaw-gw). The template matches on both so the rename doesn't blind it.

The template

id: openclaw-exposure
info:
  name: Openclaw (formerly Clawdbot / Moltbot) - Detect
  author: rxerium
  severity: info
  description: |
    Clawdbot Gateway service was detected exposing configuration information via mDNS including DNS settings, gateway details, and service configuration.
  classification:
    cwe-id: CWE-200
  metadata:
    verified: true
    max-request: 1
    shodan-query: product:openclaw
    fofa-query: body="ClawdBot"
  tags: network,openclaw,gateway,exposure,udp,mdns,js,discovery
javascript:
  - pre-condition: |
      isUDPPortOpen(Host,Port);
    code: |
      let c = require("nuclei/net");
      let conn = c.Open('udp', `${Host}:${Port}`);
      // mDNS query for _clawdbot-gw._tcp.local PTR record
      let packet = "000000000001000000000000095f7365727669636573075f646e732d7364045f756470056c6f63616c00000c0001"
      conn.SendHex(packet);
      let resp = conn.RecvString(2048);
      resp;
    args:
      Host: "{{Host}}"
      Port: 5353
    matchers:
      - type: dsl
        dsl:
          - "contains(response, '_openclaw-gw') && success == true"
          - "contains(response, 'clawdbot') && success == true"
        condition: or
    extractors:
      - type: regex
        part: response
        name: server
        group: 1
        regex:
          - 'displayName=([a-zA-Z0-9._-]+)'

How it works

It's a JavaScript-protocol template, not HTTP. Most exposure templates fire a GET and match the response body. This one uses Nuclei's nuclei/net library to open a raw socket and speak a binary protocol directly — necessary, because mDNS isn't something you can express with HTTP matchers.

The pre-condition gates the whole thing. isUDPPortOpen(Host, Port) checks that 5353/UDP is actually listening before any packet goes out. If it's closed, the template short-circuits and you don't spend a request — which keeps scans cheap when you point this at a large range where most hosts won't be running a gateway.

The code sends a raw mDNS query and reads the reply. It opens a UDP connection to Host:5353, sends a hex-encoded DNS packet with SendHex, and reads up to 2048 bytes back. The decoded payload is a DNS-SD service-enumeration query — a PTR question for _services._dns-sd._udp.local, the standard "list everything you advertise" meta-query. A host running the gateway answers with its advertised services, and the OpenClaw/Clawdbot service name comes back in that response.

The matchers confirm it's a gateway. Two DSL checks, or-combined: contains(response, '_openclaw-gw') or contains(response, 'clawdbot'), each gated on success == true so a half-open socket or empty read can't produce a false positive. Either string in the mDNS reply confirms you're looking at an OpenClaw gateway, whichever fork's branding it carries.

The extractor pulls the device's display name. A regex grabs displayName=... out of the advertisement and surfaces it as server in your output. So a hit isn't just "a gateway exists" — you get the human-readable name the operator gave it, which is gold for inventory and triage.

Severity is info, CWE-200. This is the honest classification: the template detects an information exposure (CWE-200, Information Exposure) — a gateway advertising its configuration where it shouldn't — not active exploitation. mDNS leaking onto a reachable interface is the finding; what an attacker does next is a separate problem.

verified: true means the template was confirmed against a real instance, not just written to spec — so a match is trustworthy.

Why mDNS detection is worth having

HTTP fingerprinting is the obvious way to find these, and it works. But mDNS catches a different slice. A gateway can be leaking service discovery onto a network segment an attacker can reach even when the HTTP side is firewalled, behind a proxy, or on a non-standard port your HTTP scan didn't cover. It's especially relevant for internal assessments and flat networks, where multicast happily crosses segments it shouldn't and the gateway is effectively announcing "I'm here, and here's my name" to everything on the wire. Run this alongside an HTTP fingerprint and you get coverage neither has alone.

Running it at scale

Your own network and perimeter first — cleanest authorization, and mDNS findings are most actionable inside networks you control.

nuclei -t openclaw-exposure.yaml -l targets.txt -o openclaw-hits.txt

The template already pins port 5353 in its args, and the isUDPPortOpen pre-condition means you can throw a wide host list at it without hammering anything — closed ports are skipped before a packet is sent.

Pre-filter with a UDP scan for big ranges. UDP scanning is slower than TCP, so on large scopes it's worth finding the live 5353 listeners first and handing only those to Nuclei:

# naabu doesn't do UDP; use nmap for the 5353/udp sweep
nmap -sU -p 5353 --open -iL ranges.txt -oG - | awk '/Up$/{print $2}' > mdns-hosts.txt
nuclei -t openclaw-exposure.yaml -l mdns-hosts.txt -o openclaw-hits.txt

Internet-wide, pivot off scan data. Don't actively blast UDP across the internet — it's noisy, slow, and legally fraught. Use the metadata queries baked into the template (product:openclaw on Shodan, body="ClawdBot" on FOFA) to enumerate exposed instances, then run the template only against candidates in your authorized scope.

Run it continuously, not once. OpenClaw's install base is climbing by the day right now, which means new gateways are appearing all the time — a one-shot scan goes stale fast. And pair every hit with two actions: get the gateway off any reachable interface, and rotate the credentials it holds.

Why this matters

mDNS leakage is the finding the template produces, but the reason to care right now is what's sitting behind an exposed gateway.

The timing is the story. CVE-2026-25253 was disclosed on 26 January and patched in OpenClaw 2026.1.29, released at the end of last week. It's a 1-click remote code execution: the Control UI accepts a gatewayUrl from a URL query string and automatically opens a WebSocket to it without confirmation, leaking the instance's auth token to whoever controls that URL. Steal the token, hijack the WebSocket, run commands. It needs no prior authentication, it's rated CVSS 8.8 (CWE-669, Incorrect Resource Transfer Between Spheres), and — the nasty part — it works even against instances running only on localhost, because the attack pivots through the victim's own browser. Researchers are calling it a "1-click RCE kill chain." Proof-of-concept code is already public, and broad press coverage is only just landing as I write this.

That's the acute issue, but the standing one is exposure in general. OpenClaw stores credentials for the cloud models it drives — Claude, OpenAI, Google AI — plus tokens for whatever messaging and tooling integrations you've wired in. An exposed gateway is SSH open with no password, except the password is a pile of paid AI credentials and a foothold on the host. And because an agent is an identity with access, whoever takes one over inherits its tokens and OAuth grants, and can feed it instructions it'll carry out without question. The credentials are the immediate prize; the persistent foothold inside a privileged agent is the lasting one. A gateway broadcasting its own displayName over mDNS is just making itself easier to find. That's the gap this template is for.

Mitigation

If you run OpenClaw, this week's to-do list:

  1. Patch now. Update to 2026.1.29 or later — it fixes CVE-2026-25253. Patching doesn't undo prior exposure, so treat it as step one, not the whole job.
  2. Rotate the gateway token and every stored credential. New authToken, new API keys for Claude/OpenAI/Google AI, and check usage logs. If it was reachable, assume it's compromised.
  3. Get it off any reachable interface. Bind to loopback, or put it behind a VPN, bastion, or ZTNA, and block 5353/UDP at segment boundaries so mDNS stops crossing networks it has no business on. Loopback is the floor, not the ceiling — the RCE pivots through the browser, so localhost-only isn't a free pass.
  4. Run the agent with least privilege. No "god mode." Scope its system, file, and key access down, and monitor it like any account with standing API and OAuth grants.
  5. Watch for the exploit pattern. Flag unexpected WebSocket connections from browsers to external domains, and alert on gateway config changes.

The detection itself isn't exotic — a pre-condition, a raw mDNS query, two string matchers. The value is timing: it catches gateways announcing themselves on the network even when the HTTP side is locked down, right when a public 1-click RCE makes finding them urgent. Run it early, run it often, rotate keys on every hit. Agent runtimes are identities with keys; finding the exposed ones fast is the whole game.