Conversation
| escapeCsvField(parsed.email), | ||
| parsed.type, | ||
| parsed.verifiedBy || '', | ||
| tags |
There was a problem hiding this comment.
Tags field missing CSV escape handling for quotes/newlines
Medium Severity
The tags field is not passed through escapeCsvField() before being included in the CSV output. While commas are replaced with semicolons, quotes and newlines in tag values would corrupt the CSV structure. The regex pattern [^\]]+ allows tags to contain quotes or newlines, which need proper escaping (wrapping in quotes and doubling internal quotes) to produce valid CSV. Unlike username and email which use escapeCsvField(), the tags field bypasses this protection.
| escapeCsvField(parsed.email), | ||
| parsed.type, | ||
| parsed.verifiedBy || '', | ||
| tags |
There was a problem hiding this comment.
Tags field not escaped for CSV output
Medium Severity
The tags field is added directly to the CSV row without being passed through escapeCsvField(), unlike username and email which are properly escaped. The tags originate from Discord role names (via assignedRoleNames), which can contain double quotes or newlines. Replacing commas with semicolons on line 104 doesn't protect against these other CSV-breaking characters, resulting in malformed CSV output.
| username = member ? member.user.username : ''; | ||
| } catch { | ||
| username = ''; | ||
| } |
There was a problem hiding this comment.
Per-message member fetch causes timeout on large exports
Medium Severity
For every parsed log message, interaction.guild.members.fetch(parsed.userId) makes a Discord API call. With up to 10,000 messages and many unique users (especially ones who've left the server and aren't cached), this can trigger thousands of sequential API calls subject to rate limiting. This risks exceeding the 15-minute deferred interaction timeout, causing the export to silently fail.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| // Deduplicate | ||
| const uniqueEmails = [...new Set(emails)]; | ||
|
|
||
| serverSettings.allowedEmails = uniqueEmails; |
There was a problem hiding this comment.
Upload silently replaces email list instead of appending
Medium Severity
The upload subcommand assigns serverSettings.allowedEmails = uniqueEmails, which completely replaces the existing allowed email list. However, the success message (emaillistUploaded) says "Added %VAR% unique email address(es)" across all languages, implying the new emails were appended to the existing list. An admin who uploads a second CSV expecting it to merge with the first list will silently lose all previously allowed emails with no warning.
Additional Locations (1)
| } | ||
| } else if (onlyEmailList) { | ||
| // Only email list, no domains - show default roles | ||
| const defaultRoleNamesDisplay = getRoleNames(defaultRoles) |
There was a problem hiding this comment.


Note
Medium Risk
Adds new premium/monetization gating that can block verification email sending and CSV features if misconfigured, plus database migrations for new per-guild settings/credits. Also changes verification eligibility to include an uploaded allowlist, so mistakes in list handling or locale JSON could affect user verification flows.
Overview
Adds CSV-based admin tooling: a new
/emaillistcommand to upload/list/clear a per-server allowed-email allowlist, and an/export logscommand to export verification log channel messages as CSV.Introduces premium/monetization support via
PremiumManager, including a free monthly email cap with optional subscription/credit-pack bypass, a/premiumcommand (status + redeem entitlements), and premium-gating for CSV import/export; the verification flow now checks both domain allowlists and the uploaded email list, and blocks sending when the monthly limit is reached.Updates persistence and UX: adds DB migrations for
allowedEmailsand aguild_premiumtable (credits + CSV unlock), extends/statusand the verify modal to display allowed-email and premium info, and adds localized strings across supported languages.Written by Cursor Bugbot for commit 49fe50b. This will update automatically on new commits. Configure here.