Skip to content

Exact-recipient direct messages

Keep one-to-one private messaging behind the dedicated direct-messages toolset, independent audit, delivery, owned-file attachment, editing, and deletion gates, and a bounded exact ordinary-user allowlist. The exact allowlist expresses only local operator authority; it is not evidence of recipient consent, prior contact, or Discord-side eligibility. Private-file delivery must additionally require ordinary delivery authority and at least one configured canonical attachment root; guild attachment authority and private attachment authority never imply each other. Never add recipient discovery, username lookup, private-channel enumeration, group DMs, bulk recipients, shared-bot relay, ambient scope inheritance, or DM Gateway ingestion. The operator must supply and pin their own Discord application, bot identity, and secret token.

Reads must require a caller-known exact recipient and exact one-to-one channel, plus an exact message ID for lookup. Re-verify the pinned application and bot, channel type, sole recipient, participant boundary, exact response identity, supported message type, timestamps, content, reply identity, message flags, pinned state, and aggregate rich-state and mention counts before returning a strict transient projection. Return supported text directly, normalize supported static Components V2 into the bounded Text Display, Separator, callback-free Link Row, and one-level Container DSL, and project a supported single attachment only as exact ID, safe filename, nullable bounded description, and numeric size. Return a static link-button destination only inside the transient normalized layout and treat it as untrusted. Omit Discord-generated component IDs plus custom-ID actions, attachment URLs, proxy URLs, content types, dimensions, placeholders, CDN signatures, and raw attachment objects. Classify every other rich presentation as unsupported while returning only its ordinary content and bounded aggregate counts, never rich bodies. Reject system and bot recipients, group channels, malformed evidence, profile expansion, and messages authored outside the two verified participants. Never cache, search, index, journal, trace, export, download, or persist private content, component layouts, link destinations, profiles, avatars, attachment URLs, raw payloads, or unknown values.

Keep text, static Components V2, or single owned-file send and reply, same-format text or Components V2 connector-message edit, and irreversible supported-message deletion behind one plan-verify-execute workflow with strict action-specific inputs. Send and reply require an explicit expected-contact acknowledgement; deletion requires an explicit irreversible-deletion acknowledgement. Planning a send may fetch only the exact user and read the explicitly requested local file when present; it must not create or discover a channel. Accept bounded plain text, only the static Text Display, Separator, callback-free Link Row, and one-level Container DSL, or one exact absolute local file path with optional plain text, safe filename, and bounded description. Require every normalized link-button origin to match scopes.componentLinkOrigins before recipient, channel, or Discord access. Never accept raw Discord component JSON, caller-selected component IDs, interactive controls, callbacks, embeds, remote media or attachment URLs, data URLs, base64, MCP byte fields, caller-selected MIME type, multiple files, streams, polls, stickers, or reusable content-bearing templates. Apply the owned-file symlink, hard-link, ownership, canonical-root, size, stable-path, stable-metadata, and keyed-byte checks under a direct-message-specific digest domain. Treat creation with IS_COMPONENTS_V2 as irreversible for that message and never convert an existing message between formats. Editing must reject attachment bodies and require an unpinned same-format supported text or Components V2 message. Deletion may accept a URL-free single-attachment projection but must reject any target not authored by the pinned bot or any target with parsed mentions, unsupported rich state, pinning, or reactions. Bind the complete transient body, normalized layout and preview, exact link URLs and origins or file identity and keyed bytes when applicable, local review reason, exact identities, acknowledgements, forced empty mentions, fixed anti-spam limits, exact presentation and current state, privacy omissions, operation-key hash, and warnings into the process-keyed plan. Never send the local review reason as a Discord audit-log header.

Require signed interactive confirmation, write-aware host approval, a final fresh matching plan, durable exact-target coordination, a request-bound schema-v2 one-shot receipt, and pending content-free activity before Discord contact. Keep the global ceiling at five changes per rolling minute and the per-recipient interval at five seconds without a configuration override. Force the exact minimal empty allowed_mentions shape, disable reply-author notification, derive a deterministic enforced nonce for sends and replies, and never automatically retry a Create DM, create-message, multipart upload, edit, or delete request. Upload one reviewed in-memory snapshot through one payload_json and one files[0] field, with no guild ID or remote source. A send may need both Create DM and message creation, so checkpoint its exact channel before dispatch and checkpoint the exact message identity before readback. Require a matching exact presentation and complete body or receipt-bound filename, description, and byte size in the response and fresh message readback, or exact 404 absence after deletion. Never fetch an attachment URL to claim remote byte equality; Discord exposes no attachment content digest.

Receipt transitions must be immutable and monotonic from reserved through optional channel-ready and message-dispatched checkpoints to terminal. Derive the request binding from the active bot secret independently of the process-bound plan key, so restart preserves exact caller-retained request verification while credential rotation deliberately invalidates it. Verification must compare that binding and all receipt targets before Discord or local-file access, read only the receipt-bound exact message or absence when safe, and never reopen the requested file, follow an attachment URL, scan history, reserve a key, append activity, consume a rate budget, or trust caller-selected recovery targets. Pending, malformed, mismatched, rate-limited, transport-failed, server-failed, or readback-indeterminate work must fail closed or remain quarantined; every reserved key stays spent.

Persist only the exact recipient, channel, reply-target, and message IDs needed for recovery, action, fixed message-format class, nullable attachment byte size in the operation receipt, request and plan digests, operation-key hash, immutable stage, timestamps, fixed status and verification values, activity ID, and a sanitized error category. Never persist private content, local paths, file bytes, filenames, descriptions, file metadata, byte digests, component layouts or previews, link destinations or origins, attachment URLs, embeds, components, usernames, profile names, avatars, review reasons, raw operation keys, nonces, response bodies, routes, transport causes, or raw Discord objects.

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.