Русскоязычный журнал про Zcash Русскоязычный журнал

Несколько уязвимостей Zcash успешно устранены

Первоисточник: публикация в официальном блоге ZODL | Авторы: Нил Джайю, Дайра-Эмма Хопвуд и Крис Наттикомб (ZODL); Зуко Уилкокс (Shielded Labs) | Перевод и адаптация: ruzcash

Несколько уязвимостей Zcash успешно устранены — обложка

Ключевые моменты

  • В zcashd и Zebra обнаружили и исправили несколько уязвимостей. Среди них были ошибка, способная аварийно завершить работу узлов при обработке определённых транзакций Orchard, расхождение в применении правил консенсуса между двумя реализациями, способное привести к разделению цепочки, ошибка, отключавшая контроль балансов в механизме «турникета» zcashd, а также неопределённое поведение из-за отсутствия проверки переполнения при операциях с целыми числами при расчёте балансов пулов.
  • Уязвимости не использовались для воздействия на основную цепочку. Средства пользователей находятся в безопасности, угрозы конфиденциальности не было.
  • Ни одна из этих уязвимостей сама по себе не позволяла увеличить предложение ZEC. Уязвимость, способная отключить механизм «турникета», не могла причинить такой вред без отдельной ошибки, позволяющей создавать необеспеченные монеты. Даже при их сочетании нарушение ограничений «турникета» в блокчейне было бы публично заметно.
  • Уязвимости передал через процедуру согласованного раскрытия исследователь безопасности Алекс «Scalar» Сол. Это тот же исследователь, который сообщил об уязвимости проверки Sprout в марте 2026 года. Новый отчёт поступил 4 апреля 2026 года. Исправления для zcashd, закрывающие также дополнительные возможные способы эксплуатации, подготовили инженеры Zcash Open Development Lab (ZODL). Исправление для Zebra разработали инженеры Zcash Foundation.
  • Исправления потребовались и zcashd, и Zebra. Обе реализации обновили согласованно до публичного раскрытия информации.
  • До публикации этого материала исправления установили майнинговые пулы, на которые приходится подавляющее большинство вычислительной мощности сети, а также основной оператор, использующий Zebra в майнинговой инфраструктуре.
Затронутые версииИсправленная версия
zcashdот v5.0.0 до v6.12.0 включительноv6.12.1
Zebraот v1.0.0 до v4.3.0 включительноv4.3.1

Кратко

Исследователь безопасности Алекс «Scalar» Сол обнаружил несколько уязвимостей в zcashd и Zebra, двух реализациях полного узла протокола Zcash. Инженеры Zcash Open Development Lab (ZODL) и Zcash Foundation подготовили и проверили исправления для обеих реализаций, а затем согласовали их установку с майнинговыми пулами и операторами узлов до публичного раскрытия информации.

Уязвимости не использовались для воздействия на основную цепочку. Средства пользователей находятся в безопасности, угрозы конфиденциальности не было. Это можно проверить, запустив Zebra v4.3.1 или zcashd v6.12.1. Обе обновлённые реализации независимо проверяют блокчейн Zcash и подтверждают, что в цепочку были добавлены только действительные транзакции.

Наиболее доступная для прямой эксплуатации ошибка присутствовала в zcashd начиная с v5.0.0 и приводила к аварийному завершению работы. Специально сформированная транзакция Orchard могла аварийно завершить работу любого доступного по сети узла zcashd или Zebra. Авторы подтвердили, что в основной сети нет транзакций, вызывающих такое состояние, а до выпуска исправления не поступало сообщений о необъяснимых сбоях узлов. Связанная с ней ошибка представляла собой расхождение между zcashd и Zebra при проверке одного из требований протокола Orchard. С её помощью можно было опубликовать транзакцию, которую zcashd принял бы, а Zebra отклонила бы. Это могло привести к разделению цепочки.

