
Fuzzer for the Sparkplug B IIoT protocol
A comprehensive security assessment tool for testing Sparkplug B MQTT protocol implementations. The fuzzer systematically tests all protocol fields across all 9 message types, discovers live devices on the network, and produces detailed logs for analysis.
This tool sends malformed, injection, and protocol-violating MQTT messages to a target broker. Only run it against systems you own or have explicit written authorization to test. Sparkplug B brokers commonly sit in OT/ICS environments where unexpected payloads can disrupt physical processes — assume every target is production-adjacent unless proven otherwise.
If you discover a vulnerability in a Sparkplug B implementation using this tool, please follow coordinated disclosure with the affected vendor. To report a security issue in this tool itself, see SECURITY.md.
The Sparkplug B specification defines a topic namespace and payload format built on MQTT and Google Protocol Buffers for Industrial IoT (IIoT) environments. This fuzzer assesses the security and robustness of Sparkplug B implementations by:
On modern Debian/Ubuntu/Kali (PEP-668 systems), --setup cannot pip install into the system Python — use a virtual environment or pipx first. The recommended path:
python3 -m venv .venv
source .venv/bin/activate
python3 sparkplug-fuzzer.py --setup
Or run via pipx run if you prefer not to manage the venv yourself. On older systems without PEP-668 enforcement, plain python3 sparkplug-fuzzer.py --setup works directly.
--setup will:
paho-mqtt, protobuf)TAHU_REF in the script)sparkplug_b.py and array_packer.py helper modulessparkplug_b.proto into Python bindings (uses protoc if available, falls back to grpcio-tools)After setup, your directory should contain:
sparkplug-fuzzer.py # The fuzzer
sparkplug_b.py # Sparkplug B helper module (from Tahu)
array_packer.py # Array packing helper (from Tahu)
sparkplug_b_pb2.py # Generated protobuf bindings
requirements.txt # Python dependencies
pip install -r requirements.txt
git clone https://github.com/eclipse/tahu.git
cp tahu/python/core/sparkplug_b.py .
cp tahu/python/core/array_packer.py .
protoc --python_out=. sparkplug_b.proto
rm -rf tahu
python3 sparkplug-fuzzer.py --setup # first-time setup
python3 sparkplug-fuzzer.py -H localhost -p 1883 -v # run fuzzer
This will:
localhost:1883sparkplug_fuzz.jsonlpython3 sparkplug-fuzzer.py [OPTIONS]
| Option | Default | Description |
|---|---|---|
-H, --host | localhost | MQTT broker hostname or IP |
-p, --port | 1883 (or 8883 with --tls) | MQTT broker port |
-u, --username | None | MQTT username (also reads MQTT_USERNAME env var) |
-P, --password | None | MQTT password (also reads MQTT_PASSWORD; pass - to read from stdin without echo) |
--tls | off | Connect over TLS; default port becomes 8883 if -p unset |
--cafile | None | CA bundle for TLS server certificate verification |
--insecure | off | Skip TLS hostname/certificate verification (testing only) |
-g, --group | Sparkplug B Devices | Sparkplug group ID the fuzzer registers under |
-n, --node | FuzzNode | Sparkplug edge node ID for the fuzzer |
-d, --device | FuzzDevice | Sparkplug device ID for the fuzzer |
-c, --categories | all | Space-separated list of fuzz categories to run |
--discovery-time | 10 | Seconds to passively listen for network discovery |
--delay | 0.1 | Delay in seconds between fuzz messages |
--probe-anon-write | off | During discovery, send one QoS=1 publish to confirm whether the broker accepts unauthenticated PUBLISH |
-l, --log | sparkplug_fuzz.jsonl | Output log file name (relative paths land inside --output-dir; absolute paths are honored as-is) |
--output-dir | ./sparkplug-runs/<UTC-ts>_<host>/ | Per-run output directory. Created if absent. |
-v, --verbose | 0 | Increase console verbosity (-v = info, -vv = debug). -vv also surfaces fuzz-generator skips, and the throttled paho.mqtt logger bumps to INFO/DEBUG with verbosity. |
--setup | — | Install all dependencies and exit |
--tahu-path | — | Path to a local clone of eclipse/tahu (or its python/core directory). Used by --setup in air-gapped environments instead of git clone. |
--extra-string-payloads | — | Path to a file of additional string-injection payloads (one per line, UTF-8). Appended to the built-in STRING_FUZZ_VALUES; does not replace them. Max 10 MB / 10,000 payloads. See Custom string corpora. |