{"id":"CVE-2026-95847","aliases":["EUVD-2026-85417","GHSA-5f42-97gr-vfhq"],"status":"published","title":"Moquette client IDs can cause cross-session H2 durable-queue corruption","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, H2PersistentQueue 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 make its message map collide with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types, which can corrupt queue head and tail data and cause message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions. This issue is fixed in version 0.18.1.","severity":{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00341,"percentile":0.27839,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-155","CWE-20","CWE-248","CWE-636","CWE-674","CWE-770","CWE-862","CWE-863","CWE-99"],"published":"2026-09-23T16:11:18Z","modified":"2026-10-28T11:21:49Z","affected":[{"source":"osv","ecosystem":"Maven","package":"io.moquette:moquette-broker","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.18.1"}]}],"versions":["0.15","0.16","0.17"],"bundled":8}],"products":[{"vendor":"moquette","product":"moquette"},{"vendor":"moquette-io","product":"moquette"}],"references":[{"url":"https://github.com/moquette-io/moquette/security/advisories/GHSA-5f42-97gr-vfhq","tags":["x_refsource_CONFIRM","exploit","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/moquette-io/moquette/pull/964","tags":["x_refsource_MISC","Patch","fix"]},{"url":"https://github.com/moquette-io/moquette/commit/72d6c8257191d2e4b2e3aa11ab25fd09f88c6cb7","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/moquette-io/moquette/releases/tag/v0.18.1","tags":["x_refsource_MISC","Release Notes","web"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/85xxx/CVE-2026-85724.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-85724","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/b4a98bb3f3425ece476ed073aa080c627c1239af","tags":["fix","web"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95842.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95842","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/86feb7c31e6fac849c465d8079d08c0e7ef01cdf","tags":["fix","web"]},{"url":"https://github.com/moquette-io/moquette/pull/957","tags":["fix","web"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95843.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95843","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/affdc71fdba92dc020421678970ae70518fb6da2","tags":["fix","web"]},{"url":"https://github.com/moquette-io/moquette/pull/962","tags":["fix"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95844.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95844","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/ca17e0be19e86d5e291f4532dfdc94616c8e0049","tags":["fix","web"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95845.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95845","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/2482cadfba44e615be704b892009a57ce06a1aba","tags":["fix"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95846.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95846","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/f5a323fe782d1505c0097498cb22eb6ec6c96973","tags":["fix","web"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95847.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95847","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/95xxx/CVE-2026-95848.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-95848","tags":["advisory"]},{"url":"https://github.com/moquette-io/moquette/commit/14a2f4fd280c8f6a791600c306cbccecb7c67007","tags":["fix","web"]},{"url":"https://github.com/moquette-io/moquette/pull/967","tags":["fix"]},{"url":"https://github.com/moquette-io/moquette/pull/959","tags":["web"]},{"url":"https://github.com/moquette-io/moquette/pull/958","tags":["web"]},{"url":"https://github.com/moquette-io/moquette/commit/d77753542e262b7aa573dee3c2b05e44439bbd96","tags":["web"]},{"url":"https://github.com/moquette-io/moquette/commit/c65b3e90fa03e562e2c2fa69c3ee916c2cbfbd2b","tags":["web"]},{"url":"https://github.com/moquette-io/moquette/commit/26498631e92d50440b4e3ed42fa546253cc4090c","tags":["web"]},{"url":"https://github.com/moquette-io/moquette","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-95847","title":"Moquette client IDs can cause cross-session H2 durable-queue corruption","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, H2PersistentQueue 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 make its message map collide with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types, which can corrupt queue head and tail data and cause message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:56.125Z","modified":"2026-09-23T16:50:25.152Z","cvss":[{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high","assessor":"cna"}],"cwes":["CWE-99"],"updated_at":"2026-11-02T14:20:05.505362Z"}],"euvd":[{"id":"EUVD-2026-85417","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, H2PersistentQueue 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 make its message map collide with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types, which can corrupt queue head and tail data and cause message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:56Z","modified":"2026-09-23T16:50:25Z","cvss":[{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T17:28:00.617613Z"}],"nvd":[{"id":"CVE-2026-95847","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, H2PersistentQueue 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 make its message map collide with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types, which can corrupt queue head and tail data and cause message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T17:17:21.78Z","modified":"2026-09-28T15:23:24.197Z","cvss":[{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high","assessor":"primary"}],"cwes":["CWE-99"],"updated_at":"2026-11-02T14:12:50.703874Z"}],"osv":[{"id":"CVE-2026-85724","title":"Moquette pattern ACL wildcard injection allows cross-tenant authorization bypass","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, when pattern-based ACL rules are configured, AuthorizationsCollector.canDoOperation substitutes client ID and username values directly into rules containing %c or %u and then treats the result as an MQTT topic filter. A client that uses + or # in either identity can broaden the substituted filter and gain cross-tenant read and write access. A # identity can also produce an invalid filter that triggers a NullPointerException in Topic.match and disrupts session processing. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:36.296Z","modified":"2026-10-28T11:00:52.689324241Z","cvss":[{"version":"3.1","score":9.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N","level":"critical"}],"cwes":["CWE-155","CWE-863"],"updated_at":"2026-11-02T15:45:18.825071Z"},{"id":"CVE-2026-95842","title":"Moquette uncaught MQTT command exceptions can terminate shared session event loops","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, SessionEventLoop.run catches only InterruptedException, and SessionEventLoopGroup does not restart a terminated loop. An MQTT command that raises an uncaught exception can terminate an event loop shared by multiple client sessions, preventing every co-located client from processing PUBLISH, SUBSCRIBE, PUBACK, and other commands. An attacker can select client IDs that map across the available loops to disrupt session processing for the entire broker. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:41.744Z","modified":"2026-10-28T11:21:46.570692649Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95843","title":"Moquette malformed shared subscriptions can crash command processing","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, PostOffice.subscribe parses a shared-subscription filter through SharedSubscriptionUtils.extractShareName before validating the complete $share/{shareName}/{topicFilter} structure. A remote client can send a filter such as $share/grp without a topic-filter portion, causing a StringIndexOutOfBoundsException while calculating the share name. The exception terminates command handling on the shared session event loop and can deny service to other client sessions assigned to that loop. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:44.588Z","modified":"2026-10-28T11:00:57.53610203Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95844","title":"Moquette deeply nested MQTT topics can cause stack exhaustion","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, Moquette does not limit the depth of topic names and topic filters before processing them through recursive CTrie insertion and matching operations. A remote client can publish or subscribe with a deeply nested topic, causing a StackOverflowError that disrupts session processing and can deny service to broker clients. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:49.416Z","modified":"2026-10-28T11:21:48.102924994Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-674"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95845","title":"Moquette unbounded per-session message queues allow memory exhaustion","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, the broker does not enforce a maximum length for pending per-session message queues. When a fast publisher sends messages to a slow subscriber whose in-flight window is full, queued messages can accumulate without bound in memory or persistent storage. Remote clients can use this condition to exhaust broker resources and cause a denial of service. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:51.402Z","modified":"2026-10-28T11:09:56.440359405Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-770"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95846","title":"Moquette publishes Last-Will messages without enforcing write authorization","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, PostOffice.publishWill publishes a client's Last-Will message without applying the canWrite authorization and reserved-topic checks used for a normal PUBLISH. A client can configure a Will for a topic that the client is not permitted to write and cause the broker to publish the unauthorized message when the client disconnects unexpectedly. This issue allows unauthorized message injection into restricted topics. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:54.13Z","modified":"2026-10-28T11:21:49.257586219Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-862"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95847","title":"Moquette client IDs can cause cross-session H2 durable-queue corruption","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, H2PersistentQueue 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 make its message map collide with another client's metadata map. The colliding sessions read and write the same H2 MVStore map with incompatible value types, which can corrupt queue head and tail data and cause message loss, misdelivery, failed queue reloads, or exposure of queued content across sessions. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:56.125Z","modified":"2026-10-28T11:21:47.336330742Z","cvss":[{"version":"4.0","score":8.8,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-99"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"CVE-2026-95848","title":"Moquette fails open when configured authentication or authorization classes cannot load","description":"Moquette is a lightweight Java MQTT broker. Prior to 0.18.1, when a configured authenticator or authorizator class cannot be loaded, Server.initializeAuthenticator and Server.initializeAuthorizatorPolicy treat the failure as though no custom class was configured and fall back to AcceptAllAuthenticator or PermitAllAuthorizatorPolicy. A misspelled class name, missing dependency, constructor failure, or classpath problem can therefore start the broker with authentication or authorization disabled even though the operator configured those controls. This issue is fixed in version 0.18.1.","status":"published","published":"2026-09-23T16:29:58.3Z","modified":"2026-10-28T11:21:46.952272648Z","cvss":[{"version":"4.0","score":9.3,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N","level":"critical"}],"cwes":["CWE-636"],"updated_at":"2026-11-02T15:45:21.262447Z"},{"id":"GHSA-5f42-97gr-vfhq","title":"Moquette: Pattern-ACL wildcard injection (cross-tenant authorization bypass) plus a remote-unauthenticated DoS cluster, a Will-message authorization bypass, and a cross-session durable-corruption bug","description":"moquette is reachable by untrusted MQTT clients (anonymous by default), so every byte from any client, including pre-authentication, is untrusted. This is a memory-safe JVM: the ceiling is authorization/ACL bypass + denial of service + cross-session integrity, **not RCE** (I did not find one and do not claim one). Audited at commit `da7f719a6bab9829d520b5838e13ea7b1f9be3ef`, module `broker/`.\n\n## What a connecting client can do\n\n1. (Critical) Bypass `pattern`-based ACLs across tenants. In `AuthorizationsCollector.canDoOperation` (AuthorizationsCollector.java:116-131, esp. line 123) the clientId/username is substituted raw into a pattern ACL rule and then wildcard-matched, and the clientId is never validated for MQTT wildcard characters +/# at CONNECT (MQTTConnection.processConnect):\n\nTopic substitutedTopic = new Topic(auth.topic.toString().replace(\"%c\", client).replace(\"%u\", username));\nif (topic.match(substitutedTopic)) return true;\n\nA client that connects with clientId + turns sensor/%c/# into the filter sensor/+/#, gaining cross-tenant read AND write. (Precondition: pattern ACL rules configured — a common multi-tenant setup.)\n\n2. (High) Crash the whole broker. SessionEventLoop (SessionEventLoop.java:40-54) catches only InterruptedException and is never restarted (SessionEventLoopGroup), so any uncaught exception on it wedges every co-located client. Trivially reachable inputs: malformed $share/grp SUBSCRIBE (SharedSubscriptionUtils.extractShareName -\u003e StringIndexOutOfBoundsException), deeply nested topic (CTrie recursion -\u003e StackOverflowError), and ACL NPE below. Unbounded subscriptions / retained / in-flight / topic-alias / interceptor state (BrokerInterceptor uses an unbounded queue) also allow OOM; durable stores allow disk exhaustion.\n\n3. (High) NPE in ACL sink on clientId # (invalid filter sensor/#/# -\u003e null tokens -\u003e Topic.match NPE at Topic.java:173).\n\n4. (High) Will-message authorization bypass. Last-Will topic is published (PostOffice.publishWill) without canWrite/reserved-topic checks used for normal PUBLISH.\n\n5. (Medium) Cross-session durable corruption. H2PersistentQueue opens queue_\"+clientId and queue_\"+clientId+\"_meta; client id sensor_meta collides with victim sensor metadata map -\u003e corrupts head/tail.\n\n6. (Medium) Fail-open if authenticator/authorizator class fails to load -\u003e PermitAll/AcceptAll (Server.java:483-531).\n\n## Proof of concept\n\nSource-only, no network; PoCs run on JDK 17:\n- PoCPatternAcl — clientId + gains cross-tenant read/write; clientId # triggers NPE\n- PoCSharedSubCrash — extractShareName(\"$share/grp\") throws StringIndexOutOfBoundsException\n- PoCMapCollision — H2 MVStore collision overwrites victim metadata pointer\n\n## Impact\n\nCross-tenant eavesdropping and injection, whole-broker DoS, unauthorized Will publishes, and cross-session durable corruption.\n\n## Remediation\n\n1. Reject clientId/username containing +/# (and / if structural) at CONNECT; expand %c/%u as literal tokens.\n2. Harden SessionEventLoop (catch Throwable + restart supervision) and validate $share filters.\n3. Apply authorization to Will publishes like normal PUBLISH.\n4. Add resource caps (connections, queues, retained, aliases, interceptor queue) + bounded session expiry.\n5. Separate H2 namespaces and fail closed on auth-class load failure.","status":"published","published":"2026-09-23T16:11:18Z","modified":"2026-10-19T19:30:12.063094642Z","cvss":[{"version":"3.1","score":9.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N","level":"critical"}],"cwes":["CWE-155","CWE-863"],"updated_at":"2026-11-02T15:46:38.213481Z"}]}}
