ИИ-агент нашёл семь уязвимостей в криптобиблиотеке Cloudflare CIRCL

Компания zkSecurity, разработчик автономного ИИ-аудитора кода zkao, опубликовала первый пост в серии о багах, которые её агенты находят в открытых криптографических проектах. Первой целью стала CIRCL, библиотека Cloudflare с продвинутой и постквантовой криптографией. Конвейер zkSecurity прогнал код в двух режимах: обычная LLM с простым промптом и LLM с навыками (skills), которые готовили эксперты компании по безопасности. Затем на тех же проектах, где LLM нашла реальные уязвимости, отдельно запустили zkao, и он не только повторил находки, но и обнаружил более сложные и серьёзные проблемы. По итогам эксперимента команда подтвердила семь багов; все они уже исправлены в апстриме, большинство, с выплатой bounty по программе Cloudflare на HackerOne. Авторы подчёркивают: ИИ выдаёт только кандидатов в находки, а не готовые отчёты, люди из команды перепроверяли каждую проблему, оценивали эксплуатируемость, минимизировали PoC и вели раскрытие информации; эта проверка человеком остаётся дорогой и важной частью процесса, хотя новая версия zkao уже берёт на себя всё больше этой работы.

Баг 1, потеря точности float64 в пороговой RSA (tss/rsa). Функция Deal() при разделении секрета по схеме Шамира вычисляла член x^i через math.Pow(float64(x), float64(i)) вместо big.Int. У float64 мантисса 53 бита, и как только x^i превышает 2^53 (около 9×10^15), результат округляется ещё до приведения к целому. Например, при 100 участниках и пороге 27 вычисление x=100, i=26 требует 100^26 = 10^52, на 36 порядков больше предела точности; ошибка возникает уже при x=20, i=16. В итоге доли ключа, выдаваемые участникам, оказываются неверными, а комбинирование подписи либо явно ломается, либо выдаёт правдоподобные, но нерабочие доли. ИИ оценил баг как критический (компрометирует корректность протокола), Cloudflare, как низкий по вероятности реальной эксплуатации. Исправление заменило вычисление на метод Горнера в big.Int, как и предлагал старый TODO в коде.

Баг 2, подделка DLEQ-доказательства через параметр безопасности, который контролирует нападающий (zk/qndleq). В доказательстве равенства дискретных логарифмов длина челленджа Фиата-Шамира задаётся полем SecParam, которое лежит прямо внутри структуры Proof, то есть подконтрольно тому, кто предъявляет доказательство. При верификации челлендж пересчитывался с использованием этого же SecParam. Если атакующий выставит SecParam=1, челлендж схлопывается до одного бита (подбор с вероятностью 50%), при SecParam=8 достаточно порядка 256 попыток перебора. Исправление убрало SecParam из структуры Proof и сделало его явным аргументом функции Verify, который задаёт сама проверяющая сторона.

Баг 3, верификация агрегированной BLS-подписи без проверки различия сообщений (sign/bls), единственный случай, где ИИ занизил серьёзность. Функция VerifyAggregate реализует режим агрегации BLS BASIC, который безопасен только если все сообщения в пакете различны, это защита от атаки rogue key. Проверка пары агрегатов выполнялась, но различие сообщений не проверялось вовсе, оставляя это на совести вызывающего кода. Без проверки применяется классическая атака: злоумышленник, зная публичный ключ жертвы и сообщение, регистрирует свой ключ как разность своего секретного ключа и публичного ключа жертвы и подделывает агрегированную подпись над двумя одинаковыми сообщениями, не зная секретного ключа жертвы. У CIRCL нет инфраструктуры proof-of-possession, которая могла бы подстраховать. ИИ верно опознал атаку rogue key, но счёл требование к вызывающей стороне смягчающим фактором и занизил оценку до средней; авторы поста считают это ошибкой и относят баг к критическим, Cloudflare подтвердила high. Исправление заставляет VerifyAggregate отклонять пакеты с повторяющимися сообщениями.

Баг 4, обход надёжности DLEQ-доказательства через коллизию знака в сериализации FillBytes (zk/qndleq), самый тонкий баг в подборке. Взяв честное, валидное доказательство для утверждения о равенстве логарифмов для пары (g, gx, h, hx), атакующий без знания секрета предъявляет то же самое доказательство, но для другого утверждения, с отрицательным значением -gx вместо gx. Совпадают сразу два фактора: алгебраически (-gx)^c по модулю N равно (-1)^c·gx^c, и при чётном c знак исчезает; а функция сериализации FillBytes при вычислении хеша-челленджа записывает абсолютное значение big.Int, отбрасывая знак, поэтому хеши от gx и -gx совпадают. Чётность c, это просто младший бит хеша, так что подделка проходит примерно в половине случаев для честно сгенерированных доказательств; верификатор ошибочно признаёт равенство логарифмов, которого нет. Ни алгебраическая формула, ни выбор сериализации сами по себе не являются ошибкой, уязвимость рождается на стыке двух безобидных решений. ИИ оценил баг как high (это подрыв надёжности доказательства), Cloudflare, как low из-за высокой сложности практической атаки. Исправление добавило проверку границ, требующую 0 < x < N для всех входных значений при вычислении челленджа: отрицательное -gx теперь отклоняется до того, как способно навредить.

