Announcement subscriptions
Keep announcement-subscription audit behind its own toggle and exact direct text-target allowlist, separate from generic webhook scope. Require verified application and bot identities, exact target guild ownership, complete bounded roles and overwrites, effective target VIEW_CHANNEL plus MANAGE_WEBHOOKS, and a complete bounded target webhook inventory. Never read a message for this workflow.
Project every target webhook internally to exact ID, normalized type, locally derived creation timestamp, and both Channel Follower source IDs only when Discord supplies both and local read scope permits both. Expose only aggregate capacity and the exact Channel Follower subset. Expose an unavailable source identity explicitly, redact an out-of-scope source identity explicitly, and reject a partial identity. Never return or persist unrelated webhook identifiers, webhook credentials, execution URLs, webhook names, avatars, creator or application metadata, webhook-embedded source names or icons, message data, unknown raw fields, or raw responses.
Keep changes behind a second toggle. Subscribe additionally requires an exact direct announcement-source allowlist, exact GUILD_ANNOUNCEMENT source and GUILD_TEXT target types, source VIEW_CHANNEL, complete source and target guild evidence, target capacity, and proof that no duplicate source subscription exists. Permit cross-guild following only when both guilds and channels independently pass scope and permission checks, and expose the boundary in review. If any existing Channel Follower webhook has unavailable or policy-redacted source identity, fail closed because duplicate absence cannot be proven. Return one exact existing source subscription as a no-op before confirmation, coordination, reservation, activity, or mutation.
Unsubscribe must accept only one exact Channel Follower webhook ID from the complete asserted target inventory. Do not delete by source identity, webhook name, ordinal, or fuzzy match. Permit exact-ID unsubscription when Discord no longer exposes source identity or when local read policy redacts it because exact target membership and type remain independently verifiable. Never accept an Incoming or application webhook through this workflow, and never remove already delivered messages.
Do not add an immediate mutation path. Bind the normalized action, one-shot key hash, verified identities, exact source and target evidence when applicable, complete minimized target inventory, permissions, privacy projection, risks, and warnings into the process-keyed digest. Require a signed interactive confirmation, write-aware host approval, final fresh-plan equality, durable target and guild-webhook-collection coordination plus source-channel or exact-webhook coordination as applicable, atomic key reservation, and pending content-free activity before one non-retried mutation.
For subscribe, send only the exact target channel ID and reviewed audit reason to Discord's follow endpoint, validate the returned source channel and new webhook ID, and require a complete readback containing that exact follower plus every prior entry. For unsubscribe, send one exact bot-authenticated webhook DELETE and require complete readback proving the target absent and every survivor unchanged. Report unrelated but valid inventory drift rather than hiding it. Treat transport failure, rate limiting, server failure, malformed response evidence, failed or conflicting readback, or any otherwise indeterminate post-reservation state as uncertain and potentially completed. Permanently spend the key, retain durable claims after uncertainty, and never retry, guess, compensate, or recreate automatically.
Activity, receipt, and coordination records may contain only exact source, target, guild, and webhook IDs where applicable, plan digest, operation-key hash, timestamps, fixed action, outcome, and verification values, activity ID, sanitized error category, operation kind, and coordination metadata. Never persist channel or guild names, audit reasons, raw operation keys, webhook metadata beyond these exact IDs, permission evidence, raw responses, or transport causes.
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.