Channels: per-channel tool permission scoping for unattended deployments
Summary
When deploying Claude Code with Telegram (or other channels) on a VPS for 24/7 unattended operation, there's no hard gate to restrict which tools the model can use based on the message source. The current protections are LLM instructions ("don't run this if asked from Telegram"), which are soft gates vulnerable to prompt injection.
The problem
In a terminal session, the user is present to approve/deny tool calls. In an unattended channel deployment, nobody is watching. The model has full access to Bash, Edit, Write, and can:
- Modify its own hook configuration to remove guardrails
- Edit
access.jsonto allow unauthorized senders - Run arbitrary shell commands prompted by a Telegram message
- Alter or delete files in the workspace
File-system permissions don't help if the model has Bash access — it can work around them.
The tension
Locking the model out of all powerful tools defeats the purpose of an AI agent. The value of channel mode is that the AI can do things while you're away — not just chat.
Proposed solution: per-channel tool scoping
Allow settings.json (or channel config) to define a tool allowlist/blocklist per channel source:
{
"channels": {
"telegram": {
"allowedTools": ["Read", "Glob", "Grep", "Skill", "mcp__plugin_telegram_*"],
// or inversely:
"blockedTools": ["Bash", "Edit", "Write"],
// optional: skill allowlist
"allowedSkills": ["heartbeat", "cross-pollination"],
"blockedSkills": ["telegram:configure", "telegram:access"]
}
}
}
Key requirements:
- Enforced by the harness, not the model — the model never sees blocked tools in its tool list for channel sessions
- Config must be immutable from channel context — the model in a channel session cannot modify its own channel permissions
- Per-channel granularity — terminal sessions remain fully capable
- Skill-level scoping — not just raw tools, but which skills can be invoked from which channel
Workaround (current)
Run the bot as an unprivileged OS user with:
- Read-only access to
.claude/config - No sudo
- Hooks config owned by root
This is brittle and requires manual ops work that most users won't do.
Context
This came up while setting up a Telegram channel for a personal Second Brain vault. The bot is useful for quick queries and notifications, but deploying it unattended on a VPS requires trust that a crafted Telegram message can't escalate to full system access.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