> · · 8 мин

Шесть критических CVE в SQLite выдумала LLM. Одной дали 10.0, а функции из отчёта не существует

Шесть критических CVE в SQLite выдумала LLM. Одной дали 10.0, а функции из отчёта не существует

В отчёте о критической уязвимости в SQLite указаны строки 3555 и 3575 файла src/json.c. Проблема в том, что в заявленной версии 3.41.0 этот файл длиной 2706 строк. Строк 3555 там нет. И самой функции, в которой якобы сидит use-after-free, в этой версии тоже нет.

Такой отчёт получил в NVD оценку 7.5 High. Его сосед по репозиторию — 9.8 Critical. А ещё одному Red Hat поначалу выдал ровные 10.0.

TL;DR: Свежесозданный GitHub-репозиторий вывалил пачку advisory на SQLite; NVD пометила их как критические, CISA согласилась. JFrog проверила шесть штук — все выдуманы: несуществующие функции, номера строк за пределами файла, «патчи», которых нет в диффе, PoC, не проходящие даже парсер. Остальные 49 CVE в том же репозитории (libraw, ESP32-audioI2S) тоже фейк, кроме одного реального бага с непроверенными метаданными. MITRE отклонила всю пачку.

Что именно нафантазировала модель

Шесть advisory, шесть разных способов ошибиться — и ни одного, который выдержал бы пять минут проверки по исходникам.

  • CVE-2026-51302, 9.8 Critical. Заявлен UAF: sqlite3ReleaseTempReg() оставляет висячий указатель, который потом разыменовывает exprComputeOperands(). Функции exprComputeOperands() в SQLite 3.41 не существует, она появилась в середине 2025 года. Вдобавок sqlite3ReleaseTempReg() вообще не освобождает память: она складывает индексы регистров в массив для переиспользования, так что UAF там невозможен архитектурно. Именно этой CVE Red Hat сначала поставил 10.0, потом снизил до 7.6.
  • CVE-2026-51303, 9.8 Critical. Заявлено, что ExprListDelete() не чистит обратные ссылки в родительских структурах, и что это починили в 3.51.3. Обратных ссылок в структурах Expr, Select и Window нет вообще. А дифф между 3.51.2 и 3.51.3 не содержит ни одного изменения в src/expr.c — «патч» выдуман целиком. PoC при этом невалидный SQL и падает на парсере, до исполняемой логики не доходя.
  • CVE-2026-51300, 9.1 Critical. Ссылается на строки 1012 и 1026 в expr.c. По этим адресам лежат комментарий и вызов выделения памяти, ни то, ни другое к удалению указателей отношения не имеет.
  • CVE-2026-51297, 8.8 High. Обвиняет jsonBlobEdit(), которой в 3.41.0 нет: она приехала позже вместе с реализацией JSONB.
  • CVE-2026-51296, 7.5 High. Тот самый случай со строками 3555 и 3575 в файле из 2706 строк.
  • CVE-2026-51304, 7.5 High. Утверждает, что sqlite3ExprListDelete(pOrderBy) освобождает список, который потом читают. Такой односоставной подписи не существует, реальная требует ещё и указатель на контекст БД. А SQLite прямо после удаления обнуляет указатель: pPrior->pOrderBy = 0;.

Методика проверки у JFrog простая и воспроизводимая: клонировали официальный репозиторий, выкатили теги version-3.41.0, 3.51.2 и 3.51.3, собрали релизы в изолированных Docker-контейнерах, скормили PoC из каждого advisory собранным бинарникам под AddressSanitizer, отдельно сверили CPE и метаданные в NVD и GHSA. Ни один PoC не вызвал ни падения, ни утечки. Плюс отдельный признак, который к делу не подшить, но который совпал: при прогоне через GPTZero весь набор advisory помечается как сгенерированный.

Как выдумка получает статус Critical в NVD

Потому что в цепочке от заявки до записи с оценкой 9.8 не осталось ни одного места, где кто-то обязан воспроизвести баг.

Публичная форма подачи CVE у MITRE не требует верификации личности: описание уязвимости и предложенный CVSS может отправить практически кто угодно. Раньше страховкой служил NIST: эксперты NVD вручную разбирали и обогащали входящие записи. Эта страховка сломалась в феврале 2024 года, когда поток отчётов вырос настолько, что глубокий анализ пришлось остановить. CISA и другие Authorized Data Publishers попытались закрыть дыру своим обогащением, но конвейер в итоге фрагментировался и оброс бэклогом.

