The Index

Fundamentals

Discord bot security, explained

Discord bot security as four checkable practices — token handling, requested permissions, privileged intent review and two-factor enforcement.

Key
FN-004
Section
Fundamentals
Read
6 min
Checked
31 August 2026

Discord bot security is not one practice — it is four separate, checkable ones that get treated as a single vague instruction to “be careful” far too often: protecting the token, requesting the minimum permissions and intents a feature needs, passing privileged-intent review at the right size, and accounting for two-factor requirements a server can impose on anything it adds.

The token is the whole account

Discord’s own developer guidance is blunt about what a bot token actually is: “used to authorize API requests and carry your app’s permissions, so they are highly sensitive.” A leaked token is not a partial compromise — whoever holds it can act as the bot completely, with every permission the bot has been granted anywhere it is installed.

The practical rules follow directly from that: never commit a token to version control, store it in an environment file that is itself excluded from version control, and treat a password manager as the right place for a backup copy rather than a chat message or a shared document. If a token is ever exposed — a public repository, a pasted log, a screen-shared terminal — the only correct response is regenerating it immediately. Regeneration invalidates the old token everywhere it was in use, which means every legitimate deployment needs the new one before the old one is revoked, not after.

Request only what the bot actually uses

Every permission bit in an invite URL and every intent declared at identify is a capability the bot can exercise, whether or not any shipped feature uses it. Two separate reference points on this site cover the mechanics in depth — gateway intents for the data a bot receives, OAuth2 scopes for what an authorization grants — and the security implication of both is the same: a wider request is a wider blast radius if the token is ever compromised, and it is friction the server administrator evaluating the invite has to reason through for no functional benefit if the bot does not actually use what it asked for.

bot_require_code_grant is the setting that raises that friction on purpose. With it enabled, a server administrator cannot use the simplified one-click bot invite — they are routed through the full OAuth2 authorization code flow instead, an explicit extra confirmation step. It trades install convenience for a deliberate pause, and it is the right trade for an application whose bot permission set is broad enough that a casual one-click add is the wrong amount of friction for what is being granted.

Privileged intents are a review gate, not a checkbox

GUILD_MEMBERS, GUILD_PRESENCES and MESSAGE_CONTENT can be switched on directly in a small app’s settings, and that self-service option disappears once the app is visible to more than 10,000 unique users across every server it is in — at that point, continued access requires Discord’s review. A privileged intent used without approval does not degrade gracefully: the gateway connection closes outright with code 4014, which is a hard stop for every feature that depends on it, not a warning.

The security dimension here is less about the review process itself and more about what it forces: an application requesting MESSAGE_CONTENT is asking to read message text across every server it joins, and the review exists because that is meaningfully sensitive data to hold at scale. Treating the review as a bureaucratic hurdle rather than the actual point misses why it is there.

The same logic applies to what an approved application then does with the data, even though Discord’s review process itself stops at the approval decision. A privileged intent granted for one feature is not a blanket license to retain everything it can now see — the security-conscious version of this practice logs and stores only what a shipped feature actually needs, for only as long as that feature needs it, rather than treating approval as permission to accumulate data indefinitely simply because access exists.

Two-factor authentication is enforced on the bot owner, not just the bot

A server with server-wide two-factor authentication enabled will not admit a bot requesting elevated permissions unless the bot’s owning account itself has 2FA turned on. This is easy to miss because it never surfaces during development — a test server without that setting enabled will never trigger it — and then blocks an install attempt on exactly the kind of security-conscious server most likely to be a good, careful adopter of a new bot.

The permission a bot requests is not the only lever available

A bot’s OAuth2 permission bitmask sets the ceiling — nothing it does can exceed what was granted at invite. Below that ceiling, a well-built platform gives its own operators a second, finer-grained lever: deciding which of the bot’s own commands a given role may invoke, independent of whether that role holds the underlying Discord permission at all. Vetox’s Command Management works at exactly that layer — a role can be granted /warn-add without holding Moderate Members anywhere in the server, because the gate is enforced in the bot’s own command handling rather than by mirroring Discord’s permission system. It does not change what the bot itself was granted at invite; it changes who inside the server can trigger which slice of it, which is the same least-privilege principle Discord’s own permission and intent model applies, moved one layer down to the people using the bot rather than the bot itself.

A webhook URL is a bearer credential too, just a smaller one

Token security gets the attention because a bot token is the whole account. A webhook URL deserves close to the same discipline and rarely gets it, because it looks like a plain link rather than a credential. It is not — a Discord webhook URL carries its own authorization inline, and anyone who has it can post to that specific channel with no further authentication at all. There is no separate secret to also protect; the URL is the secret.

The practical consequence is the same class of mistake that makes bot tokens dangerous in version control, at smaller scale: a webhook URL pasted into a public repository, a shared config file, or a support ticket is immediately usable by whoever finds it, to post as that integration in that channel, until the webhook is deleted and recreated. Because a webhook is scoped to one channel rather than a whole bot’s permission set, the blast radius of a leak is narrower than a token leak — which is a reason to treat webhook URLs with real but proportionate care, not a reason to treat them as harmless. An integration posting automated content — a notification feed, a status alert, a cross-server relay — that stores its webhook URL with the same discipline the bot token gets is protecting a smaller surface with the same habit, which is cheaper than learning the distinction only after a channel starts receiving posts nobody on the team sent.

What this means in practice

Treat the token as equivalent to the account’s password, because functionally it is one — store it outside version control, and regenerate without hesitation the moment exposure is even suspected. Request permissions and intents against the actual shipped feature set, and revisit both when a feature using one is removed. Track unique-user reach, not server count, as the trigger for privileged-intent review, and start that process before the 10,000 threshold rather than after a connection starts closing with 4014. And test an install against a server with 2FA enforced at least once before assuming the invite flow works everywhere it will actually be used.

Sources

Checked

  1. Discord Developer Documentation — Getting Started (opens in a new tab)
  2. Discord Developer Documentation — OAuth2 (opens in a new tab)
  3. Discord Developer Documentation — Gateway (opens in a new tab)
  4. docs.vetox.io — Command Management (opens in a new tab)

How we verify