Doctor: warn on gateway exposure (#2016)

Co-authored-by: Alex Alaniz <Alex-Alaniz@users.noreply.github.com>
This commit is contained in:
Shadow
2026-01-25 20:01:38 -06:00
parent 8f6542409a
commit 5c231fc21f
2 changed files with 56 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ Docs: https://docs.clawd.bot
Status: unreleased.
### Changes
- TBD.
- Doctor: warn on gateway exposure without auth. (#2016) Thanks @Alex-Alaniz.
## 2026.1.24-3

View File

@@ -10,6 +10,61 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
const warnings: string[] = [];
const auditHint = `- Run: ${formatCliCommand("clawdbot security audit --deep")}`;
// ===========================================
// GATEWAY NETWORK EXPOSURE CHECK
// ===========================================
// Check for dangerous gateway binding configurations
// that expose the gateway to network without proper auth
const gatewayBind = cfg.gateway?.bind ?? "loopback";
const customBindHost = cfg.gateway?.customBindHost?.trim();
const authMode = cfg.gateway?.auth?.mode ?? "off";
const authToken = cfg.gateway?.auth?.token;
const authPassword = cfg.gateway?.auth?.password;
const isLoopbackBindHost = (host: string) => {
const normalized = host.trim().toLowerCase();
return (
normalized === "localhost" ||
normalized === "::1" ||
normalized === "[::1]" ||
normalized.startsWith("127.")
);
};
// Bindings that expose gateway beyond localhost
const exposedBindings = ["all", "lan", "0.0.0.0"];
const isExposed =
exposedBindings.includes(gatewayBind) ||
(gatewayBind === "custom" && (!customBindHost || !isLoopbackBindHost(customBindHost)));
if (isExposed) {
if (authMode === "off") {
warnings.push(
`- CRITICAL: Gateway bound to "${gatewayBind}" with NO authentication.`,
` Anyone on your network (or internet if port-forwarded) can fully control your agent.`,
` Fix: ${formatCliCommand("clawdbot config set gateway.bind loopback")}`,
` Or enable auth: ${formatCliCommand("clawdbot config set gateway.auth.mode token")}`,
);
} else if (authMode === "token" && !authToken) {
warnings.push(
`- CRITICAL: Gateway bound to "${gatewayBind}" with empty auth token.`,
` Fix: ${formatCliCommand("clawdbot doctor --fix")} to generate a token`,
);
} else if (authMode === "password" && !authPassword) {
warnings.push(
`- CRITICAL: Gateway bound to "${gatewayBind}" with empty password.`,
` Fix: ${formatCliCommand("clawdbot configure")} to set a password`,
);
} else {
// Auth is configured, but still warn about network exposure
warnings.push(
`- WARNING: Gateway bound to "${gatewayBind}" (network-accessible).`,
` Ensure your auth credentials are strong and not exposed.`,
);
}
}
const warnDmPolicy = async (params: {
label: string;
provider: ChannelId;