Writing a third-party UHBS protocol plugin¶
Status: Phase 1 / experimental extension point. UHBS is an open-source evaluation framework (see
AGENTS.mdandGOVERNANCE.md) — this page describes what the code does today, not a certified or committee-reviewed plugin API.
UHBS ships 39 built-in protocol plugins under src/uhbs_core/protocols/
(uhbs lab --list-protocols): bacnet, bluetooth, coap, dhcp, dns, ftp, generic, git, http,
httpproxy, imap, ipp, irc, kubernetes, ldap, mcp, memcache, modbus, mongodb, mqtt, mssql,
mysql, ntp, oracle, pjl, pop3, postgres, rdp, redis, s7comm, sip, smb, smtp,
snmp, socks5, ssh, telnet, tftp, vnc. As of this note, the registry
(src/uhbs_core/protocols/registry.py) can also load plugins from an
installed third-party Python package via
importlib.metadata entry points —
you do not need to fork this repository to add a protocol.
1. Implement a plugin class¶
A plugin is any class implementing the uhbs_core.protocols.base.ProtocolPlugin
interface (probe_fsm and probe_negotiation are required; probe_timing,
probe_state, probe_payload, probe_fuzz, and probe_load_once have
sane defaults you may override). See src/uhbs_core/protocols/generic.py
for the smallest working example, and
src/uhbs_core/contract_validation.py's UHBSProtocolPlugin structural
Protocol for a documented method-signature reference you can type-check
against without subclassing anything.
# my_uhbs_acme_plugin/plugin.py
from uhbs_core.models import CheckResult, TargetSpec
from uhbs_core.protocols.base import ProtocolPlugin
from uhbs_core.tps import TPS
class AcmeProtocolPlugin(ProtocolPlugin):
name = "acme-protocol"
families = ("iot",)
def probe_fsm(self, host: str, port: int, target: TargetSpec, tps: TPS | None):
... # return list[CheckResult]
def probe_negotiation(self, host: str, port: int, target: TargetSpec, tps: TPS | None):
... # return list[CheckResult]
src/uhbs_core/plugin_sdk.py re-exports the low-level netutil transport
helpers (tcp_transact, udp_transact, sample_udp_latencies) with
plugin-author-facing docstrings/defaults, plus a couple of small new
framing helpers (e.g. PktLineBuilder) — prefer it over reaching into
uhbs_core.netutil directly so your plugin keeps working if internal
helper names change.
2. Register it via a Python entry point¶
In your own package's pyproject.toml (not this repository's), declare
an entry point under the uhbs.plugins group pointing at your plugin class:
[project.entry-points."uhbs.plugins"]
acme-protocol = "my_uhbs_acme_plugin.plugin:AcmeProtocolPlugin"
When your package is pip install-ed alongside uhbs, the registry
automatically discovers and instantiates it the next time UHBS starts —
no changes to this repository are required. Internally, this repo's own
pyproject.toml documents the same group (as a comment, since there
are no first-party third-party plugins to register yet):
# Third-party plugin authors register here in *their own* project, not here:
# [project.entry-points."uhbs.plugins"]
# acme-protocol = "my_uhbs_acme_plugin.plugin:AcmeProtocolPlugin"
3. Failure isolation¶
load_external_plugins() loads every discovered entry point independently,
inside a try/except. If your plugin's module fails to import, its class
fails to instantiate, or it doesn't actually implement ProtocolPlugin,
UHBS logs a logging.warning(...) and continues bootstrapping the
built-in plugins — a broken third-party package cannot crash the core
harness. See tests/test_entry_point_plugins.py for the exact contract
being tested (including the "broken plugin doesn't crash discovery" case).
4. Maturity expectations¶
Per GOVERNANCE.md, a plugin registered only via an
entry point is Experimental by default — UHBS performs basic
presence/type checks on load, not a security or protocol-fidelity audit.
See GOVERNANCE.md's plugin maturity lifecycle section for what it takes
to be considered for Standard recognition in this repository's own
docs/conformance/ fixtures, and
docs/architecture/plugin-contracts.md
for the (opt-in, advisory) CheckResult contract validator plugin authors
can run against their own output.
5. Lab-target safety (built-in probes)¶
Built-in plugins that speak proxies, DNS, DHCP, or cleartext auth are designed for isolated lab targets only:
- httpproxy / socks5 — CONNECT / tunnel probes use loopback or
.invaliddestinations on purpose. Point them at a production proxy and you risk unintended egress (SSRF-shaped traffic from the proxy’s view). - dns / dhcp — UDP probes assume a honeypot or hermetic stub, not a shared enterprise resolver/DHCP server.
- imap — negotiation may send a synthetic cleartext
LOGINwith disposable credentials to exercise AUTH paths; never aim that at a real mailbox.
Cap framed reply sizes in new plugins (see LDAP’s 64 KiB BER cap and MongoDB’s message limit) so a broken peer cannot force unbounded allocations in the harness process.
What this is not (yet)¶
- Not a plugin marketplace or curated registry — there is no discovery UI.
- Not a security sandbox — an entry-point plugin runs with the same privileges as the harness process. Only install plugin packages you trust.
- Not schema/Pydantic-enforced at the interface boundary yet — see
docs/architecture/plugin-contracts.mdfor the current (dataclass + advisory validator) state and the tracked Pydantic v2 follow-up inROADMAP.md.