MessageLinkEmbeds: fix issue where a message's origin channel could be faked

This had a bad interaction with SupportHelper, where it could be used to add a "Run Snippet" button
to any linked message, which when clicked would run code contained in that message

Reported by Kaede
This commit is contained in:
Vendicated 2026-09-14 19:26:05 +02:00
parent c3b8254c2b
commit 339b85ba40
No known key found for this signature in database
GPG key ID: D66986BAF75ECF18
4 changed files with 30 additions and 17 deletions

View file

@ -1,7 +1,7 @@
{
"name": "vencord",
"private": "true",
"version": "1.15.5",
"version": "1.15.6",
"description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": {

View file

@ -264,6 +264,8 @@ export default definePlugin({
},
renderMessageAccessory(props) {
if (props.message.vencordEmbeddedBy) return null;
const buttons = [] as JSX.Element[];
const shouldAddUpdateButton =

View file

@ -46,6 +46,8 @@ const messageCache = new Map<string, {
fetched: boolean;
}>();
const getCacheKey = (channelId: string, messageId: string) => `${channelId}:${messageId}`;
const Embed = findComponentLazy(m => m.prototype?.renderSuppressButton);
const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hideAccessories");
let AutoModEmbed: ComponentType<any> = () => null;
@ -128,17 +130,19 @@ const settings = definePluginSettings({
});
async function fetchMessage(channelID: string, messageID: string) {
const cached = messageCache.get(messageID);
async function fetchMessage(channelId: string, messageId: string) {
const cacheKey = getCacheKey(channelId, messageId);
const cached = messageCache.get(cacheKey);
if (cached) return cached.message;
messageCache.set(messageID, { fetched: false });
messageCache.set(cacheKey, { fetched: false });
const res = await RestAPI.get({
url: Constants.Endpoints.MESSAGES(channelID),
url: Constants.Endpoints.MESSAGES(channelId),
query: {
limit: 1,
around: messageID
around: messageId
},
retries: 2
}).catch(() => null);
@ -146,10 +150,12 @@ async function fetchMessage(channelID: string, messageID: string) {
const msg = res?.body?.[0];
if (!msg) return;
if (msg.id !== messageId) return;
const message = MessageStore.getMessages(msg.channel_id).receiveMessage(msg).get(msg.id);
if (!message) return;
messageCache.set(message.id, {
messageCache.set(cacheKey, {
message,
fetched: true
});
@ -230,31 +236,32 @@ function MessageEmbedAccessory({ message }: { message: Message; }) {
const accessories = [] as (JSX.Element | null)[];
for (const [_, channelID, messageID] of message.content!.matchAll(messageLinkRegex)) {
if (embeddedBy.includes(messageID) || embeddedBy.length > 2) {
for (const [_, channelId, messageId] of message.content!.matchAll(messageLinkRegex)) {
if (embeddedBy.includes(messageId) || embeddedBy.length > 2) {
continue;
}
const linkedChannel = ChannelStore.getChannel(channelID);
const linkedChannel = ChannelStore.getChannel(channelId);
if (!linkedChannel || (!linkedChannel.isPrivate() && !PermissionStore.can(PermissionsBits.VIEW_CHANNEL, linkedChannel))) {
continue;
}
const { listMode, idList } = settings.store;
const isListed = [linkedChannel.guild_id, channelID, message.author.id].some(id => id && idList.includes(id));
const isListed = [linkedChannel.guild_id, channelId, message.author.id].some(id => id && idList.includes(id));
if (listMode === "blacklist" && isListed) continue;
if (listMode === "whitelist" && !isListed) continue;
let linkedMessage = messageCache.get(messageID)?.message;
const cacheKey = getCacheKey(channelId, messageId);
let linkedMessage = messageCache.get(cacheKey)?.message;
if (!linkedMessage) {
linkedMessage ??= MessageStore.getMessage(channelID, messageID);
linkedMessage ??= MessageStore.getMessage(channelId, messageId);
if (linkedMessage) {
messageCache.set(messageID, { message: linkedMessage, fetched: true });
messageCache.set(cacheKey, { message: linkedMessage, fetched: true });
} else {
messageFetchQueue.unshift(() => fetchMessage(channelID, messageID)
messageFetchQueue.unshift(() => fetchMessage(channelId, messageId)
.then(m => m && updateMessage(message.channel_id, message.id))
);
continue;

View file

@ -655,8 +655,8 @@ export const Devs = /* #__PURE__*/ Object.freeze({
id: 383365021415243776n
},
paige: {
name: "paige",
id: 1375697625864601650n
name: "paige",
id: 1375697625864601650n
},
jax: {
name: "jax",
@ -669,6 +669,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
Davri: {
name: "Davri",
id: 457579346282938368n
},
Kaede: {
name: "Kaede",
id: 1492642701320126504n
}
} satisfies Record<string, Dev>);