Lock down an OpenClaw bot before you add it to a group chat
Who can trigger your OpenClaw bot, what it reads and what it may do: allowlists, mention gating, context filters, tool limits and approvals.
· ranx.cloud

The moment an OpenClaw agent sits in a WhatsApp group, a Slack channel or a Discord server, other people can put text in front of a model that may be able to fetch URLs, write files and run shell commands. This post goes through the settings that decide who can trigger it, what it reads, and what it's allowed to do, and gives a config you can paste into Settings → Advanced → Raw. It's for anyone who set up a personal assistant and is about to invite it somewhere with other people.
The OpenClaw security docs put it plainly: prompt injection doesn't need public DMs. Any untrusted content the agent reads, including a quoted message, a web page or an attachment, can carry instructions. So access control is one layer, and you also need to limit what a successful injection can do.
Layer 1: who can trigger a turn
Every channel has the same two knobs (groups, pairing):
dmPolicy:pairing(default),allowlist,open,disabled.groupPolicy:allowlist(the default once the channel block exists),open,disabled, plus a per-channel map of which rooms count and who in them may trigger the bot.
The safe pattern for a shared room is an explicit room list, an explicit sender list, and a required mention:
{
channels: {
whatsapp: {
dmPolicy: "allowlist",
allowFrom: ["+15551234567"],
groupPolicy: "allowlist",
groupAllowFrom: ["+15551234567", "+15557654321"],
groups: { "120363012345678901@g.us": { requireMention: true } },
},
discord: {
dmPolicy: "pairing",
groupPolicy: "allowlist",
guilds: {
"123456789012345678": {
requireMention: true,
users: ["987654321098765432"],
roles: ["112233445566778899"], // role IDs, needs Server Members Intent
},
},
},
slack: {
groupPolicy: "allowlist",
channels: { C01ENGINEER: { requireMention: true } },
},
},
}
Details that matter:
- Use IDs, not names. Slack and Discord resolve names to IDs at startup, and inbound authorization is ID-first. Matching on raw names needs
dangerouslyAllowNameMatching: true, and the name says what it is: display names can be changed by their owners. - A reply is not a permission. Replying to the bot satisfies the mention requirement in WhatsApp, but a sender outside the allowlist is still blocked.
- Pairing approvals don't extend to groups. The Approve DM access dialog says so directly: "It does not grant group access."
- Owners are separate from allowed senders.
commands.ownerAllowFromdecides who can run owner-only commands and approve risky actions from chat. Being onallowFromdoesn't make someone an owner. Keep the owner list to yourself.
The UI also limits pairing on its own. Requests expire after an hour, and each channel account holds at most three pending requests, so a stranger who finds the bot can't build up a backlog.
Layer 2: what the model reads
An allowlist controls who can trigger a turn, not what ends up in the prompt. By default OpenClaw keeps supplemental context as received: quoted messages, thread history, forwarded content, and in WhatsApp up to 50 buffered group messages since the bot last spoke. A non-allowlisted member can't trigger the bot, but their message can sit in the history an allowlisted person's mention pulls in.
contextVisibility filters that:
{
channels: {
defaults: { contextVisibility: "allowlist_quote" },
whatsapp: { historyLimit: 10 },
},
}
| Mode | Context included |
|---|---|
all (default) |
Everything as received |
allowlist |
Only history/thread/quote context from allowlisted senders |
allowlist_quote |
Same, plus the one message explicitly replied to |
This applies to WhatsApp, Slack, Discord, Signal, Telegram and several others (docs). Also turn off /reasoning, /verbose and /trace in shared rooms. They can echo tool arguments and fetched content back into the chat.
Layer 3: what the agent can do
This is the layer that limits damage. Two facts make it urgent on a cloud host:
- If
tools.profileis unset, core tools are unfiltered (tool policy). For gateway hosts,exec.securitydefaults tofullandexec.asktooff(exec approvals). - Sandboxing is off by default and needs a backend: Docker or Podman locally, or a remote SSH or OpenShell machine. With no sandbox,
execruns in the gateway's own environment, next toopenclaw.jsonand its stored channel tokens.
So decide per room what the agent may do. A reasonable split is full tools in your own DMs and the Control UI, and messaging plus web search in groups, with shell and file writes off:
{
channels: {
whatsapp: {
groups: {
"*": { tools: { deny: ["exec", "process", "write", "edit", "apply_patch", "browser"] } },
},
},
discord: {
guilds: {
"123456789012345678": {
tools: { deny: ["exec", "process", "write", "edit", "apply_patch", "browser"] },
toolsBySender: {
"id:987654321098765432": { alsoAllow: ["exec"] }, // you, in your own server
},
},
},
},
},
}
Be careful with the WhatsApp "*" key. In channels.whatsapp.groups it also admits every group. If you keep a strict group list, repeat the tools block on each listed group instead.
toolsBySender gives one person more tools in a shared room. The docs add a caveat (hardened baseline): sender-scoped tools follow the person who triggered the turn, not everyone whose text is in the prompt. If you trigger a turn whose history contains a hostile message, that message runs with your tools. Pair toolsBySender with contextVisibility: "allowlist".
For a quick global baseline, the docs offer a hardened profile you can start from and loosen:
{
tools: {
profile: "messaging",
deny: ["group:automation", "group:runtime", "group:fs", "sessions_spawn", "sessions_send"],
fs: { workspaceOnly: true },
exec: { security: "deny", ask: "always" },
elevated: { enabled: false },
},
session: { dmScope: "per-channel-peer" },
}
dmScope: "per-channel-peer" gives each DM sender their own session. One person's conversation, and anything injected into it, doesn't carry over into another person's.
Layer 4: approvals where you'll see them
If you do allow exec, make it ask first, and send the prompt somewhere you'll notice:
{
tools: { exec: { security: "allowlist", ask: "on-miss" } },
channels: {
discord: { execApprovals: { enabled: true, approvers: ["987654321098765432"], target: "dm" } },
slack: { execApprovals: { enabled: true, approvers: ["U01AAAAAAA"], target: "dm" } },
},
approvals: { exec: { enabled: true, mode: "session" } },
}
Discord and Slack render native approval buttons that only the listed approvers can use. In WhatsApp, approvals for WhatsApp-originated requests show up as thumbs-up and thumbs-down reactions, and the approvers must be in allowFrom. If no approver responds, the default askFallback is deny. Resolved approvals are listed for 30 days under Settings → Approvals, with who decided and from which session.
Skills are code
ClawHub, the public skills registry, had a large malware campaign in early 2026. Koi Security found 341 malicious skills among the 2,857 it audited, and later counts went past 1,000 (Snyk's write-up, AI Incident Database). ClawHub now shows each skill's scan status (VirusTotal, ClawScan, static analysis) before install. The OpenClaw skills docs still say to treat third-party skills as untrusted code and read them before enabling.
Practical rule: install skills from the Skills page only after reading the skill's files, prefer publishers you recognise, and don't install skills on an agent that also sits in a group chat with tools enabled.
Costs
Most of this is free. Two settings change spend:
contextVisibility: "allowlist"and a lowerhistoryLimitreduce input tokens per group turn. Cutting 40 buffered messages of roughly 50 tokens each saves about 2,000 input tokens a turn, which is $0.004 per turn on Claude Sonnet 5.5 at $2 per million input tokens (pricing, November 2026). Small per turn, but it adds up in a busy group.- Model choice is a security setting too. The OpenClaw docs tell you not to put smaller or older models on tool-enabled agents that read untrusted input. Haiku 5.5 at $0.10/$0.50 per million is fine for a chat-only bot with tools off. Once tools are on and strangers can post, pay for the stronger model.
What goes wrong
The bot answers someone you didn't approve. Usually groupPolicy: "open" was set while testing, or groups["*"] admitted every group and the sender list fell back to a wildcard. Check the channel's card in Settings → Channels, which shows the effective policy, then the raw config for duplicate keys. In JSON5 the later key silently wins.
History injection. An attacker who can't trigger the bot posts instructions, then waits for an allowed user to mention it. The fix is contextVisibility plus historyLimit. A past advisory (GHSA-chfm-xgc4-47rj) showed the same pattern through Microsoft Teams thread history.
Name-based allowlists. A third-party advisory argued that identity matched on mutable display names can be spoofed. OpenClaw now matches on IDs by default. Keep dangerouslyAllowNameMatching off.
Approvals never arrive. execApprovals.enabled is set but no approver resolves (wrong ID, or no approvers and no commands.ownerAllowFrom), so requests fall through to deny. Check Settings → Approvals history for the recorded reason.
Two bots in a loop. Discord and Slack accept bot-authored messages by default (allowBots: true). In a room with another bot, set allowBots: "mentions" or false, or configure channels.defaults.botLoopProtection.
A built-in shell in the Control UI. The Control UI has an operator terminal that opens a shell on the gateway host for connections with admin access (panels docs). It's on by default. Treat Control UI access as shell access, and give other people chat access through their messaging account rather than the Control UI. If you never use the terminal, gateway.terminal.enabled: false turns it off without a restart. On ranx.cloud only the instance's owner can open the Control UI, by signing in with their ranx.cloud account, and the terminal's shell runs inside that instance's own container.
Checklist
- Every channel:
dmPolicyispairingorallowlist. Noopen. - Every shared room: listed by ID,
requireMention: true, explicit senders. channels.defaults.contextVisibilityisallowlistorallowlist_quote.- Group rooms deny
exec,process, file writes andbrowser. commands.ownerAllowFromlists only you.- Exec approvals go to a DM you read.
- Third-party skills only after you've read them.


