fix(security): gate slash commands by sender

This commit is contained in:
Peter Steinberger
2026-01-17 05:25:37 +00:00
parent c8b826ea8c
commit a624878973
14 changed files with 525 additions and 85 deletions

View File

@@ -198,11 +198,15 @@ export const buildTelegramMessageContext = async ({
return null;
}
}
const commandAuthorized = isSenderAllowed({
allow: isGroup ? effectiveGroupAllow : effectiveDmAllow,
const allowForCommands = isGroup ? effectiveGroupAllow : effectiveDmAllow;
const senderAllowedForCommands = isSenderAllowed({
allow: allowForCommands,
senderId,
senderUsername,
});
const useAccessGroups = cfg.commands?.useAccessGroups !== false;
const commandAuthorized =
useAccessGroups && !allowForCommands.hasEntries ? false : senderAllowedForCommands;
const historyKey = isGroup ? buildTelegramGroupPeerId(chatId, resolvedThreadId) : undefined;
let placeholder = "";
@@ -229,6 +233,14 @@ export const buildTelegramMessageContext = async ({
const hasAnyMention = (msg.entities ?? msg.caption_entities ?? []).some(
(ent) => ent.type === "mention",
);
if (
isGroup &&
hasControlCommand(msg.text ?? msg.caption ?? "", cfg, { botUsername }) &&
!commandAuthorized
) {
logVerbose(`telegram: drop control command from unauthorized sender ${senderId ?? "unknown"}`);
return null;
}
const activationOverride = resolveGroupActivation({
chatId,
messageThreadId: resolvedThreadId,

View File

@@ -172,17 +172,18 @@ export const registerTelegramNativeCommands = ({
: [];
const senderId = msg.from?.id ? String(msg.from.id) : "";
const senderUsername = msg.from?.username ?? "";
const commandAuthorized =
allowFromList.length === 0 ||
allowFromList.includes("*") ||
(senderId && allowFromList.includes(senderId)) ||
(senderId && allowFromList.includes(`telegram:${senderId}`)) ||
(senderUsername &&
allowFromList.some(
(entry) =>
entry.toLowerCase() === senderUsername.toLowerCase() ||
entry.toLowerCase() === `@${senderUsername.toLowerCase()}`,
));
const allowFromConfigured = allowFromList.length > 0;
const commandAuthorized = allowFromConfigured
? allowFromList.includes("*") ||
(senderId && allowFromList.includes(senderId)) ||
(senderId && allowFromList.includes(`telegram:${senderId}`)) ||
(senderUsername &&
allowFromList.some(
(entry) =>
entry.toLowerCase() === senderUsername.toLowerCase() ||
entry.toLowerCase() === `@${senderUsername.toLowerCase()}`,
))
: !useAccessGroups;
if (!commandAuthorized) {
await bot.api.sendMessage(chatId, "You are not authorized to use this command.");
return;

View File

@@ -296,9 +296,11 @@ describe("createTelegramBot", () => {
loadConfig.mockReturnValue({
commands: { native: true },
telegram: {
dmPolicy: "open",
allowFrom: ["*"],
channels: {
telegram: {
dmPolicy: "open",
allowFrom: ["*"],
},
},
});

View File

@@ -2064,9 +2064,11 @@ describe("createTelegramBot", () => {
loadConfig.mockReturnValue({
commands: { native: true },
telegram: {
dmPolicy: "open",
allowFrom: ["*"],
channels: {
telegram: {
dmPolicy: "open",
allowFrom: ["*"],
},
},
});