Skip to main content
Vulnerability Database/CVE-2026-95847

CVE-2026-95847: Moquette MQTT Broker Information Disclosure

CVE-2026-95847 is an information disclosure vulnerability in Moquette Java MQTT broker that allows session collision and data exposure. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-95847 Overview

CVE-2026-95847 affects Moquette, a lightweight Java Message Queuing Telemetry Transport (MQTT) broker. The vulnerability exists in the H2PersistentQueue component in versions prior to 0.18.1. The broker derives a session's message-map name as queue_ plus the client ID, and its metadata-map name as queue_ plus the client ID plus _meta. A durable session whose client ID ends in _meta can therefore collide its message map with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types. This is classified under [CWE-99] Improper Control of Resource Identifiers.

Critical Impact

An unauthenticated remote attacker can register a durable session with a crafted client ID to corrupt queue head and tail data, causing message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions.

Affected Products

  • Moquette MQTT Broker versions prior to 0.18.1
  • Deployments using H2PersistentQueue for durable session persistence
  • Any application embedding vulnerable Moquette releases as an MQTT broker library

Discovery Timeline

  • 2026-09-23 - CVE-2026-95847 published to the National Vulnerability Database (NVD)
  • 2026-09-23 - Last updated in NVD database
  • Patch released - Moquette v0.18.1 published with the fix

Technical Details for CVE-2026-95847

Vulnerability Analysis

The flaw resides in broker/src/main/java/io/moquette/persistence/H2PersistentQueue.java. Moquette uses the H2 MVStore key-value engine to persist durable MQTT sessions. Each session receives two named maps: a message map storing enqueued MQTT payloads keyed by a monotonic Long, and a metadata map storing head and tail offsets keyed by String. The map names are derived directly from the raw MQTT client ID without namespacing.

Because both prefixes share the string queue_ and the metadata name appends _meta, an attacker-controlled client ID ending in _meta produces a message-map name that matches the metadata-map name of a legitimate session. Two sessions then bind to the same underlying MVStore map with incompatible value types (EnqueuedMessage versus Long). Writes from one session corrupt the head and tail offsets of the other, resulting in message loss, misdelivery to the wrong subscriber, failed queue reloads at broker restart, or exposure of queued content across tenants.

Root Cause

The root cause is unsafe resource name construction. The client ID is used as a raw component of a persistent storage identifier without validation or namespace separation. See the GitHub Security Advisory GHSA-5f42-97gr-vfhq for the coordinated disclosure record.

Attack Vector

The attack vector is network based and requires no authentication or user interaction on brokers that accept anonymous durable sessions. An attacker connects to the MQTT broker with cleanSession=false and a client ID crafted to end in _meta. When any legitimate durable session shares the derived name prefix, the two maps collide inside H2 MVStore and corruption occurs on subsequent publish or reload operations.

java
 class H2PersistentQueue extends AbstractSessionMessageQueue<SessionRegistry.EnqueuedMessage> {

+    // The message map and the metadata map must live in disjoint name spaces. The queue name is a raw
+    // client id, so deriving both names from a shared "queue_" prefix let a client id ending in "_meta"
+    // make its message map ("queue_" + "victim_meta") collide with another client's metadata map
+    // ("queue_" + "victim" + "_meta") -> durable cross-session corruption. The metadata prefix now differs
+    // from the message prefix at a fixed position, so no queue name can make the two names collide.
+    private static final String MESSAGES_MAP_PREFIX = "queue_";
+    private static final String METADATA_MAP_PREFIX = "queuemeta_";
+    private static final String LEGACY_METADATA_MAP_SUFFIX = "_meta";
+
     private final MVMap<Long, SessionRegistry.EnqueuedMessage> queueMap;
     private final MVMap<String, Long> metadataMap;
     private final AtomicLong head;

Source: Moquette Commit 72d6c82

Detection Methods for CVE-2026-95847

Indicators of Compromise

  • MQTT CONNECT packets containing client IDs ending in the literal suffix _meta from external or untrusted sources
  • Unexpected ClassCastException or MVStore type mismatch errors in Moquette broker logs referencing queue_ prefixed maps
  • Failed durable queue reload messages at broker startup, or subscribers receiving payloads addressed to different client IDs

Detection Strategies

  • Inspect MQTT broker access logs and connection audit records for client identifiers matching the pattern .*_meta$
  • Correlate H2 MVStore corruption stack traces with the timestamps of new durable session registrations
  • Monitor for cross-session message misdelivery reports from downstream consumers as a behavioral indicator

Monitoring Recommendations

  • Forward Moquette broker logs to a centralized analytics platform and alert on H2PersistentQueue warnings and errors
  • Track the population of unique durable client IDs and flag new entries whose suffix matches reserved internal patterns
  • Baseline normal MQTT publish and subscribe rates per client ID to detect anomalous cross-tenant traffic

How to Mitigate CVE-2026-95847

Immediate Actions Required

  • Upgrade Moquette to version 0.18.1 or later, which namespaces the metadata map under the queuemeta_ prefix
  • Audit existing durable session storage for client IDs ending in _meta and revoke or rename any suspicious entries
  • Restrict anonymous MQTT connections and require authentication before allowing durable session registration

Patch Information

The fix is available in Moquette v0.18.1 and merged via Pull Request #964. The patch introduces a distinct METADATA_MAP_PREFIX constant so that no valid client ID can produce a colliding storage name. A LEGACY_METADATA_MAP_SUFFIX constant is retained to migrate existing on-disk data. Review the full diff in commit 72d6c82.

Workarounds

  • Enforce a client-ID validation policy at the broker or authentication layer that rejects identifiers ending in _meta
  • Require authenticated connections and bind each authenticated principal to a namespaced client-ID prefix
  • Disable durable sessions where feasible by requiring cleanSession=true until the patch can be applied
bash
# Configuration example: enforce client-ID validation at an upstream proxy or auth hook
# Reject any MQTT CONNECT whose ClientID matches the vulnerable suffix pattern
CLIENT_ID_DENY_REGEX='.*_meta$'

# Upgrade Maven dependency to the patched release
# <dependency>
#   <groupId>io.moquette</groupId>
#   <artifactId>moquette-broker</artifactId>
#   <version>0.18.1</version>
# </dependency>

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.