Soundboard
Keep default and guild soundboard inventory behind its own audit toggle, and keep guild reads behind an exact guild allowlist. Project Discord responses immediately to bounded stable metadata, tagged emoji state, exact creator IDs, unknown-field counts, and complete ownership-aware permission evidence. Never return audio bytes, CDN URLs, creator profiles, raw objects, or unknown values. Require complete guild, bot-member, role, permission, and inventory evidence before returning a guild read or plan.
Keep every create, metadata update, and delete behind the independent change toggle, process-keyed planning, signed interactive confirmation, write-aware host approval, final fresh-plan match, atomic one-shot operation-key reservation, pending content-free activity, one non-retried mutation, and exact metadata or absence readback. Discord requires CREATE_GUILD_EXPRESSIONS for creation. Updating or deleting a sound requires either MANAGE_GUILD_EXPRESSIONS or exact bot ownership together with CREATE_GUILD_EXPRESSIONS. Do not add an immediate change call, bulk mutation, fuzzy lookup, automatic retry, rollback, or reconciliation. The change workflow must never accept playback fields or play audio.
Keep playback behind its own independent capability, exact ordinary voice-channel allowlist, and exact custom-sound source-guild allowlist. A null source may select only one exact sound from Discord's default inventory. A custom source must remain inside both local guild read scope and the dedicated source scope. Never infer a source guild, accept a name as identity, widen target scope from a guild, parent, inventory, or other soundboard capability, or let sound creation and administration grant playback.
Both the readiness check and the write must freshly verify the pinned application and bot, exact target channel and guild, ordinary voice type, complete channel overwrites, connector membership and roles, exact available sound, and the bot's exact current connection to that voice channel. Require complete VIEW_CHANNEL, CONNECT, SPEAK, and USE_SOUNDBOARD evidence, plus USE_EXTERNAL_SOUNDS when the custom sound comes from another guild. Server mute, server deaf, self-deaf, suppression, disconnected state, unknown evidence, malformed fields, absent sounds, and unavailable sounds must fail closed. The connector does not join a voice channel; an independently managed bot voice session must already be connected to the exact target.
Playback is a guarded non-destructive write, not a reviewed destructive workflow. Require MCP host write approval, a request-bound one-shot operation key, durable exact-channel coordination across connector processes, the shared interaction limiter, an atomic pending receipt, and pending content-free activity before one non-retried exact-ID POST. Accept only Discord's strict empty success. An exact VOICE_CHANNEL_EFFECT_SEND event for the same guild, channel, bot, and sound may corroborate success, but every non-target event must be discarded without entering the general event feed and no Gateway event may override an ambiguous REST result. A deterministic client rejection may be failed; rate limiting, request timeout, transport ambiguity, server failure, malformed success, and record-finalization failure remain uncertain with the key spent and exact channel claim quarantined.
A completed matching operation-key replay must return only from the durable receipt without repeating Discord reads or playback. A mismatched, pending, failed, uncertain, or malformed receipt must conflict rather than replay. Never persist sound or channel names, voice profiles or state, roles, overwrites, permission evidence, Gateway payloads, raw operation keys, or transport causes. Playback activity and operation records may contain only exact guild, channel, sound, and optional source-guild IDs, request digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category.
Creation must accept only one bounded canonical owned local MP3 or Ogg file under a dedicated soundboard root. Never accept a remote URL, Discord CDN reference, data URL, base64 payload, arbitrary byte field, stream, directory, multiple files, or runtime-configurable Discord origin. Reject path escapes, symlinks, hardlinks, foreign ownership, unstable reads, unsupported codecs or containers, invalid MP3 frames, invalid Ogg checksums or sequences, chained or multiplexed Ogg streams, audio above 512 KiB, and duration outside the supported range before reservation. Upload only the reviewed byte snapshot bound into the fresh plan.
Normalize names, bounded volume, exact IDs, and a tagged custom, Unicode, or absent emoji choice. Resolve a requested custom emoji by exact ID in the target guild. Fail closed on absent update targets, normalized-name collisions, missing or unavailable custom emoji, incomplete permissions, local safety capacity, unknown target fields, malformed Discord evidence, changed file state, stale plans, and a prior uncertain same-guild outcome. A no-op update or already absent deletion must reserve nothing, journal nothing, request no confirmation, and issue no write.
Bind the normalized request, verified identities, exact guild and complete inventory, relevant roles, permission and ownership evidence, current and desired metadata, custom emoji evidence, privacy projection, local audio state, warnings, and domain-separated operation-key hash into the plan. Exclude the raw operation key from plan material, signed request state, records, results, and errors. Treat a known pre-write Discord client error as failed. Treat transport errors, malformed mutation responses, Discord server errors, failures after mutation, failed readback, and failed receipt finalization as uncertain and potentially completed. Never claim stored byte equality because Discord does not return sound audio for readback.
Serialize soundboard changes per guild inside one process as defense in depth. The production facade also acquires a durable exact guild soundboard-collection claim, so connector processes sharing the activity-state root exclude overlapping changes and retain the claim after uncertainty. Never persist names, emoji, role names, local paths, file metadata, audio bytes, content digests, creator profiles, audit reasons, raw operation keys, permission evidence, or raw Discord responses. Activity and operation records may contain only exact guild and optional sound IDs, action, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category.
Canonical source: SECURITY.md
Documentation generated for guildcontrol@0.0.0. Canonical source and edit history remain in the public repository. GuildControl is an independent project and is not affiliated with or endorsed by Discord Inc. Discord is used only to identify the platform that GuildControl connects to.