Threat model in five questions
- What can the token do? Read every message? Post in every channel? Ban members? That is the blast radius of a leak.
- Who can talk to the bot? Anyone on the internet, members of one server, employees?
- What does the bot touch? Databases, payment APIs, internal systems, the filesystem, URLs supplied by users.
- What data does it keep? Messages, phone numbers, files, AI conversations.
- How would you know it was abused? Logs, alerts, unusual volume.
Secrets
- Keep tokens in environment variables loaded from a secret manager (Workers secrets, cloud secret managers, Vault, encrypted CI secrets). Never in source code, Docker images, client-side code or screenshots.
- Use separate tokens for development and production, ideally separate bots.
- Scan repositories and CI logs with Gitleaks, TruffleHog or GitHub secret scanning; run the token helper before pasting logs anywhere.
- Rotate on any suspicion and after people with access leave. Know the rotation steps for each platform before you need them.
- Encrypt per-tenant tokens (for example Slack OAuth tokens per workspace) at rest.
Least privilege
- Request the minimum Discord permissions and intents, Slack scopes and Meta permissions. Never request Administrator "to be safe".
- Give the bot's database user only the tables it needs.
- Run the process as an unprivileged user in a read-only filesystem where possible.
Verify everything that arrives
- Verify webhook signatures or secret headers on every request (see APIs and webhooks).
- Reject stale timestamps to prevent replays.
- Do not expose admin or debug endpoints on the same public host without authentication.
Authorization
The most common logic bug in bots is a missing permission check.
- Identify users by stable numeric IDs, never by display name or username, which can be changed or spoofed.
- Check authorization on every command and every button click, not only when the button was shown.
- In group chats, verify admin status with the platform API at the time of the action.
- Scope data access to the requesting user or tenant in the query itself:
WHERE tenant_id = ?.
Treat input as hostile
- Injection: use parameterized queries; never build SQL, shell commands or file paths from message text.
- Markup: escape user text before inserting it into HTML, Markdown, Block Kit or embeds; set
allowed_mentionson Discord so nobody can make the bot ping everyone. - Regular expressions: limit input length and avoid catastrophic patterns (test with the regex tester).
- Commands: allow-list subcommands and argument formats.
SSRF: when the bot fetches URLs
Link previews, "summarize this page" and image tools fetch URLs that users supply. An attacker can point them at http://169.254.169.254/ (cloud metadata), localhost admin panels or internal services. Defend by:
- Allowing only
httpandhttps, and resolving the hostname yourself to block private, loopback and link-local ranges (re-check after redirects). - Setting short timeouts, size limits and a redirect limit.
- Running fetchers in an isolated network without access to internal systems.
Files
Check size and type by content, not extension; store uploads outside the web root with random names; scan them if you serve them to others; and never execute or unzip untrusted archives without limits.
AI-specific risks
Prompt injection can turn any text into instructions. Enforce permissions in code, require confirmation for consequential actions, keep secrets out of prompts, and sanitize model output before rendering. Details in AI chatbots and agents.
Logging and privacy
Log event IDs, types, user ID hashes, outcomes and latency. Do not log tokens, full message bodies, phone numbers or AI conversations unless you have a reason and a retention period. Make /delete or /stop actually delete data.
Supply chain
Pin dependencies with a lockfile, enable Dependabot or equivalent, prefer well-maintained libraries, and review install scripts. A malicious package in a bot's dependency tree can exfiltrate its token on the first run.
Incident response
- Revoke the token or webhook URL immediately and deploy a new one.
- Contain: disable the affected commands or take the bot offline.
- Investigate: what did the token do during the exposure window? Check the platform audit logs.
- Notify affected server owners or users if their data was exposed, and follow legal obligations.
- Fix the cause and add a test or a scan that would have caught it.