Перейти к основному содержанию

nebula-mesh: 23 уязвимости за четыре с половиной месяца

В мае писал про nebula-mesh1 — панель управления для Nebula, которую собрал сам. Всего у проекта уже 41 релиз, а в разделе Security Advisories репозитория2 появилось 23 опубликованные записи, 16 из них получили номера CVE. Я собираюсь рассказывать о проекте шире, и первым вопросом к панели, которая хранит ключи центра сертификации, будет вопрос о безопасности. Поэтому начну с него сам.

Цифры

КритичностьКоличество
Critical1
High10
Medium10
Low2

По времени записи распределились неравномерно: 12 в мае, 6 в июне, одна в июле, ни одной в августе и четыре в конце сентября. Все исправлены, последние четыре — в версиях 0.17.1 и 0.18.0 от 29 сентября.

Нашли их разные люди. Двенадцать майских прислал один человек, Адам (ak2k ). Три июньские найдены при собственных проверках кода. Остальные восемь сообщили ещё пятеро. Две записи вышли по отчёту Нгуена Хюи Ву Зунга (dungNHVhust ) и Тхай Шон Диня (sondt99 ), по одной прислали Адам Джордан (adamyordan ) и Pig-Tail , четыре сентябрьские нашёл Дэниел Коулз (manus-pi ).

Первая волна

Первый релиз вышел 11 мая. Через восемь дней Адам попросил включить закрытый приём сообщений об уязвимостях, и за следующие шесть дней по его отчётам вышло двенадцать записей.

Самая тяжёлая из них получила оценку critical3. API проверял только токен и не проверял, кому принадлежит объект запроса. Оператор с обычным ключом мог выпустить API-ключ для любого другого оператора, в том числе для администратора, и получить полные права. Для центров сертификации проверка была, для хостов, сетей и правил firewall — нет, и в коде об этом прямо говорил комментарий.

Остальное из той же волны — привычный набор для молодого веб-приложения: не было CSRF-токенов, заголовков безопасности и флага Secure у cookie, токены регистрации лежали в базе открытым текстом, а через дополнительные параметры хоста можно было подмешать свой YAML в конфиг агента.

История закончилась хорошо: Адам не только сообщал, но и чинил. Сейчас за ним 48 pull request’ов, и он второй по вкладу человек в проекте.

Отзыв, который не отзывал

Эту запись я считаю самой неприятной, хотя оценка у неё high, а не critical4.

В Nebula нет ни CRL, ни OCSP. Отозвать сертификат можно одним способом: внести его отпечаток в список pki.blocklist в конфиге каждого узла. В nebula-mesh была кнопка «Заблокировать». Сервер добавлял отпечаток в список и отдавал его агентам при каждом опросе. Агент список получал, разбирал и выбрасывал. Генератор конфига поля blocklist вообще не знал.

В панели хост значился заблокированным, в журнале была запись. А в самой сети его сертификат продолжал работать до конца срока: до 30 дней у хоста с агентом и до 365 дней у телефона.

Тесты проекта не поднимали настоящую Nebula и не проверяли, что заблокированный узел действительно теряет связь. Такой тест описан в плане проекта и до сих пор не написан; это один из открытых пунктов в списке готовности к промышленной эксплуатации5.

Одна ошибка, четыре раза

Если разложить записи по типам, видно, что большинство — повторы.

Класс ошибкиЗаписей
Нет проверки, чей это объект4
Ключ CA остаётся в памяти после использования4
Секрет лежит в базе открытым текстом3
Отзыв сертификата не доходит до сети3

Про ключ CA в памяти сообщали в мае, в июне и дважды в сентябре — каждый раз в новом месте кода. С открытым текстом в базе то же самое: сначала токены регистрации, потом сессии, потом секреты TOTP.

Каждое исправление закрывало найденное место, а не класс ошибок. Следующий отчёт показывал ту же ошибку в соседней функции.

Что изменилось в проекте

В июле подход поменялся. В репозитории появился документ с инвариантами безопасности6: семь правил, у каждого постоянный идентификатор. Например, SEC-TENANT-001 требует, чтобы область видимости любого запроса выводилась из того, кто его делает, а не из параметров. Правило проекта такое: изменение, которое затрагивает инвариант, не принимается без теста на отказ со ссылкой на его идентификатор.

Часть правил проверяется автоматически. Тест обходит все маршруты работающего роутера, и новый GET-обработчик без явного решения о том, кому он доступен, роняет сборку.

Что ещё добавилось за это время:

  • Модель угроз7 — активы, точки входа, разбор по STRIDE и риски, которые приняты осознанно.
  • Хранение учётных данных. API-ключи, сессии, токены и резервные коды лежат в базе в виде HMAC-SHA-256 с ключом, производным от мастер-ключа. Утечка одной только базы не даёт значения, которое примет сервер.
  • Шифрование секретов TOTP в базе тем же мастер-ключом.
  • Проверки при каждом pull request: детектор гонок, gosec, govulncheck, CodeQL. По ночам — фаззинг.
  • Симуляция сети из многих узлов, которая проверяет изоляцию операторов, одноразовость токенов и распространение списка отзыва.

Тестового кода в репозитории теперь почти вдвое больше, чем рабочего: 57 тысяч строк против 31 тысячи.

Отдельно скажу про то, как пишется код. Я разрабатываю nebula-mesh с помощью AI-агентов, и в репозитории лежит файл AGENTS.md с правилами для них. Инварианты записаны именно там: агент обязан прочитать их перед тем, как трогать аутентификацию, криптографию или хранилище.

Что появилось кроме исправлений

За то же время в проекте появились:

  • команды резервного копирования и восстановления;
  • вебхуки на события жизненного цикла хостов;
  • подключение уже работающей сети Nebula без перевыпуска ключей хостов;
  • агент как служба Windows и графический установщик;
  • правила firewall для отдельного хоста и шлюзы в сети за пределами Nebula;
  • ротация CA с периодом, когда узлы доверяют обоим сертификатам.

Правила firewall для отдельного хоста, шлюзы и графический установщик написал Франсиско Хавьер (inode64 ).

Где проект сейчас

Статус по-прежнему beta. В репозитории есть документ с условиями, при которых проект можно будет назвать готовым к промышленной эксплуатации5. Из 34 пунктов закрыт один.

Среди открытых — независимый аудит, подпись релизов, тест с настоящей Nebula и то, чего я не могу сделать в одиночку: хотя бы один оператор, кроме меня, который держит на nebula-mesh настоящую сеть и рассказывает, что ломается.

Если вы ведёте Nebula на скриптах и готовы попробовать панель на некритичной сети — напишите в Discussions или заведите issue. Если найдёте уязвимость, для этого есть закрытая форма8; судя по истории выше, отчёты там не теряются.


  1. nebula-mesh: панель управления для Nebula, которую я собрал сам — первая статья о проекте. ↩︎

  2. Security Advisories репозитория forgekeep/nebula-mesh. ↩︎

  3. GHSA-598g-h2vc-h5vg , CVE-2026-47724. Исправлено в 0.3.2. ↩︎

  4. GHSA-cm26-5974-52h8 , CVE-2026-61699. Исправлено в 0.7.1. ↩︎

  5. Production readiness — условия и текущее состояние. ↩︎ ↩︎

  6. Security invariants . ↩︎

  7. Threat model . ↩︎

  8. Сообщить об уязвимости . ↩︎