diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dfe96e6d..331a8d7e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Anthropic: merge consecutive user turns (preserve newest metadata) before validation to avoid incorrect role errors. - Messaging: enforce context isolation for message tool sends; keep typing indicators alive during tool execution. - Auto-reply: `/status` allowlist behavior, reasoning-tag enforcement on fallback, and system-event enqueueing for elevated/reasoning toggles. +- Auto-reply: explain how to enable `/bash` when it’s disabled; add security notes + FAQ. (#722) — thanks @vrknetha. - Auto-reply: resolve ambiguous `/model` matches; fix streaming block reply media handling; keep >300 char heartbeat replies instead of dropping. - Discord/Slack: centralize reply-thread planning; fix autoThread routing + add per-channel autoThread; avoid duplicate listeners; keep reasoning italics intact; allow clearing channel parents via message tool. - Telegram: preserve forum topic thread ids, persist polling offsets, respect account bindings in webhook mode, and show typing indicator in General topics. diff --git a/docs/start/faq.md b/docs/start/faq.md index 35e8b62f7..9b3820c0d 100644 --- a/docs/start/faq.md +++ b/docs/start/faq.md @@ -99,8 +99,9 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, - [Is it safe to expose Clawdbot to inbound DMs?](#is-it-safe-to-expose-clawdbot-to-inbound-dms) - [WhatsApp: will it message my contacts? How does pairing work?](#whatsapp-will-it-message-my-contacts-how-does-pairing-work) - [Chat commands, aborting tasks, and “it won’t stop”](#chat-commands-aborting-tasks-and-it-wont-stop) - - [How do I stop/cancel a running task?](#how-do-i-stopcancel-a-running-task) - - [Why does it feel like the bot “ignores” rapid‑fire messages?](#why-does-it-feel-like-the-bot-ignores-rapidfire-messages) +- [How do I stop/cancel a running task?](#how-do-i-stopcancel-a-running-task) +- [Why does `/bash` say it’s disabled?](#why-does-bash-say-its-disabled) +- [Why does it feel like the bot “ignores” rapid‑fire messages?](#why-does-it-feel-like-the-bot-ignores-rapidfire-messages) - [Common troubleshooting](#common-troubleshooting) - [“All models failed” — what should I check first?](#all-models-failed-what-should-i-check-first) - [I’m running on my personal WhatsApp number — why is self-chat weird?](#im-running-on-my-personal-whatsapp-number-why-is-self-chat-weird) @@ -1063,6 +1064,26 @@ Slash commands overview: see [Slash commands](/tools/slash-commands). Most commands must be sent as a **standalone** message that starts with `/`, but a few shortcuts (like `/status`) also work inline for allowlisted senders. +### Why does `/bash` say it’s disabled? + +The host shell command (`! ` or `/bash `) is **disabled by default** because it runs directly on the gateway host. To enable it, update your config and restart the Gateway: + +```json5 +{ + commands: { bash: true }, + tools: { + elevated: { + enabled: true, + allowFrom: { + "": [""] + } + } + } +} +``` + +Keep the allowlist tight and avoid enabling it in public rooms. See [Slash commands](/tools/slash-commands) and [Security](/gateway/security). + ### Why does it feel like the bot “ignores” rapid‑fire messages? Queue mode controls how new messages interact with an in‑flight run. Use `/queue` to change modes: diff --git a/docs/tools/elevated.md b/docs/tools/elevated.md index 85550d23c..ac1cf46be 100644 --- a/docs/tools/elevated.md +++ b/docs/tools/elevated.md @@ -12,6 +12,8 @@ read_when: - Directive forms: `/elevated on`, `/elevated off`, `/elev on`, `/elev off`. - Only `on|off` are accepted; anything else returns a hint and does not change state. +Security note: enabling elevated access or `/bash` effectively grants host shell access. Keep allowlists tight and avoid enabling it in public rooms. + ## What it controls (and what it doesn’t) - **Availability gates**: `tools.elevated` is the global baseline. `agents.list[].tools.elevated` can further restrict elevated per agent (both must allow). - **Per-session state**: `/elevated on|off` sets the elevated level for the current session key. diff --git a/docs/tools/slash-commands.md b/docs/tools/slash-commands.md index ff8d3a5e9..bbd9e6717 100644 --- a/docs/tools/slash-commands.md +++ b/docs/tools/slash-commands.md @@ -44,6 +44,7 @@ They run immediately, are stripped before the model sees the message, and the re - Set `discord.commands.native`, `telegram.commands.native`, or `slack.commands.native` to override per provider (bool or `"auto"`). - `false` clears previously registered commands on Discord/Telegram at startup. Slack commands are managed in the Slack app and are not removed automatically. - `commands.bash` (default `false`) enables `! ` to run host shell commands (`/bash ` is an alias; requires `tools.elevated` allowlists). +- When `commands.bash` is `false`, `/bash` replies with a short enablement hint (config keys + allowlist). - `commands.bashForegroundMs` (default `2000`) controls how long bash waits before switching to background mode (`0` backgrounds immediately). - `commands.config` (default `false`) enables `/config` (reads/writes `clawdbot.json`). - `commands.debug` (default `false`) enables `/debug` (runtime-only overrides). @@ -90,6 +91,10 @@ Notes: - **Inline shortcuts (allowlisted senders only):** `/help`, `/commands`, `/status` (`/usage`), `/whoami` (`/id`) also work when embedded in text. - Unauthorized command-only messages are silently ignored, and inline `/...` tokens are treated as plain text. +## Security note: `!` / `/bash` + +`! ` and `/bash ` run **directly on the gateway host** as the gateway user. Keep this disabled unless you fully trust the sender and have locked down allowlists. Treat it like giving someone SSH access to the host. + ## Usage vs cost (what shows where) - **Provider usage/quota** (example: “Claude 80% left”) shows up in `/status` when provider usage tracking is enabled. diff --git a/src/auto-reply/reply/bash-command.ts b/src/auto-reply/reply/bash-command.ts index 3ea545199..06ff7bd6d 100644 --- a/src/auto-reply/reply/bash-command.ts +++ b/src/auto-reply/reply/bash-command.ts @@ -155,6 +155,30 @@ function buildUsageReply(): ReplyPayload { }; } +function buildBashDisabledReply(provider?: string): ReplyPayload { + const providerKey = provider?.trim().toLowerCase() || ""; + return { + text: [ + "⚠️ /bash is disabled (default).", + "Enable it in your config (host-only; trusted senders only):", + "```json5", + "{", + " commands: {", + " bash: true", + " },", + " tools: {", + " elevated: {", + " enabled: true,", + ` allowFrom: { "${providerKey}": [""] }`, + " }", + " }", + "}", + "```", + "Restart the Gateway after updating config.", + ].join("\n"), + }; +} + function formatElevatedUnavailableMessage(params: { runtimeSandboxed: boolean; failures: Array<{ gate: string; key: string }>; @@ -199,9 +223,13 @@ export async function handleBashChatCommand(params: { }; }): Promise { if (params.cfg.commands?.bash !== true) { - return { - text: "⚠️ bash is disabled. Set commands.bash=true to enable.", - }; + logVerbose("Blocked /bash: commands.bash is disabled."); + const provider = + params.ctx.Provider ?? + params.ctx.Surface ?? + params.ctx.OriginatingChannel ?? + undefined; + return buildBashDisabledReply(provider ?? undefined); } const agentId =