Securing the mosquitto MQTT broker

Summary: The mosquitto broker authorizes publication to SYS topics by default, which is a potential security risk. We explain how to address this issue and provide some background on MQTT brokers’ default security.

MQTT is a publish/subscribe messaging protocol: when a device sends out a message, it won’t explicitly send it to a given device or address, but instead the sender tags the message with a string called a topic. All devices that have previously subscribed to that topic will then receive the message; pretty dumb logic, but efficient and enough for most IoT and machine-to-machine networks.

In MQTT, topic names usually follow a topic hierarchy. For example, data from the New-York State power grid can be accessed using MQTT under topics such as “ny-power/upstream/fuel-mix/Hydro” or “ny-power/upstream/fuel-mix/Wind”. MQTT also supports a wildcard symbol: if a device subscribes the the topic “ny-power/#”, then it will receive all the messages published under topic names starting with “ny-power/”.

In MQTT, the server implementing the publish/subscribe logic—as well as authorization and authentication mechanisms—is called a broker. The best known MQTT broker is arguably mosquitto, an open-source broker part of the Eclipse Foundation and an project.

The first thing you have to be careful with when using mosquitto is that by default it is open to anonymous connections—that is, it allows anyone to connect to it and use it. Such an open broker would allow anyone to see the messages published by subscribing to their topics. A number of open brokers are available for testing, and you can also find open brokers evidently used for production and critical systems. In contrast, an enterprise-oriented broker such as VerneMQ will not allow you to connect to it without having first created authorized credentials, which is the safest default configuration.

Many systems and services will default to an insecure configuration, because it’s more convenient and because such services will often run in closed networks, where the risk is lower. For example, popular services such as ElasticSearch default to unauthenticated, unencrypted connections. Also, some MQTT brokers are only available via VPN, which minimizes the risk of open brokers. Insecure defaults are thus not always a big deal, as long as they’re documented and that the risk is obvious to most users.

Recently we observed another case of insecurity-by-default, which is the point of this post: so-called SYS topics. These are a special class of topics under which the broker publishes data, typically for monitoring purposes. SYS topics are not a formal standard but are an established practice in MQTT brokers. For example, mosquitto defines SYS topics such as:

$SYS/broker/clients/maximumThe maximum number of clients that have been connected to the broker at the same time.

$SYS/broker/clients/totalThe total number of active and inactive clients currently connected and registered on the broker.

$SYS/broker/messages/receivedThe total number of messages of any type received since the broker started.

As explained by HiveMQ, provider of an enterprise MQTT broker: “These topics are special meta topics which are used by the broker to publish information about the broker itself and its MQTT client sessions. All SYS-Topics start with $SYS and are read-only for MQTT clients, so publishing to these topics is prohibited.” We indeed verified that the HiveMQ broker prevents publication to SYS topics in its default configuration. The aforementioned VerneMQ does it too.

Furthermore, the MQTT standard states (as non-normative comment) that “Applications cannot use a topic with a leading $ character for their own purposes”, which suggests that publication SYS topics should be restricted to the broker.

Mosquitto, however, authorizes by default any client to publish messages under SYS topics, and therefore to potentially send fake status data to consumers. In particular, mosquitto’s public broker allows clients to publish to $SYS/#. You can for example send fake data as follows, where I sent an invalid number of connected clients:

First, subscribe to the topic $SYS/broker/client/connected, (where the dollar sign must be escaped in my terminal):

$ mosquitto_sub -h -t "\$SYS/broker/clients/connected" -d
Then, in another terminal, publish an invalid number of connected clients under that topic (here, 414141414141):

$ mosquitto_pub -h -t "\$SYS/broker/clients/connected" -m 414141414141 -d

The first terminal will then show that it received correct values (968, 970), followed by the incorrect one.:

Client mosqsub|80540-id received PUBLISH (d0, q0, r0, m0, '$SYS/broker/clients/connected', ... (3 bytes))
Client mosqsub|80540-id received PUBLISH (d0, q0, r0, m0, '$SYS/broker/clients/connected', ... (3 bytes))
Client mosqsub|80540-id received PUBLISH (d0, q0, r0, m0, '$SYS/broker/clients/connected', ... (12 bytes))


We reported this observation to mosquitto maintainers, who responded that this permissive behavior is intended and well known. Unlike opening the service to anonymous connections, however, authorizing publication to SYS topics doesn’t have any usability or convenience benefit, so we respectfully challenge this design choice.

It is therefore the responsibility of users to prevent the publish capabilities to SYS topics. This can be done via access control lists (ACL), as for example documented here.

To conclude, if you run an MQTT broker make sure that:

  1. Your service is not open to anyone (well-known risk);
  2. Only the broker can publish to SYS topics (also note that SYS topics should not be used as a source of production metrics).

One thought on “Securing the mosquitto MQTT broker

Comments are closed.