Skip to content

MQTT IoT Broker Guard (mqtt) ​

The MQTT Broker Guard plugin inspects Message Queuing Telemetry Transport protocols (MQTT 3.1.1 and MQTT 5.0). It inspects initial client CONNECT packets, validates Client Identifiers against prefix rules and maximum length constraints, blocks scanner botnets (e.g., Shodan and automated IoT probes), and shields brokers from connection storms.


Capabilities & Threat Defense ​

Threat / Attack VectorDefense MechanismAction Taken
IoT Scanner & Botnet ProbingFilters Client Identifier against blocked_client_id_prefixesConnection terminated immediately with CONNACK refusal
Malformed Client ID ExploitsEnforces max_client_id_len length caps; sends MQTT CONNACK 0x02 (Identifier Rejected) before closing connection (since v3.4.0)Client receives spec-compliant rejection; compliant clients will not retry indefinitely
Broker Connection ExhaustionEnforces connection velocity limits and burst capsConnection throttled at the proxy layer

Installation ​

Install the plugin via CLI or declaratively:

# Install using short nametcp-warden plugins install mqtt# Or install via Git repository URLtcp-warden plugins install https://github.com/routewarden/plugins/mqtt

Configuration Reference ​

Add an MQTT guard service to tcp-warden.yaml:

services:  mqtt_broker_guard:    listen: ":1883"    upstream: "127.0.0.1:18830"    protocol: "mqtt"    rate_limit:      connections_per_minute: 60      burst: 15    plugin_config:      blocked_client_id_prefixes:        - "bot-"        - "scanner-"        - "shodan"        - "censys"      max_client_id_len: 64

Configuration Options ​

FieldTypeDefaultDescription
listenstring":1883"Local proxy listen address and port.
upstreamstring"127.0.0.1:18830"Target MQTT broker (Mosquitto, EMQX, HiveMQ) address.
protocolstring"mqtt"Must be set to "mqtt".
plugin_config.blocked_client_id_prefixes[]string[...]List of client ID prefixes blocked on connection attempt.
plugin_config.max_client_id_lenint64Maximum allowable length for the MQTT Client Identifier. When exceeded, a well-formed MQTT CONNACK response with return code 0x02 (Identifier Rejected) is sent before the connection is closed, per MQTT 3.1.1 specification (since v3.4.0).

Network & Deployment Architecture ​

Because MQTT operates on an unprivileged port (1883), packet redirection rules (nftables/iptables) are not required. Deploy RouteWarden using either direct reverse proxying or container network isolation:

Option A: Direct Reverse Proxy (Bare-Metal / VM) ​

Bind RouteWarden to :1883, with Mosquitto listening on loopback on an alternate port or private subnet IP:

# tcp-warden.yaml — RouteWarden binds to standard MQTT port 1883services:  mqtt_broker_guard:    listen: ":1883"    upstream: "127.0.0.1:18830" # Or private backend "10.0.0.40:1883"    protocol: "mqtt"

Option B: Docker Compose Bridge Network ​

In containerized stacks, publish port 1883 on RouteWarden while keeping Mosquitto private to the internal Docker network:

services:  routewarden:    image: ghcr.io/routewarden/tcp-warden:latest    ports:      - "1883:1883"      - "9091:9091"    volumes:      - ./tcp-warden.yaml:/etc/routewarden/tcp-warden.yaml:ro    depends_on:      - mosquitto  mosquitto:    image: eclipse-mosquitto:2    # Do NOT publish host ports; keep internal to bridge network

Testing & Verification ​

Verify legitimate connections and test blocked scanner client prefixes:

# Connect legitimate MQTT client through RouteWardenmosquitto_sub -h 127.0.0.1 -p 1883 -i "device-001" -t "sensors/#" -v

Released under the MIT License.