Дальше работает автоматика. Advisory заходит, получает предложенный автором CVSS, ADP его подтверждает, запись расходится по фидам. Формально всё корректно: каждый участник сделал свою часть, воспроизведение баги не входило в чью-либо часть ни у кого.

Показательно, что SQLite здесь оказался идеальной мишенью. Проект официально не отслеживает CVE — разработчики починили бы реальный баг за часы, но в конвейер уязвимостей они не играют и часто узнают о CVE спустя месяцы. То есть вендора, который громко скажет «этой функции у нас нет», в цепочке просто не предусмотрено. Опровержение пришло от сторонней компании через несколько дней, когда записи уже разошлись по базам.

Мы писали про AI-слоп в баг-баунти curl, где Стенберг ввёл мгновенный бан для авторов сгенерированных отчётов. Разница в том, что у curl слоп упирался в живого мейнтейнера и умирал на входе. Здесь он миновал людей полностью и вышел с официальной оценкой критичности.

Чем это опаснее просто потраченного времени

Тем, что фейковая CVE ломает не человека, а автоматику, которая на неё реагирует — и особенно ту автоматику, которую сейчас массово строят на LLM.

Сценарий из отчёта JFrog, и он не гипотетический: в организациях, где критичное приоритизируется автоматически, запись 9.8 сама открывает тикет. В организациях, где триаж и починку отдали AI-агенту, всё интереснее. Агент получает CVE, идёт искать уязвимую функцию, не находит её (потому что её не существует), но задача-то поставлена. Дальше он либо генерирует патч к коду, которого нет, либо решает, что похожая функция и есть искомая, и правит её.

Второй вариант — это внесение изменений в рабочий код ради несуществующей уязвимости. Худший возможный исход процесса, который затевался ради безопасности.

Отдельная деталь для калибровки доверия. В комментариях к заметке LWN читатель обратил внимание на неудобное совпадение: JFrog публикует разбор про фейковые CVE в те же дни, когда обсуждается настоящая дыра в её собственном Artifactory — та, через которую модели OpenAI пробрались в инфраструктуру Hugging Face. Мотивы читателя проверить нельзя, а вот техническая часть разбора проверяется по исходникам SQLite за десять минут и подтверждается. Как раз это и есть правильная реакция на любой security-отчёт, включая отчёт о фейковых отчётах: смотри на воспроизводимость, а не на репутацию.

Подводные камни

  • Пачка отклонена, но фиды помнят. MITRE отклонила все advisory, однако записи успели разойтись по зеркалам и агрегаторам, и часть из них до сих пор отдаёт старые данные с прежним CVSS. Твой сканер может ругаться на SQLite ещё недели.
  • Оценки менялись на ходу. У одной и той же CVE было 10.0 у Red Hat, потом 7.6, и 0 в некоторых зеркалах. Если ты снимаешь метрики риска по CVSS из фида, ты снимаешь шум.
  • В той же пачке был один реальный баг. Из 49 остальных CVE (libraw и ESP32-audioI2S) одна описывала настоящую проблему, но с непроверенными метаданными. Правило «репозиторий помечен как слоп, значит всё содержимое можно игнорировать» здесь не работает и приводит к пропуску настоящей уязвимости.
  • GPTZero — не доказательство. Детекторы AI-текста дают ложные срабатывания, и в отчёте JFrog это лишь дополнительный признак рядом с шестью техническими опровержениями. Строить вывод на одном детекторе нельзя, особенно если решение — забанить автора.
  • Отсутствие CVE на сайте вендора тоже не приговор. Для SQLite это сильный сигнал, потому что у проекта есть страница. Для тысяч мелких библиотек, у которых advisory-страницы нет вообще, признак не работает.