Отдельная ошибка в zcashd, появившаяся в v5.10.0, могла отключить учёт «турникета» Zcash. Этот механизм отслеживает и контролирует балансы ZEC между пулами ценности. Ошибка могла проявиться при определённых сетевых условиях, возникающих в ходе обычной работы одноранговой сети, либо быть вызвана намеренно вредоносным узлом. Сама по себе она не позволяла создавать недействительные транзакции Zcash. Для кражи средств потребовалась бы ещё одна, независимая уязвимость в учёте балансов. Кроме того, любое нарушение ограничений «турникета» было бы заметно всем; одним из способов устранения последствий был бы откат цепочки. Ничего подобного не произошло.

Исправлена и связанная с предыдущей потенциальная проблема zcashd. Она могла позволить вредоносному узлу повредить сохранённые на диске значения учёта цепочки.

В ходе устранения уязвимостей инженеры ZODL также усилили проверки арифметики балансов пулов. Это предотвращает неопределённое поведение в редких случаях, когда специально сформированный блок вызывает переполнение знакового целого числа в C++. Кроме того, обработка исключений при обнаружении переполнения стала безопаснее.

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

Предыстория

В Zcash существует несколько защищённых пулов ценности: устаревший Sprout, Sapling и Orchard. Каждый из них защищён доказательствами с нулевым разглашением. Они гарантируют, что перемещать ZEC могут только действительные транзакции, а новые ZEC появляются исключительно как награда за блок. Прозрачные средства и пул Lockbox также считаются отдельными пулами ценности.

Orchard является текущим защищённым пулом Zcash. Он появился вместе с сетевым обновлением NU5 в мае 2022 года. Две уязвимости из этого отчёта связаны с тем, как правила консенсуса проверяют отдельные поля действий Orchard.

Один из основных защитных механизмов протокола Zcash называется «турникетом». Это правило учёта, которое отслеживает общий баланс ZEC в каждом пуле ценности, включая Sprout, Sapling, Orchard, прозрачный пул и Lockbox, а также ограничивает объём средств, который может переходить между пулами. «Турникеты» описаны в ZIP 209 и разделе 4.17 спецификации протокола Zcash. Они работают как аварийные заслонки. Даже если какая-либо уязвимость позволила бы создать необеспеченную стоимость внутри одного пула, попытка вывести из него избыточную общую стоимость была бы остановлена. Иными словами, это второй рубеж защиты правил баланса, которые должен обеспечивать протокол. Это важно для понимания уязвимости «турникета» из данного отчёта и причины, по которой она сама по себе не угрожала средствам пользователей.

Сообщение стороннего исследователя

Алекс «Scalar» Сол сообщил об уязвимостях в Shielded Labs 4 апреля 2026 года.

После получения отчёта Shielded Labs привлекла основных инженеров ZODL для проверки проблем и подготовки исправлений. Дайра-Эмма Хопвуд и Крис Наттикомб проанализировали и подтвердили уязвимости. Крис Наттикомб подготовил исправления для сбоя Orchard, расхождения правил консенсуса и ошибки учёта «турникета». Дайра-Эмма Хопвуд разработала два защитных исправления для целочисленного переполнения и безопасной обработки исключений, а также дополнительные изменения, вводящие контрольную точку общего объёма ZEC в цепочке и повторный расчёт изменений балансов. Дайра-Эмма Хопвуд и Крис Наттикомб проверили работу друг друга. Зуко Уилкокс подробно изучил и прокомментировал набор исправлений, переданный партнёрам. Авторы материала сообщают, что стали шире применять искусственный интеллект в работе. В отдельных частях анализа и устранения уязвимостей помогала модель Claude Opus 4.6, после чего результаты тщательно проверили специалисты.

6 апреля 2026 года Shielded Labs сообщила о проблемах Zcash Foundation. Конрадо Гувейя из Zcash Foundation подготовил исправление для Zebra, устраняющее сбой Orchard и связанное с ним расхождение правил проверки.

Shielded Labs организовала взаимодействие с майнинговыми пулами и поставщиками инфраструктуры для согласованной установки исправлений. С пулами ViaBTC, Luxor, F2Pool и AntPool, использующими zcashd, связались напрямую для координации обновлений. Компания Foundry, применяющая Zebra в майнинговой инфраструктуре, также получила исправление до его публичного выпуска.

