Doctor: warn on gateway exposure (#2016)
Co-authored-by: Alex Alaniz <Alex-Alaniz@users.noreply.github.com>
This commit is contained in:
@@ -6,7 +6,7 @@ Docs: https://docs.clawd.bot
|
|||||||
Status: unreleased.
|
Status: unreleased.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
- TBD.
|
- Doctor: warn on gateway exposure without auth. (#2016) Thanks @Alex-Alaniz.
|
||||||
|
|
||||||
## 2026.1.24-3
|
## 2026.1.24-3
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,61 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
|||||||
const warnings: string[] = [];
|
const warnings: string[] = [];
|
||||||
const auditHint = `- Run: ${formatCliCommand("clawdbot security audit --deep")}`;
|
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: {
|
const warnDmPolicy = async (params: {
|
||||||
label: string;
|
label: string;
|
||||||
provider: ChannelId;
|
provider: ChannelId;
|
||||||
|
|||||||
Reference in New Issue
Block a user