security: add mDNS discovery config to reduce information disclosure (#1882)

* security: add mDNS discovery config to reduce information disclosure

mDNS broadcasts can expose sensitive operational details like filesystem
paths (cliPath) and SSH availability (sshPort) to anyone on the local
network. This information aids reconnaissance and should be minimized
for gateways exposed beyond trusted networks.

Changes:
- Add discovery.mdns.enabled config option to disable mDNS entirely
- Add discovery.mdns.minimal option to omit cliPath/sshPort from TXT records
- Update security docs with operational security guidance

Minimal mode still broadcasts enough for device discovery (role, gatewayPort,
transport) while omitting details that help map the host environment.
Apps that need CLI path can fetch it via the authenticated WebSocket.

* fix: default mDNS discovery mode to minimal (#1882) (thanks @orlyjamie)

---------

Co-authored-by: theonejvo <orlyjamie@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Jamieson O'Reilly
2026-01-27 00:32:11 +11:00
committed by GitHub
parent 58949a1f95
commit a1f9825d63
10 changed files with 162 additions and 22 deletions

View File

@@ -338,6 +338,7 @@ const FIELD_LABELS: Record<string, string> = {
"channels.signal.account": "Signal Account",
"channels.imessage.cliPath": "iMessage CLI Path",
"agents.list[].identity.avatar": "Agent Avatar",
"discovery.mdns.mode": "mDNS Discovery Mode",
"plugins.enabled": "Enable Plugins",
"plugins.allow": "Plugin Allowlist",
"plugins.deny": "Plugin Denylist",
@@ -369,6 +370,8 @@ const FIELD_HELP: Record<string, string> = {
"gateway.remote.sshIdentity": "Optional SSH identity file path (passed to ssh -i).",
"agents.list[].identity.avatar":
"Avatar image path (relative to the agent workspace only) or a remote URL/data URL.",
"discovery.mdns.mode":
'mDNS broadcast mode ("minimal" default, "full" includes cliPath/sshPort, "off" disables mDNS).',
"gateway.auth.token":
"Required by default for gateway access (unless using Tailscale Serve identity); required for non-loopback binds.",
"gateway.auth.password": "Required for Tailscale funnel.",

View File

@@ -17,8 +17,21 @@ export type WideAreaDiscoveryConfig = {
enabled?: boolean;
};
export type MdnsDiscoveryMode = "off" | "minimal" | "full";
export type MdnsDiscoveryConfig = {
/**
* mDNS/Bonjour discovery broadcast mode (default: minimal).
* - off: disable mDNS entirely
* - minimal: omit cliPath/sshPort from TXT records
* - full: include cliPath/sshPort in TXT records
*/
mode?: MdnsDiscoveryMode;
};
export type DiscoveryConfig = {
wideArea?: WideAreaDiscoveryConfig;
mdns?: MdnsDiscoveryConfig;
};
export type CanvasHostConfig = {

View File

@@ -272,6 +272,12 @@ export const ClawdbotSchema = z
})
.strict()
.optional(),
mdns: z
.object({
mode: z.enum(["off", "minimal", "full"]).optional(),
})
.strict()
.optional(),
})
.strict()
.optional(),