MQTT Topic ACL Linter

August 10, 2026 · View on GitHub

A deterministic, local-only TypeScript library for reviewing MQTT topic-filter ACL documents. It flags invalid filters, dangerously broad wildcard grants, duplicate or subsuming rules, literal placeholder text, and optional RunMQTT policy-boundary findings.

Try the canonical online demo at https://runmqtt.com/mqtt-acl-linter.

Trust boundary

  • profile mqtt contains generic MQTT syntax and structural checks. These findings are based on MQTT topic-filter rules or conservative least-privilege review guidance.
  • profile runmqtt adds current RunMQTT-specific Policy Template constraints, tenant and device boundaries, and directional naming heuristics. These findings are not MQTT protocol requirements and may not apply to another broker.
  • Analysis runs entirely in the calling process. The library does not connect to a broker, call an API, persist input, or send telemetry.
  • A clear result is not proof that a policy is secure. This is not a security audit and cannot evaluate broker-side precedence, inherited roles, provider transformations, or effective enforcement. Test allowed and denied operations against the real broker before deployment.

Requirements

  • Node.js 22 or newer
  • pnpm 10
pnpm install --frozen-lockfile
pnpm test

Input syntax

Input is a line-based document. Blank lines are ignored, and comments start with //.

profile mqtt|runmqtt
scope <literal-topic-prefix>
principal device|service <literal-id>
publish|subscribe|both <mqtt-topic-filter>

profile defaults to mqtt. A document needs at least one ACL rule. scope and principal provide context for RunMQTT-specific checks; they are not sent to RunMQTT or an MQTT broker. Publish and subscribe directions remain separate.

Generic MQTT example:

profile mqtt
publish factory/line-1/telemetry
subscribe factory/line-1/commands/#

RunMQTT-specific example:

profile runmqtt
scope tenants/acme
principal device sensor-42
publish tenants/acme/devices/sensor-42/telemetry
subscribe tenants/acme/devices/sensor-42/commands/#

Library usage

import { lintMqttAcl } from "./src/acl-linter";

const result = lintMqttAcl(`profile mqtt
subscribe factory/#`);

console.log(result.diagnostics);

The engine returns stable diagnostic codes, line numbers, MQTT or RunMQTT scope, and error, warning, or info severity. See the rule-set method for the complete input contract, diagnostic table, algorithm, fixtures, and limitations.

Development

pnpm format:check
pnpm typecheck
pnpm test

Changes to parsing or diagnostic behavior must update the fixtures, tests, and method document together. See CONTRIBUTING.md.

License

MIT © 2026 UllrAI.