Набор исправлений zcashd, переданный майнинговым пулам, намеренно сделали простым, чтобы снизить риск появления новых ошибок. Версия zcashd v6.12.1 включает эти исправления, а также более широкий набор защитных изменений и проверок. Среди них контрольная точка общего объёма ZEC в цепочке на момент активации NU6.1 и повторный расчёт изменений балансов после неё. Это позволяет обнаружить возможное повреждение сохранённых значений.

Хронология

21 мая 2019 года

  • Проверка «турникета» на уровне консенсуса, описанная в ZIP 209, появилась в выпуске zcashd v2.0.5.

14 июня 2023 года

  • Выпущена Zebra v1.0.

27 августа 2024 года

  • В выпуске zcashd v5.10.0 появилась уязвимость, способная отключить проверку «турникета» и допустить целочисленное переполнение с неопределённым поведением.

4 апреля 2026 года

  • Алекс «Scalar» Сол сообщил об уязвимостях в Shielded Labs.

5 апреля 2026 года

  • Shielded Labs вместе с инженерами ZODL Дайрой-Эммой Хопвуд и Крисом Наттикомбом проверила и подтвердила уязвимости.

6 апреля 2026 года

  • Shielded Labs сообщила о проблемах Zcash Foundation.
  • Началась разработка исправлений. Крис Наттикомб подготовил первые изменения для устранения сбоя Orchard и ошибки учёта «турникета».

10 апреля 2026 года

  • Дайра-Эмма Хопвуд завершила два защитных исправления для неопределённого поведения при целочисленном переполнении и безопасной обработки исключений.
  • Конрадо Гувейя из Zcash Foundation завершил исправление для Zebra.
  • Исправления передали партнёрам экосистемы.

11 апреля 2026 года

  • Майнинговый пул F2Pool установил исправление zcashd.

16 апреля 2026 года

  • Майнинговые операторы Luxor и Foundry подтвердили установку исправлений для zcashd и Zebra соответственно.

17 апреля 2026 года

  • Майнинговый пул ViaBTC подтвердил установку исправления zcashd.
  • Состоялся публичный выпуск zcashd v6.12.1 и Zebra v4.3.1.

Подробности уязвимостей

Сбой узла из-за нейтрального ключа подписи rk в Orchard

В каждом действии транзакции защищённого протокола Orchard присутствует ключ подписи rk, который можно преобразовывать случайным образом. Спецификация протокола Zcash разрешала rk принимать любое значение в группе Pallas, включая нейтральную точку, то есть нейтральный элемент группы. Однако при построении данных для проверки доказательства Orchard и zcashd, и Zebra аварийно завершали работу, если встречали такое значение rk.

Злоумышленник мог передать специально сформированную транзакцию с действием Orchard, в котором rk имел кодировку из одних нулей. Это единственная кодировка нейтральной точки Pallas. Любой узел zcashd или Zebra, получивший и обработавший такую транзакцию, немедленно прекращал бы работу. Постоянная повторная отправка этой транзакции могла помешать узлам участвовать в работе сети.

Обе реализации исправили независимо друг от друга:

  • zcashd. Крис Наттикомб добавил проверку validate_action_encodings() в CheckTransactionWithoutProofVerification. Она выполняется до проверки доказательства как при обработке очереди неподтверждённых транзакций, так и при проверке блоков. Проверка сравнивает rk с его канонической кодировкой из одних нулей и отклоняет любую транзакцию с таким значением, применяя DoS(100, REJECT_INVALID).
  • Zebra. Конрадо Гувейя из Zcash Foundation добавил отклонение на этапе преобразования входных данных. Если rk кодирует нейтральную точку, возвращается ошибка сериализации.

Спецификацию протокола обновят, чтобы согласовать её с реализациями. При расхождении реализации и спецификации обычно безопаснее привести менее строгое правило к более строгому. Тогда влияние на консенсус в худшем случае ограничивается обратно совместимым ужесточением правил сети.

В основной сети Zcash не обнаружено транзакций с нейтральным значением rk. Это подтверждает, что до исправления уязвимость не использовалась в основной цепочке.

