Skip to content

Security: antonskv/claude-telegram-interface

Security

SECURITY.md

Security

claude-telegram-interface connects a Telegram chat to a Claude Code CLI running on your machine with access to a directory you choose. Treat it as what it is: a remote doorway to a capable agent. Read this before exposing it.

Threat model in one line

The bot has no inbound network surface (it long-polls Telegram; it opens no ports). The only way to reach the agent is to send the bot a Telegram message and have your numeric user id on the allowlist. The allowlist is the only door.

The allowlist is the only door

  • allowed_user_ids in config.toml is the sole authentication boundary. A message from any id not on that list is silently dropped — the sender gets no reply and no signal the bot exists.
  • There are no roles, no per-user scoping, no identity attestation beyond the Telegram user id. Keep the list to ids you control.
  • Anyone on the allowlist can make the agent do anything the agent can do in working_dir. Only list yourself (and people you fully trust at that level).
  • Your Telegram account IS the key. The gate authenticates the Telegram user id — it cannot tell you from someone logged in as you. A compromised Telegram account on the allowlist is a compromised agent. Protect the account itself (enable Telegram's two-step verification).
  • Keep it 1:1. Don't add the bot to group chats, and treat its chat like a shell prompt on your machine — because that is what it is.

What the agent can do — and the optional write-jail

By default the spawn runs in Claude Code's normal permission mode. If you set bypass_permissions = true, the headless spawn runs with --permission-mode bypassPermissions, so it can execute tools (bash, git, file writes) without interactive approval. That is powerful and dangerous.

For that reason bypass_permissions is interlocked: the bot refuses to start with bypass on unless a write-jail is in place (see config.py) — on macOS a sandbox_profile, on Linux linux_confined = true (and never as root).

  • macOS: point sandbox_profile at a Seatbelt profile (see examples/example.sb) that confines writes to your working_dir (plus ~/.claude, which --resume needs, and temp dirs).
  • Linux: there is no Seatbelt; the confinement layer is systemd. The unit in deploy/ runs the bot as an unprivileged user with ProtectSystem=strict + scoped ReadWritePaths — the kernel confines writes to the working dir and agent state dirs, reproducing the macOS boundary. linux_confined = true is your attestation that this unit is actually in place (the engine cannot verify systemd from inside; it does verify it is not running as root). Don't set it outside that unit.
  • The jail is write-only by design: reads, exec, network, and credentials (Keychain on macOS) stay open, so credential-based helper CLIs keep authenticating. It guards against an unintended write outside your project — not against network egress.

Secrets: your bot token

  • The bot token lives only in config.toml, which is gitignored. Never commit it. Use config.example.toml (placeholder token) for samples.

  • A portable pre-commit secret gate is included at scripts/pre-commit-secret-gate.sh. It blocks committing a real config.toml or any Telegram-token-shaped string. Install it in your clone:

    cp scripts/pre-commit-secret-gate.sh .git/hooks/pre-commit
    chmod +x .git/hooks/pre-commit

    The hook is client-side and --no-verify-bypassable — it stops accidents, not a determined push. For a server-side guarantee, enable GitHub push protection (Secret scanning) on the repo.

  • If a token ever leaks, rotate it immediately via @BotFather (/revoke or /token).

Reporting

This is a small personal project. Open an issue for security concerns; do not include real tokens, ids, or paths in the report.

There aren't any published security advisories