Баг 5, обход проверки PSK в HPKE из-за побитового ИЛИ в switch (hpke/util.go), почти языковая ловушка. Метки case в функции verifyPSKInputs были записаны как case modeBase | modeAuth и case modePSK | modeAuthPSK. В Go запись case a | b: задаёт ОДНО значение case, результат побитового ИЛИ констант, а не два отдельных варианта. Поэтому case modePSK | modeAuthPSK фактически соответствует только значению modeAuthPSK, а ветка для чистого modePSK не срабатывает вообще. В результате ветка, которая должна отклонять отсутствие PSK в режиме PSK, попросту пропускается, и SetupPSK(..., nil, nil) продолжает работу с пустым PSK вместо ожидаемого отказа, конфигурация незаметно понижается до более слабого режима. Исправление, замена побитового ИЛИ на перечисление case через запятую (case modePSK, modeAuthPSK:). Баг подтверждён как дубликат (уже был известен ранее).

Баг 6, переполнение int64 при вычислении коэффициентов Лагранжа (tss/rsa). После разделения долей секрета комбинирование подписей требует интерполяции Лагранжа; функция computeLambda считала числитель и знаменатель коэффициента в переменных типа int64, которые переполняются уже при умеренном числе участников, что приводит к усечённому целочисленному делению и неверному коэффициенту. Авторы отмечают, что здесь фактически скрыты две независимые ошибки; подробный разбор второй из них выходит за рамки доступного фрагмента материала.

Общий вывод серии: оценка серьёзности, которую ИИ даёт собственным находкам, довольно шумная, иногда завышена (баг 1), иногда занижена (баг 3), иногда расходится с итоговой оценкой Cloudflare в любую сторону. Авторы обещают вернуться к этому расхождению в конце серии постов.

Ключевые факты

  • zkSecurity прогнала свой ИИ-конвейер (включая продукт zkao) по криптобиблиотеке Cloudflare CIRCL и подтвердила семь реальных уязвимостей; все исправлены апстримом, большинство, с bounty на HackerOne
  • Баг 1: в пороговой RSA (tss/rsa) степень x^i считалась через float64/math.Pow вместо big.Int, при показателях за пределом 53-битной мантиссы (например, x=100, i=26) результат портится, доли ключа получаются неверными
  • Баг 2: DLEQ-доказательство (zk/qndleq) хранило параметр безопасности SecParam внутри самой структуры Proof, подконтрольный атакующему; SecParam=1 давал подделку с вероятностью 50%
  • Баг 3: верификация агрегированной BLS-подписи не проверяла различие сообщений, классическая атака rogue key; ИИ ошибочно оценил её как среднюю по серьёзности, хотя это критический класс уязвимостей
  • Люди в команде по-прежнему валидируют каждую находку ИИ, проверяют эксплуатируемость и готовят раскрытие, ИИ выдаёт кандидатов, а не готовые к публикации отчёты

Почему это важно

Это первый пост в серии, где компания, продающая ИИ-аудит кода, показывает конкретные результаты на реальном, широко используемом криптографическом проекте Cloudflare, а не на синтетических бенчмарках. Семь подтверждённых и исправленных багов, среди которых полноценный обход контроля доступа (rogue key в BLS) и обход надёжности криптографического доказательства (DLEQ), сильный сигнал, что современные LLM способны находить нетривиальные, многошаговые уязвимости в криптографическом коде, а не только опечатки и типовые паттерны.

Кому это важно

Разработчикам и мейнтейнерам криптографических и security-критичных библиотек, как ориентир, какие классы багов реально ловит ИИ-аудит уже сегодня. Специалистам по безопасности и компаниям, оценивающим ИИ-инструменты для аудита кода, как пример методологии сравнения (просто LLM против LLM с экспертными навыками против специализированного продукта). Cloudflare и пользователям CIRCL, это библиотека постквантовой и продвинутой криптографии, поэтому исправленные баги напрямую касаются надёжности их применений.

Как это применить

zkao, коммерческий продукт zkSecurity для непрерывного ИИ-аудита кода; в посте не приводится цена или условия доступа, только методология и результаты одного прогона на CIRCL. Практический вывод для команд: даже точечный ИИ-скан существующего, уже проверенного open source кода может вскрыть баги, пропущенные людьми, но результат такого скана нужно рассматривать как кандидатов в находки, требующих ручной валидации перед раскрытием или исправлением.

Можно ли доверять

Материал публикует сама zkSecurity, продающая продукт zkao, это заинтересованная сторона, и пост одновременно служит маркетингом. При этом фактическая проверяемость высокая: все семь багов подтверждены и исправлены Cloudflare апстримом (указаны конкретные коммиты), часть уже отмечена в программе bug bounty на HackerOne, то есть независимая сторона (Cloudflare) признала уязвимости реальными, а не просто заявлениями автора поста. Собственная оценка серьёзности со стороны ИИ, по признанию авторов, шумная и не всегда совпадает с итоговой оценкой Cloudflare.

Риски и подводные камни

Главный риск, переоценка автономности ИИ-аудита: авторы сами подчёркивают, что ИИ выдаёт лишь кандидатов в находки, а validation, оценку эксплуатируемости и раскрытие информации всё ещё делают люди, и это дорогой, но необходимый шаг. Оценки серьёзности от ИИ ненадёжны в обе стороны, есть случай серьёзного занижения критичного бага (rogue key в BLS) и случай завышения малозначимого на практике бага (float64 в RSA). Наконец, материал описывает только шесть из семи багов подробно (последний, про переполнение int64 при вычислении коэффициентов Лагранжа, разобран не до конца в доступном тексте), часть деталей серии, вероятно, раскрывается в последующих постах.

«Уточнение: ИИ выдаёт кандидатов в находки, а не готовые отчёты. Люди в нашей команде всё равно проверяли каждую проблему, оценивали эксплуатируемость, минимизировали PoC там, где это было нужно, и вели раскрытие информации. Этот шаг с участием человека по-прежнему очень важен, потому что кандидаты в находки от ИИ дёшевы, а заслуживающие доверия отчёты, нет.»

— zkSecurity, блог zkao