| title | Security |
|---|---|
| description | Permission gates, BotStaff ACL, setup authorization, and ticket close rules for doubt-bot |
Guild slash commands use discordx guards and Discord permission checks where implemented:
| Surface | Gate |
|---|---|
/setup |
@Guard(ManageGuildOnly) — Manage Server |
/rank reset, /rank set |
Runtime check for Manage Server |
| Setup components (welcome, tickets, JTC) | denyUnlessManageGuild() in src/utils/setupGuard.ts |
Other commands (economy, /ping, /help, /afk, …) do not set Discord default_member_permissions unless added in future ports.
Restart the bot after deploying code that changes slash metadata so bot.initApplicationCommands() on ready re-syncs guild commands.
/eval and other legacy devOnly utilities from Doubt-Discord-Bot are not shipped in doubt-bot yet. When ported, they should remain developer-only (DEVELOPER_DISCORD_IDS) and run inside a restricted VM sandbox (timeout, blocked identifiers such as process, require, fs, child_process, …) — matching the legacy safeEval.js behavior.
Until eval is ported, do not expose arbitrary code execution on production bots.
Keep `DEVELOPER_DISCORD_IDS` limited to trusted operator accounts.Ticket close is enforced in src/utils/ticketAuth.ts and the ticket-close button handler.
A member may close a ticket only if any of the following is true:
- They have Manage Channels on the guild.
- They have the configured ticket staff role (
Setup.ticketStaffRoleId). - They are the ticket opener (their user ID has an allow View Channel overwrite on the ticket channel).
Everyone else receives an ephemeral denial. Opening a ticket uses the panel select menu and modal (ticket-modal); members who can see the panel can open a ticket subject to the one-open-ticket check.
/setup requires Manage Server via ManageGuildOnly.
Follow-up setup interactions call denyUnlessManageGuild() on welcome, ticket, and JTC components. The helper setupComponentFilter() exists to bind collectors to the initiating user where message collectors are used; welcome message text is collected through a modal, not a MessageCollector.
Staff-only commands use @Guard(StaffOnly) in src/guards/accessGuards.ts. Privilege is checked with canUseStaffCommands() in src/services/botStaffService.ts against PostgreSQL — not guild roles.
| Layer | Role |
|---|---|
BotStaff Postgres table (discordId) |
ACL — who may pass StaffOnly |
DEVELOPER_DISCORD_IDS |
Developers always pass staff gates |
bot-staff badge (UserBadge → reserved Badge) |
Display-only; never grants command access |
The reserved badge key is bot-staff. /badge rejects reserved keys and lookalikes (bot_staff, botstaff, …). Management is via /botstaff (developers only).
StaffOnly denies users who are neither developers nor in BotStaff. There is no fallback to legacy moderation.staffRoles.
If BotStaff is empty, staff-only commands fail until operators run /botstaff add or import rows via yarn migrate:mongo.
Only developers (DeveloperOnly guard) may run /botstaff add, remove, list, or migrate. Each add records addedBy and addedAt; removals write BotStaffRemoval audit rows.
yarn prisma:migrate:deployon the target database.- Import staff (Mongo migrator and/or
/botstaff add). - Run
/botstaff migrateif badge display is out of sync. - Verify with
/botstaff list.
/badge subcommands are @Guard(StaffOnly) — bot staff or developers. Reserved badges cannot be created, updated, or deleted through /badge. Granting the 🛡️ mark for staff is always through /botstaff, not manual badge grants.
| Surface | Primary gate |
|---|---|
/setup and setup components |
Manage Server (ManageGuildOnly / denyUnlessManageGuild) |
| Ticket close button | Opener, ticket staff role, or Manage Channels |
/botstaff |
Developer allowlist |
StaffOnly commands (e.g. /badge) |
Developer allowlist or BotStaff Postgres ACL |
Reserved bot-staff badge |
Locked in /badge; synced via /botstaff |
/eval (legacy) |
Not available on doubt-bot until ported |
Regression tests in doubt-bot assert the client intent list excludes Message Content. AFK uses mention metadata only (src/events/afkCheck.ts). Do not enable Message Content Intent for standard deployments.