Photo by Markus Spiske on Pexels.com
creative internet computer display

Исправлена потенциально опасная уязвимость бота vkpin2exec


Был исправлен баг, из-за которого бот мог при определенных условиях повторно выполнять команды от имени любого человека. На чьей стороне этот баг не совсем ясно, но так как в документации по Callback API не нашлось информации об этом (описание будет ниже), то судя по всему виновником можно считать вк

Баг заключается в том, что вк, по какой-то причине, при закреплении сообщения в чате стал присылать боту два отдельных события: собственно само сервисное сообщение «закреп» и отдельно присылать текст закрепленного сообщения как «новое сообщение в чате». Приблизительно до 2025 года вк присылал только одно первое событие

При этом, если закрепить сообщение, содержащее команду ТБРУ, бот выполнит её от имени автора сообщения (даже если оно было отправлено 7 лет назад), а не от имени того, кто сделал закреп. В том числе команды /перевод и /обмен. Например:

2 Пользователя: вася (id: 1111) и ваня (id 5555)

*2023 год*
Вася пишет: /перевод 5555 600
Бот пишет Васе: Вы перевели Ване 600 баллов

*2026 год*
Ваня: *находит старое сообщение васи*
Ваня: *закрепляет сообщение Васи /перевод 5555 600*

ВК отправляет боту событие: Ваня закрепил сообщение васи с текстом ...
Бот: *игнорирует*

ВК отправляет боту второе событие: новое сообщение в чате: автор: вася; текст: "/перевод 5555 600"; дата: 2023 год
Бот отвечает Васе: Вы перевели Ване 600 баллов

Уязвимость получила локальное название vkpin2exec (закрепи сообщение вк, чтобы выполнить команду от чужого имени). При закрепе бот в Callback получает следующие события:

(первое событие)
{
	"group_id": 175121984,
	"type": "message_new",
	"event_id": "4a0cce...ffd58",
	"v": "5.199",
	"object": {
		"client_info": {...},
		"message": {
			"date": 1793027139,
			"from_id": 189079189,
			"id": 0,
			"version": 10384740,
			"out": 0,
			"fwd_messages": [],
			"important": false,
			"is_hidden": false,
			"action": {
				"type": "chat_pin_message",
				"conversation_message_id": 1875560,
				"member_id": 189079189,
				"message": "омси"
			},
			"attachments": [],
			"conversation_message_id": 1875604,
			"text": "",
			"is_unavailable": true,
			"peer_id": 2000000051,
			"random_id": 0
		}
	}
}

Первое событие, как и полагается и ожидается, содержит поле action->type, что говорит боту о том, что это сервисное сообщение. Сам текст закрепленного сообщения также присутствует внутри поля action->message. Но затем вк присылает боту второе событие (уведомление):

{
	"group_id": 175121984,
	"type": "message_new",
	"event_id": "a36282...5f6a",
	"v": "5.199",
	"object": {
		"client_info": {...},
		"message": {
			"date": 1793025670,
			"from_id": 7***1,
			"id": 0,
			"version": 10384740,
			"out": 0,
			"fwd_messages": [],
			"important": false,
			"is_hidden": false,
			"is_pinned": true,
			"pinned_at": 1793027139,
			"attachments": [],
			"conversation_message_id": 1875560,
			"text": "омси",
			"is_unavailable": true,
			"peer_id": 2000000051,
			"random_id": 0
		}
	},
}

Бот воспринимал это как новое сообщение в чате и выполнял введенную команду еще раз. Единственное, чем «псевдоновое сообщение» отличается от нового (кроме даты) это поле is_pinned=true. Причем, в самой документации вк об этом поле ни слова не написано…

Зачем вообще вк стал дополнительно отправлять событие «новое сообщение» с закрепленным сообщением сразу после события «в чате закрепили такое-то сообщение» — не ясно. Видимо, догвайбкоднейрослопились ребята…

Кроме указанного, есть и другие… (эм, баги?) задвоения команд, но не считающиеся опасными и не исправленные в боте до сих пор. В некоторых случаях вк также по непонятным соображениям дублирует события (причем у каждого дубля свой event_id, отличающийся от оригинального события). Буду называть это «багами со стороны ВК» т.к. даже логически не могу ожидать такого поведения от callback api вк

Ссылки

Если вместе с командой боту отправить ссылку, т.е ввести, например, /профиль provgis.ru, бот также ответит на это сообщение дважды, поскольку вк отправляет боту два события: сообщение «/профиль provgis.ru» и сообщение «/профиль provgis.ru» со сниппетом

Репосты из каналов

Баг был обнаружен в январе 2026: бот на репост из канала трижды (!!!! даже не дважды !!!) присылает онлайн. Если в тексте репоста содержится команда, например /график, бот пришлет два раза онлайн и один раз график, поскольку вк присылает боту сразу три события:

1) пустое сообщение без текста и вложений. Вероятно, репост из канала, но опознание невозможно
2) сообщение с текстом, имеется ссылка на предыдущее сообщение [1] в чате. ВК теперь зачем-то текст к репосту отправляет отдельно от самого репоста (видимо, хотели скопировать крутую фишку из [удалено]грама, но на мой взгляд это наоборот было плюсом вк, что текст репоста не отправляется отдельным сообщением)
3) пустое сообщение без текста и вложений. Имеется ссылка на предыдущее сообщение [2] с текстом….

Стикеры чата

Работают аналогично. Если сообщение с обычным содержит поле attachments:

"attachments": [
	{
		"type": "sticker",
		"sticker": {
			"inner_type": "base_sticker_new",
			"sticker_id": 84669,
			"product_id": 1799,
			"images": [...]
			"images_with_background": [...]
			"is_allowed": false
		}
	}
]

То сообщения со стикерами чата, как и с репостами из каналов, до сих пор не содержат ничего, а в событии вк присылает пустое поле attachments (хотя, как ожидается, должно быть что-то типа такого: attachments[0]->type=chat_sticker). Событие не содержит даже никакого банального поля is_sticker или is_chat_sticker как с закрепами, и бот включает стандартную логику «нет вложений? Нет текста? Отправляю онлайн», изначально заложенную в него специально, поэтому исправить данный баг пока невозможно, кроме как отказаться от этой логики