fix(share-ai): reject non-text message parts to close size-cap bypass (RT-19) #63

Closed
opened 2026-06-21 01:56:55 +03:00 by Ghost · 0 comments

Источник: red-team-аудит, RT-19 (закрывает заодно RT-14) (docs/red-team-report.md).

Что происходит

Лимит размера сообщения MAX_SHARE_MESSAGE_CHARS=8000 считает только текстовые части (uiMessageTextLength, public-share-chat.controller.ts:284,308). Если в parts запихнуть большой не-текстовый кусок (forged tool-result/file/data), он обходит лимит и раздувает вход модели (token-DoS); convertToModelMessages разворачивает подделанный tool-result в контекст (RT-14).

Фикс

Сервер в анонимном ходе тулзы не исполнял → любой tool-part в запросе клиента нелегитимен. Отбивать не-текстовые части на шаге проверки размера:

// public-share-chat.controller.ts — reject any non-text part up front. The server
// ran no tools, so a client tool-part is never legitimate; rejecting keeps the
// size cap meaningful and avoids JSON.stringify-ing an attacker-sized payload.
import { isTextUIPart } from 'ai';
for (const m of messages) {
  const parts = Array.isArray(m?.parts) ? m.parts : [];
  if (parts.some((p) => !isTextUIPart(p))) throw new HttpException('Unsupported message content', 400);
  if (uiMessageTextLength(m) > MAX_SHARE_MESSAGE_CHARS) throw new HttpException('Message too long', 413);
}

Цена / приоритет

Маленькая правка в одной точке, закрывает и RT-19, и RT-14.

**Источник:** red-team-аудит, RT-19 (закрывает заодно RT-14) (`docs/red-team-report.md`). ### Что происходит Лимит размера сообщения `MAX_SHARE_MESSAGE_CHARS=8000` считает только текстовые части (`uiMessageTextLength`, `public-share-chat.controller.ts:284,308`). Если в `parts` запихнуть большой **не-текстовый** кусок (forged tool-result/file/data), он обходит лимит и раздувает вход модели (token-DoS); `convertToModelMessages` разворачивает подделанный tool-result в контекст (RT-14). ### Фикс Сервер в анонимном ходе тулзы не исполнял → любой tool-part в запросе клиента нелегитимен. Отбивать не-текстовые части на шаге проверки размера: ```ts // public-share-chat.controller.ts — reject any non-text part up front. The server // ran no tools, so a client tool-part is never legitimate; rejecting keeps the // size cap meaningful and avoids JSON.stringify-ing an attacker-sized payload. import { isTextUIPart } from 'ai'; for (const m of messages) { const parts = Array.isArray(m?.parts) ? m.parts : []; if (parts.some((p) => !isTextUIPart(p))) throw new HttpException('Unsupported message content', 400); if (uiMessageTextLength(m) > MAX_SHARE_MESSAGE_CHARS) throw new HttpException('Message too long', 413); } ``` ### Цена / приоритет Маленькая правка в одной точке, закрывает и RT-19, и RT-14.
Ghost added the bugsecurity labels 2026-06-21 02:27:18 +03:00
Ghost closed this issue 2026-06-21 14:10:29 +03:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#63