This repository is a client-side MQTT 3.1.1 library implemented in C23. It is not a broker, not a sandbox, not a TLS stack, and not an authorization layer. Its job is to serialize MQTT requests, parse MQTT broker responses, and manage client-side protocol state inside the caller's process.
Everything that comes from the network, from the broker, or from caller-supplied topics and payloads must be treated as untrusted. The library enforces protocol framing and some internal consistency checks, but application policy remains the caller's responsibility.
- Inbound broker traffic processed by
__mqtt_recv(),mqtt_sync(), and the unpacking helpers is untrusted. - Topic names, payloads, credentials, keep-alive values, and all other inputs passed into the public API are untrusted until the application validates them.
- The core library performs socket I/O through the PAL in
include/mqtt/mqtt_pal.handsrc/mqtt_pal.c. The PAL, socket handle type, and any custom transport implementation are part of the trusted computing base. - TLS configuration and certificate validation are outside the core MQTT library. The OpenSSL, mbedTLS, WolfSSL, and BearSSL paths live in the PAL and examples; their correctness depends on the caller's transport setup.
- User callbacks (
publish_response_callback,inspector_callback,reconnect_callback) execute with the caller's privileges and are trusted.
- Memory safety while packing and unpacking MQTT control packets.
- Integrity of the client's internal message queue, packet ID tracking, and retransmission state.
- Correct handling of caller-owned send and receive buffers.
- Rejection of malformed fixed headers, invalid flags, invalid remaining lengths, malformed responses, and unexpected acknowledgements.
- The parser validates MQTT control packet types and required flag patterns.
- Remaining length handling rejects values beyond the MQTT 3.1.1 limit of
268435455. - The client reports
MQTT_ERROR_RECV_BUFFER_TOO_SMALLwhen the configured receive buffer can never fit the next complete packet. - The send path reports
MQTT_ERROR_SEND_BUFFER_IS_FULLwhen the configured egress queue cannot stage another message. - The default PAL treats peer closure and hard socket/TLS errors as
MQTT_ERROR_SOCKET_ERRORso callers can reconnect. - Per-client mutexes protect internal state transitions during normal API use.
- Debug builds are wired for
-fsanitize=address,undefined,leakinjustfileandbuild.zig.
- The library is MQTT 3.1.1, not MQTT 5.
- The core library does not provide encryption by itself. Plain TCP is the default unless the caller selects a TLS-capable PAL/socket handle.
- Default examples and integration tests target
test.mosquitto.orgon ports1883or8883. - Send and receive storage is fully caller-owned. Buffer sizes directly affect reliability and denial-of-service tolerance.
mqtt_init()expects a non-blocking connected socket.sendbufshould be suitably aligned forstruct mqtt_queued_messageaccesses. Unaligned transmit buffers can fault on strict-alignment targets.
- Treat broker-provided topic names and payloads as attacker-controlled data. The library does not sanitize application payload contents.
- The core library does not implement hostname verification, certificate pinning, trust store management, secret storage, ACLs, or authorization checks. Those belong in the application and transport layer.
publish_response_callbackis invoked directly from the receive path while the client mutex is held. Keep it non-blocking and avoid re-entering the same client from that callback.- If
publish_response_callbackis null, inboundPUBLISHpackets are still parsed and protocol acknowledgements are generated, but the decoded publish is dropped after protocol handling. inspector_callbackandreconnect_callbackare also trusted code paths. Bugs in those callbacks can deadlock the client, corrupt application state, or weaken reconnect logic.mqtt_sync()and reconnect handling rely on specific lock sequencing. Sharing onemqtt_clientacross threads is supported only if callers respect the documented API model and do not bypass it with unsynchronized direct field access.- The library does not persist session state across process restarts and does not rate-limit broker traffic. Hostile peers can still consume CPU, socket bandwidth, and caller-provided buffer space.
- Example programs are demonstrations, not hardened production deployments. They print received data, use public brokers, and inherit the transport and callback risks above.
Validation confirmed in this checkout:
just testbuildsbin/testssuccessfully. In this environment, the local serialization and utility tests passed, and the network-backed broker tests depend on outbound DNS/network access totest.mosquitto.org.zig build testscompletes successfully as a build-only check for the test executable.
Additional validation paths present in the repository:
zig build testbuilds and runs the test executable.just build-examplesandzig build examplesbuild the example clients.- Setting
DEBUG=1forjustor-Doptimize=Debug -Dsanitize=truefor Zig enables sanitizer-backed builds on supported platforms.
- Use TLS and explicit certificate verification in production. Do not treat the plain TCP examples as a secure default.
- Size
sendbufandrecvbuffor the largest publish, subscription, and acknowledgement patterns your broker can produce. - Provide a real
publish_response_callbackfor any subscriber or any client that might receive publishes. - Keep callbacks small, non-blocking, and free of recursive calls into the same client unless you have audited the locking implications.
- Reconnect logic should close and replace compromised sockets, rebuild subscriptions, and reapply authentication state explicitly.
- If the library will process hostile traffic, keep sanitizer coverage and
protocol tests in CI and consider adding dedicated fuzzing for
mqtt_unpack_response()and related parsers.
This repository does not currently publish a dedicated private security contact or disclosure workflow in-tree. If you need coordinated disclosure, use an existing maintainer contact channel if you have one; do not post exploit details publicly before the maintainer has had a chance to assess them.