Case study

NanoMQ Fuzzing Infrastructure

A merged upstream contribution that added a protocol aware libFuzzer path for the MQTT PUBLISH decoder and prepared a separate OSS Fuzz integration request.

Role
Open source security contributor
Status
Merged upstream contribution with an open follow on
Year
2026
  • Cybersecurity
  • C
  • Protocol fuzzing
  • Open source
Architecture showing MQTT seeds and a dictionary feeding libFuzzer, the NanoMQ PUBLISH decoder, and sanitizer evidence

Evidence boundary

Claims and supporting records

  1. Merged NanoMQ pull request 2238 added an optional fuzzing build path, a libFuzzer harness for MQTT PUBLISH decoding, an MQTT dictionary, seed inputs, and operating documentation.

  2. The merged harness exercises native NanoMQ decoder code with protocol informed inputs and sanitizer compatible build settings.

  3. I prepared the separate NanoMQ onboarding change for OSS Fuzz, and that pull request remains open rather than merged.

Problem

NanoMQ processes MQTT packets supplied by network clients. A conventional example based test can cover expected packets while missing malformed lengths, unusual property combinations, and byte sequences that only appear after sustained mutation.

The engineering goal was to give the project a repeatable way to exercise its PUBLISH decoder with generated inputs under memory safety instrumentation.

Constraints

The contribution had to fit an established native C project and its existing CMake build. The harness needed to test real decoder behavior, clean every resource it created, and remain optional so normal NanoMQ builds were unaffected.

MQTT version differences also mattered. Useful mutation requires valid starting shapes and protocol tokens, not only arbitrary bytes. Upstream acceptance required review by maintainers outside the project work that produced the first implementation.

Ownership

I designed and submitted the fuzzing contribution as an external open source contributor. My merged work covered the optional build configuration, PUBLISH decoder harness, MQTT dictionary, seed corpus, and usage documentation.

NanoMQ maintainers own the broker and the final upstream decisions. I later prepared the separate OSS Fuzz onboarding pull request, which is still open.

Decisions

I targeted the PUBLISH decoder because it is a network facing parsing boundary with structured input. The harness passes controlled bytes into the existing decoder instead of recreating MQTT parsing in test code.

I paired the harness with a small seed corpus and MQTT dictionary. Seeds give mutation a valid starting shape. Dictionary tokens help the fuzzer construct packet types and property identifiers that are meaningful to the protocol.

The fuzzing build is opt in. That choice keeps sanitizer and libFuzzer settings out of ordinary builds while giving security testing a documented entry point.

Implementation

The CMake option prepares a static, sanitizer compatible build and compiles the fuzz target. The harness receives each byte buffer from libFuzzer, establishes the required NanoMQ objects, calls the PUBLISH decode path, and releases the resources it owns.

The corpus contains representative MQTT inputs. The dictionary provides protocol specific byte tokens. The accompanying documentation explains how to build and run the target so maintainers can reproduce the workflow rather than depend on one development machine.

The separate OSS Fuzz pull request packages the project configuration needed for continuous service integration. Its open status is part of the evidence boundary.

Result

NanoMQ merged the fuzzing infrastructure through pull request 2238. The accepted upstream result is the optional build path, harness, dictionary, corpus, and documentation.

The OSS Fuzz integration request is public and inspectable, but it has not been merged. This case study does not present the service integration as complete.

Limitations

The merged pull request should not be described as proof that every locally investigated decoder fix entered NanoMQ. It proves that the fuzzing infrastructure entered the upstream repository.

No vulnerability count, coverage improvement, execution rate, or security guarantee is claimed. Those statements would require preserved campaign evidence and separate confirmation of each upstream fix.

Reflection

Security tooling becomes more valuable when maintainers can build it, understand it, and keep running it. The contribution therefore needed both a technically correct harness and a path that respected the host project.

The open OSS Fuzz request also illustrates an important distinction. Preparing a documented integration request is meaningful engineering work, but submission is not acceptance.