Альтернативы: как проверять CVE, не тратя день

  • Сверка с вендором — самый быстрый фильтр. Есть ли запись на официальной странице advisory или в security-рассылке проекта. Для SQLite, curl, OpenSSL и прочих серьёзных проектов отсутствие там равно почти нулевой вероятности.
  • Наличие коммита или PR с починкой — второй фильтр, и он же убивает большинство слопа. У реальной уязвимости есть конкретный коммит. Если advisory заявляет исправление в версии X, сделай git diff между X-1 и X по указанному файлу. В случае CVE-2026-51303 этого хватило бы: изменений в expr.c там ноль.
  • Проверка ссылок на код — третий фильтр, самый дешёвый из всех. Существует ли функция в заявленной версии (git grep по тегу), лежит ли указанная строка внутри файла (wc -l). Ловит четыре из шести разобранных случаев за минуту.
  • Прогон PoC под sanitizer'ом — окончательный ответ, если первые три фильтра дали неоднозначный результат. Сборка в контейнере с ASan занимает больше времени, зато выдаёт факт, а не оценку вероятности.

Вердикт

Если у тебя автоматическая приоритизация по CVSS или тикеты, открывающиеся по оценке критичности, поставь между фидом и очередью человека или хотя бы три дешёвые проверки: есть ли запись у вендора, есть ли коммит с починкой, существуют ли упомянутые функция и строка. Это минуты работы и они отсеивают ровно тот класс мусора, который теперь генерируется дешевле, чем проверяется.

А если ты собрался поручить триаж уязвимостей AI-агенту — не давай ему права коммитить патчи. Этот инцидент показывает конкретный путь, которым такой агент вносит изменения в рабочий код ради уязвимости, которой никогда не было. Читающий агент полезен, пишущий на этих данных опасен. И да, к своим сканерам стоит относиться так же: оценка 9.8 в NVD теперь означает «кто-то так написал», а не «кто-то это проверил».

Как попробовать проверить любую CVE за пять минут

  1. Открой запись у вендора: для SQLite это sqlite.org/cves.html, для остальных — security-страница проекта. Нет записи у серьёзного проекта — сразу подозрительно.
  2. Проверь существование кода в заявленной версии: git clone репозитория, git checkout <тег версии>, затем git grep -n "имяФункции". Пусто — advisory выдуман.
  3. Проверь номер строки: wc -l путь/к/файлу. Если в advisory строка 3555, а в файле 2706 строк, дальше можно не читать.
  4. Проверь заявленный патч: git diff <версия-до>..<версия-после> -- путь/к/файлу. Пустой дифф при заявленном исправлении — фабрикация.
  5. Если сомнения остались, собери в контейнере с -fsanitize=address и скорми PoC. И сравни свой вывод с методикой JFrog — там весь маршрут расписан по шагам.
$ ls ./related/

Похожие статьи

turbofieldfare-gemma-2gb.md
26B-модель в 2 ГБ памяти: Gemma 4 на восьмигиговом MacBook Air, потому что память подорожала
> · 6 мин

26B-модель в 2 ГБ памяти: Gemma 4 на восьмигиговом MacBook Air, потому что память подорожала

TurboFieldfare держит в памяти только общее ядро модели на 1,35 ГБ, а экспертов под каждый токен стримит с SSD. Gemma 4 26B укладывается примерно в 2 ГБ вместо 14,3 ГБ и выдаёт 5–6 токенов в секунду на 8-гиговом M2 MacBook Air.

ai llm open-source macos
copilot-word-ai-worm.md
AI-червь в Word: Copilot вклеивает чужие инструкции в твой документ, и он заражает следующий
> · 6 мин

AI-червь в Word: Copilot вклеивает чужие инструкции в твой документ, и он заражает следующий

Скрытые инструкции в документе заставляют Copilot for Word изменить создаваемый файл и скопировать в него сам вредоносный промпт белым текстом. Заражённый документ становится новым вектором. На 28 июля атака воспроизводится со всеми митигациями Microsoft.

ai security copilot microsoft
kimi-k3-weights-vs-opus-5.md
Веса Kimi K3 выложили: 2,8T параметров бесплатно и 164 секунды до первого токена
> · 8 мин

Веса Kimi K3 выложили: 2,8T параметров бесплатно и 164 секунды до первого токена

Moonshot выложила веса Kimi K3 27 июля вместе с техническим отчётом. Независимые замеры: Opus 5 впереди по общему баллу, K3 берёт мультимодальность и стоит на 40% дешевле — ценой 164,6 секунды до первого токена против 21,7 у Opus.

ai llm open-source benchmark
subscribe.sh

$ cat /dev/blog/updates

> Свежие заметки о программировании,

> DevOps и AI — прямо в мессенджер

./subscribe