Summary
commands/ai/aiassistant.js declares history as a module-level array that persists across all invocations of the /aiassistant ask command. Every user's question and the AI's reply are appended to this single shared array. As a result:
- User B's request includes User A's question and answer as conversation history, so the AI model sees — and can reference — another user's private input.
- The array grows without bound, eventually exceeding Gemini's context window or causing high memory consumption on the bot process.
Vulnerable code
// module scope — shared across every user, every guild
const history = [];
// inside execute():
history.push({ role: "user", parts: [{ text: question }] });
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: history, // every previous user's Q&A is included
...
});
history.push({ role: "model", parts: [{ text: response.text }] });
Impact
- Cross-user data exposure: User B receives an AI response influenced by User A's question. If User A asked about something personal or sensitive, that information leaks into User B's session through the shared context window.
- Unbounded memory growth: The array is never trimmed. After enough usage the process will run out of memory or hit Gemini's token limit, causing errors for all users.
- Cross-guild leakage: The same array is shared across all servers the bot is in. Users in different guilds see each other's conversation history.
Suggested Fix
Maintain per-user (or per-user-per-guild) history stored in the database rather than a module-level variable. A simple in-memory approach would key by userId:
// Remove module-level history = []
const userHistories = new Map(); // temporary in-process store; use DB for persistence
async execute(interaction, client) {
const key = `${interaction.guild.id}:${interaction.user.id}`;
const history = userHistories.get(key) ?? [];
history.push({ role: "user", parts: [{ text: question }] });
// keep only the last N exchanges to bound token usage
const trimmed = history.slice(-10);
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: trimmed,
...
});
trimmed.push({ role: "model", parts: [{ text: response.text }] });
userHistories.set(key, trimmed);
...
}
For production, persist history in MongoDB (which the bot already uses) and load it at the start of each interaction.
Summary
commands/ai/aiassistant.jsdeclareshistoryas a module-level array that persists across all invocations of the/aiassistant askcommand. Every user's question and the AI's reply are appended to this single shared array. As a result:Vulnerable code
Impact
Suggested Fix
Maintain per-user (or per-user-per-guild) history stored in the database rather than a module-level variable. A simple in-memory approach would key by
userId:For production, persist history in MongoDB (which the bot already uses) and load it at the start of each interaction.