Расхождение правил консенсуса для нейтрального одноразового ключа

Раздел 5.4.9.4 спецификации протокола Zcash требует, чтобы одноразовый открытый ключ epk в каждом действии Orchard кодировал ненейтральную точку на кривой Pallas. Zebra проверяла это требование при преобразовании входных данных. zcashd его не проверял.

Из-за этого zcashd и Zebra могли по-разному оценить один и тот же блок. Специально сформированную транзакцию с нейтральным epk принял бы zcashd, но отклонила бы Zebra. Если бы злоумышленник опубликовал такую транзакцию, узлы zcashd и Zebra могли бы разойтись в оценке действительности блока и разделить сеть на две цепочки.

Исправление сбоя, связанного с rk, одновременно устраняет это расхождение. Функция validate_action_encodings() теперь проверяет и rk, и epk. Благодаря этому zcashd полностью соответствует реализации Zebra и спецификации протокола. В основной сети нейтральных значений epk не обнаружено.

Обход учёта «турникета» с помощью повторного заголовка блока

Механизм «турникета» Zcash отслеживает общий баланс ZEC в каждом пуле ценности, включая Sprout, Sapling, Orchard, прозрачный пул и Lockbox, а также контролирует допустимый объём перехода средств между ними. Эти проверки выполняются при подключении блока и требуют известного баланса цепочки для каждого пула. Если баланс пула в цепочке равен nullopt, то есть его значение не отслеживается, соответствующая проверка «турникета» пропускается.

Из-за ошибки в инициализации балансов пулов при обработке блоков zcashd мог получить блок с заголовком, совпадающим с заголовком уже известного блока, и без предупреждения заменить поля балансов пулов в соответствующей записи индекса блоков значениями nullopt. После этого проверка «турникета» отключалась для всех следующих блоков. Получение повторных объявлений одного блока от нескольких узлов является обычным поведением одноранговой сети. Поэтому такое состояние могло возникнуть при нормальной работе, а не только во время намеренной атаки. В случае атаки вредоносный узел мог повторно отправить заголовок любого уже принятого блока и сбросить учёт пулов. Для этого ему не требовалось заниматься майнингом или иметь особый доступ.

Причиной был вызов функции в неправильном месте. SetChainPoolValues инициализирует изменения значений по отдельным пулам и сбрасывает поля балансов цепочки в nullopt, подготавливая их к дальнейшему накоплению. Функция вызывалась в AcceptBlock до проверки, встречался ли ранее этот заголовок блока. Исправление переносит вызов в ReceivedBlockTransactions. Эта функция выполняется только для действительно новых блоков и лишь после проверки корня Меркла. Поэтому повторно переданные или дублирующиеся заголовки больше не могут сбросить учёт пулов. Посмотреть исправление в исходном коде.

Сама по себе эта ошибка не позволяла создать или похитить ZEC. Обход проверки «турникета» не создаёт нарушения баланса. Он только означает, что отдельная независимая уязвимость баланса могла бы причинить вред нескольким пулам, а не остаться в пределах одного. Кроме того, если бы сочетание таких ошибок использовали, блоки с нарушением «турникета» отклонили бы узлы Zebra, а также заново синхронизированные или переиндексированные узлы zcashd. В результате возникло бы публично заметное разделение цепочки. Ничего подобного не произошло.

В zcashd также существовала связанная проблема, которая могла позволить вредоносному узлу повредить сохранённые на диске значения учёта цепочки. Речь идёт об изменениях между балансами цепочки «до» и «после» на определённом блоке. После перезапуска узла «турникет» мог срабатывать на неверном уровне относительно правильных границ.

