В ответах GLM-5.3 в облаке Cloudflare две недели попадались чужие данные
Из-за ошибки в настройке и бага в открытом движке SGLang 155 ответов на сверхдлинные запросы содержали данные других клиентов Cloudflare.
Cloudflare раскрыла, что с 27 августа по 9 сентября в часть ответов модели GLM-5.3 в её сервисе Workers AI попадали данные из запросов других клиентов.
Почему это важно: облачные сервисы обслуживают запросы разных клиентов на одних и тех же видеокартах, и разделять их данные должен сам движок, который запускает модель. Ошибка нашлась в открытом движке SGLang1, на котором модели обслуживает не только Cloudflare.
Повод: 8 сентября Гади Эврон из Knostic — компании, которая защищает корпоративные данные при работе с ИИ, — сообщил через HackerOne2, что на очень длинные запросы GLM-5.3 иногда отвечает текстом из чужих сессий. Наутро Cloudflare воспроизвела утечку с двух разных аккаунтов, через 40 минут после объявления инцидента отключила модель и в тот же день вернула её. Эврон дал компании время исправить ошибку и договориться с разработчиками SGLang, поэтому отчёт вышел только 26 октября.
Как это работает: Workers AI даёт разработчикам доступ по API к открытым моделям, в том числе к GLM-5.3 китайской Z.ai — модели для агентов, которые сами пишут код. Cloudflare обслуживает её на двух группах видеокарт: одни читают запрос и строят по нему KV-кэш3, другие получают этот кэш по сети и пишут ответ. Память под кэш поделена на страницы, общие для всех запросов, и между запросами их не стирают: следующий запрос просто пишет поверх.
Детали: к утечке привели две ошибки, которые сработали только вместе:
- Первая — в настройке: Cloudflare выставила контекстное окно4 в 1 048 576 токенов, а кэш на видеокартах, читающих запрос, вмещал лишь 681 280. О расхождении знали до запуска, но ждали, что на слишком длинный запрос движок вернёт ошибку, а тесты проверяли только коды ответа, но не текст.
- Вторая — в SGLang: движок такой запрос отклонял, но не прерывал, а подменял заглушкой в один токен и передавал дальше. Видеокарты ответа резервировали страницы под весь длинный запрос, получали одну заполненную и читали остальные, где лежали запросы и ответы других пользователей.
В цифрах: пострадали 155 ответов, все — на запросы длиннее 681 280 токенов. Признаков того, что баг кто-то использовал намеренно, Cloudflare не нашла: такие запросы по времени и объёму похожи на обычную работу с длинными текстами.
Но: о баге в SGLang знали и раньше. 6 июля его описал в списке ошибок проекта на GitHub другой пользователь, а Cloudflare нашла это сообщение только во время расследования. Исправление, которое закрывало и эту ошибку, попало в основную ветку движка 6 сентября, за два дня до сигнала Эврона, но в выпуск ещё не вошло.
Что сделали: Cloudflare расширила кэш GLM-5.3 примерно до 2,04 млн токенов, вдвое больше окна, и поставила в движок свою заплатку: теперь движок прекращает обработку отклонённого запроса ещё до передачи кэша и возвращает клиенту ошибку. Других моделей Workers AI баг не задел: у них кэш и так больше контекстного окна.
Если шире: исправления вошли в SGLang версий 0.5.20–0.5.22, и Cloudflare советует всем, кто обслуживает на нём модели в режиме с двумя группами видеокарт, обновиться до 0.5.22 или новее. Ещё она советует после каждой перенастройки сверять размер кэша с контекстным окном. «Именно эту проверку мы не сделали обязательной», — признаёт компания.
Интрига: летом Cloudflare сделала прототип защиты как раз от чтения чужих страниц. У каждой страницы есть метка, которая меняется, когда страницу отдают другому запросу, и движок сверяет её перед чтением. В тестах прототип замедлял работу меньше чем на 1%. В середине августа Cloudflare испытала его на GLM-5.2, но вскоре отключила из-за проблем с надёжностью.
Что дальше: вместе с разработчиками SGLang Cloudflare делает рабочую версию такой проверки для всех моделей. Кроме того, компания хочет математически доказать, что протокол передачи кэша между видеокартами не допускает подобных ошибок, — теми же методами формальной верификации, которыми уже проверяла свои DNS-серверы.