Native polls
Keep poll audit behind a dedicated toggle and exact channel or thread allowlist. Parent-channel scope must never grant poll authority to a child thread. Require supported guild-channel types, verified identity, and exact guild ownership for reads. For reviewed writes, require complete bounded roles and overwrite evidence plus complete read permissions, including CONNECT for voice and stage channels. Creation additionally requires SEND_POLLS, the correct direct-channel or thread send permission, and an active unlocked thread when applicable. Keep voter audit behind a second toggle and return only bounded strict-ascending user-ID pages without profile fields.
Treat question text, answer text, emoji, and counts as untrusted transient data. Never cache, persist, journal, log, or export them or any voter identity. Preserve Discord answer IDs without assuming they are sequential. Distinguish missing results from zero votes, unfinished approximate counts from finalized counts, and an unknown lifecycle from an active poll. Fail closed on malformed identities, timestamps, layout, answers, counts, ordering, duplicates, limits, or result relationships. Count unknown response fields and prohibit poll ending until the connector understands every field that could affect destructive review.
Do not add a poll-creation shortcut that bypasses the audit and creation toggles, exact target allowlist, identity pins, complete permission evidence, bounded immutable request, process-keyed plan, signed interactive confirmation, write-aware host approval, final fresh-plan match, shared interaction limiter, atomic one-shot operation-key reservation, pending content-free activity, nonce enforcement, one non-retried POST, complete response validation, or exact message readback. Permit only plain poll media, optional Unicode answer emoji, bounded integer duration, and optional multiselect. Do not add custom emoji creation, message content, mentions, attachments, embeds, components, stickers, edits, app voting, automatic retry, compensation, or rollback without a separate threat model.
Keep poll ending behind its own toggle and limit it to an exact non-webhook poll message authored by the verified bot. Treat ending as destructive because Discord provides no reopen operation. Bind the complete poll structure, lifecycle, and live counts into the keyed digest so a vote change invalidates approval. Return an already-ended poll as a no-op before elicitation and reservation. Otherwise require signed confirmation, fresh-plan equality, one-shot reservation, pending activity, one non-retried expire request, exact response validation, and finalization-aware readback. Never report unfinished asynchronous tallying as final.
Exclude the raw operation key from plan material, signed request state, records, results, and errors while binding its domain-separated hash into each plan. Persist only exact guild, channel, message, application, and bot IDs, plan digest, operation-key hash, timestamps, fixed verification and outcome values, activity ID, and sanitized error category. Serialize creation per exact channel and ending per exact message inside one process as defense in depth. The production facade also acquires a durable exact channel claim for creation and durable exact channel-and-message claims for ending, so connector processes sharing the activity-state root exclude overlapping poll writes. Permanently spend every reserved key after success, known failure, local recording failure, or uncertainty. Treat transport errors, Discord 5xx responses, malformed successes, or failed post-write verification as uncertain and potentially completed. Retain the claims after uncertainty and never retry or compensate automatically.
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.