Если бы описанная выше атака повредила находящиеся в памяти значения изменений в индексе блоков, накопленное значение цепочки обычно стало бы равным nullopt. Повреждённые значения нельзя было бы увидеть напрямую, кроме как через запрос getblock для отдельных блоков, и они не сохранялись бы после перезапуска узла. Однако при некоторых условиях неправильные изменения могли попасть на диск. Исправление добавляет контрольную точку для этих значений на момент активации NU6.1 и заново вычисляет изменения после неё по данным блоков. Если сохранённые значения после контрольной точки не совпадают с пересчитанными, zcashd начиная с v6.12.1 прервёт запуск и потребует переиндексацию. Она исправит значения на диске. Для работы «турникета» достаточно, чтобы они были правильными в основной цепочке после NU6.1. Более ранние изменения доступны только через запрос getblock и больше нигде не используются. Эту проверку прошлых повреждений нельзя провести на узлах, где ради экономии места удаляется часть старых блоков. Такой режим не включён по умолчанию и редко используется в экосистеме Zcash. Владельцам таких узлов следует проверить, что значения пулов цепочки из запроса getblockchaininfo совпадают со значениями узла, хранящего полную историю блоков на той же высоте блока.

«Турникеты» являются важным уровнем защиты, а их правильная работа лежит в основе гарантий безопасности протокола. Авторы считают любое состояние, отключающее этот механизм, приоритетной проблемой, даже если его нельзя использовать самостоятельно.

Защита учёта балансов пулов от целочисленного переполнения

В C++ переполнение знакового целого числа приводит к неопределённому поведению. Компилятор вправе исходить из того, что переполнение невозможно, и оптимизировать окружающий код на основании этого предположения. В функциях zcashd, накапливающих балансы пулов, можно было сформировать вредоносный блок, вызывающий переполнение знакового целого числа при вычислении изменений значений отдельных пулов. В зависимости от компилятора и настроек оптимизации такое неопределённое поведение могло привести к пропуску проверок «турникета», преждевременному завершению проверки консенсуса или неверному расчёту балансов пулов.

Дайра-Эмма Хопвуд устранила проблему двумя исправлениями. Первое добавляет явные проверки диапазона с помощью новой вспомогательной функции MoneyDeltaRange. На каждом этапе накопления в SetChainPoolValues, ReceivedBlockTransactions, ConnectBlock и LoadBlockIndexDB она проверяет, что текущая сумма изменений по каждому пулу остаётся в пределах [-MAX_MONEY, MAX_MONEY]. Эти проверки также защищают от повреждённых значений баланса на диске, которые могла записать прежняя уязвимая версия. Второе исправление добавляет явные обработчики исключений ко всем влияющим на консенсус вызовам функций расчёта значений. Теперь любое значение вне допустимого диапазона приводит к корректному отклонению по правилам консенсуса с DoS(100, REJECT_INVALID), а не к необработанному исключению.

Благодарности

Спасибо Алексу «Scalar» Солу, который обнаружил уязвимости и ответственно сообщил о них, чтобы защитить пользователей Zcash. Это уже второй подобный отчёт исследователя для экосистемы Zcash.

Отдельная благодарность Крису Наттикомбу и Дайре-Эмме Хопвуд из ZODL за тщательный анализ, быструю подготовку исправлений и внимательную взаимную проверку работы.

Спасибо Конрадо Гувейе из Zcash Foundation за исправление Zebra и участие фонда в координации процесса.

Спасибо Джуде Карузо из Shielded Labs. Он тесно взаимодействовал с майнинговыми пулами, централизованными биржами и другими поставщиками инфраструктуры, чтобы защитить их и сеть Zcash.

Благодарим ViaBTC, Luxor, F2Pool и Foundry за установку исправлений до публичного раскрытия информации.


О ZODL: организация разрабатывает кошелёк Zodl и участвует в развитии протокола Zcash. В официальном блоге команда публикует новости о версиях, инструкции и технические материалы.

Подпишитесь на рассылку!

Никакого спама!
Только новости и видео PRO.ZCASH


Поделиться статьёй

Если статья была полезна, поделитесь ею. Скопируйте ссылку ниже или выберите социальную сеть: обложка статьи добавится автоматически.

Ссылка для публикации

Комментировать статью

Форма комментария

Связаться через Zcash-сообщение

Автор pro.zcash может получить ваше сообщение по указанному Zcash-адресу.

Для этого нужен кошелёк с поддержкой защищённых транзакций. Просто отсканируйте QR-код справа.

Сообщества pro.zcash