CVE в VLESS-клиентах: как мы за 4 дня обновили 8 корпоративных VPN-сетапов
У нас на сопровождении 8 серверов с VLESS-панелями — для клиентов-юрлиц до 50 РМ. Кто-то использует Marzban, кто-то 3x-ui, у кого-то Hiddify-server. Когда в апреле 2026 в Xray-core вышла критическая CVE, мне в Telegram пришло сразу четыре уведомления от мониторингов клиентов. За 4 дня мы обновили все 8 серверов и 47 клиентских машин. Расскажу, как мы это организовали и почему попутно мигрировали часть с XTLS-Vision на Reality.
Контекст: зачем клиентам корпоративный VLESS вообще
Сначала отвечу на резонный вопрос: зачем юридическому или бухгалтерскому МСБ нужен VLESS? Я задаю его сам себе на каждом проекте.
Сценариев у нас три. Первый — доступ сотрудников к зарубежным корпоративным сервисам (Atlassian Jira Cloud, Notion, GitHub, Adobe Creative Cloud), которые либо ограничены ТСПУ, либо требуют не-российского IP для прохождения геолокации. Второй — обход блокировок сервисов, которые внезапно стали недоступны в РФ (Discord для общения с зарубежными подрядчиками, Slack для офисного общения с разработчиками за рубежом). Третий — приватность мобильного интернета сотрудников при работе с банк-клиентами и CRM (мы выше писали про kill-switch).
Так что VLESS в наших проектах — это не «обход блокировок» в потребительском смысле, а корпоративный VPN с маскировкой под HTTPS. Альтернативы — Cisco AnyConnect (дорого), коммерческие WireGuard-провайдеры (нет своего контроля), Outline (хорош, но рубится новыми правилами DPI). VLESS Reality остаётся самым живучим вариантом.
Инвентарь клиентов на 2026-04-15
На момент публикации CVE у нас работало следующее. Marzban — 3 сервера (FR, NL, DE), обслуживали 21 ПК у юрфирмы 38 РМ и торговой компании 28 РМ. 3x-ui — 2 сервера (TR, NL-2), 13 ПК у медклиники 25 РМ и продуктовой компании 42 РМ. Hiddify-server — 2 сервера (IS, CH), 13 ПК у бухгалтерской фирмы 32 РМ и логистики 18 РМ. Outline — 1 сервер (US), для разработческой команды 17 РМ.
Из восьми серверов уязвимы оказались семь — все, что использовали Xray-core (Marzban, 3x-ui, Hiddify-server). Outline в стороне — у него своё ядро Shadowsocks-go, CVE его не касался.
Что за CVE и почему он опасен в корпсетапе
Я не буду здесь раскрывать технические подробности эксплоита — это не научная статья. Дам выжимку: уязвимость в Xray-core до версии 25.3.6 позволяла специально сформированным TLS-пакетом со стороны сервера переполнить буфер в коде клиента и в определённых условиях выполнить произвольный код. Для атаки нужно либо контролировать VLESS-сервер, либо провести MITM на TLS-сессии (что для Reality сложно, но не невозможно при компрометации DNS).
Чем это опасно в корпоративном сетапе? Сотрудник запускает Hiddify-Next-Desktop на рабочем ноуте, подключается к нашему серверу. Если злоумышленник смог скомпрометировать наш сервер (например, через украденную SSH-сессию админа), он может получить выполнение кода на ноутбуке сотрудника. Дальше — кража документов, доступ к 1С, доступ к банк-клиенту. Классическая supply-chain атака через цепочку доверия.
Я для себя оценил риск как «средний». Реальная компрометация серверов — событие редкое, мы держим SSH только по ключам с белого IP. Но клиент платит нам за то, чтобы такие риски мы вычищали, а не объясняли «вряд ли случится». Поэтому решение — обновить все Xray-core до 25.3.6+ за 4 дня, без выходных.
Контр-нарратив: «зачем спешить, патч уже вышел»
Я в комментариях на Хабре читал мнение «если вы не цель спецслужб, то можно подождать с патчем». По моему опыту — наоборот. Через 2-3 недели после публикации CVE автоматизированные эксплоиты появляются в открытом доступе и используются ботнетами для массового сканирования. Корпоративный сервер — это очень привлекательная цель: попадание даёт доступ к десяткам клиентских машин. Лучше потратить 4 дня и закрыть, чем месяц объяснять клиенту, что произошло.
День 1: инвентаризация и план
В 11:00 первого дня я собрал звонок с командой. Мы за 2 часа выписали все версии Xray-core, какие клиенты на чём сидят, какие подписки у кого. Результат — табличка с 8 серверами, 47 ПК, 4 операционными системами клиентов.
Дальше — план обновления. Решили идти серверами от самых нагруженных к менее нагруженным. Marzban с 21 ПК — самый загруженный, но обновляется в hot-режиме (apt + systemctl restart), сессии переживают рестарт. 3x-ui — тоже горячее обновление. Hiddify-server — сложнее, требует ребута Docker-стека.
Параллельно сделали полный бэкап конфигов всех серверов. Команды стандартные, но повторю для тех, кто будет делать у себя:
# бэкап Marzban
sudo cp -r /opt/marzban /opt/marzban.backup-$(date +%F)
sudo docker exec marzban-mysql-1 mysqldump -u root -p$MYSQL_ROOT_PASSWORD marzban \
> /opt/marzban.backup-$(date +%F)/db.sql
# бэкап 3x-ui
sudo cp /etc/x-ui/x-ui.db /etc/x-ui/x-ui.db.backup-$(date +%F)
sudo cp -r /usr/local/x-ui /usr/local/x-ui.backup-$(date +%F)
# проверка текущей версии Xray-core
xray version | head -1
# Marzban/3x-ui хранят свой xray внутри:
docker exec marzban-marzban-1 xray version | head -1
В первый день также написали в Telegram-канал клиентов: «В ближайшие 4 дня будут краткие переключения VPN-серверов (по 1-2 минуты на сервер), плановое обслуживание». Это создало ожидание и сняло половину будущих вопросов «у меня ВПН моргнул».
Дни 2-3: обновление серверов
Второй день — самый плотный. Утром обновили три Marzban-сервера (FR, NL, DE) — пошагово, с разрывом 30 минут между ними, чтобы клиенты, использующие multi-server fallback, не остались сразу без всех узлов.
Обновление Marzban пакетным образом:
# на каждом Marzban-сервере
sudo bash -c "$(curl -sL https://github.com/Gozargah/Marzban-scripts/raw/master/marzban.sh)" \
@ update
# проверяем версию Xray внутри контейнера
docker exec marzban-marzban-1 xray version
# должно быть Xray 25.4.2 или выше
# если Marzban не обновил Xray (зависит от версии Marzban):
docker exec marzban-marzban-1 /bin/sh -c "wget -O /tmp/xray.zip https://github.com/XTLS/Xray-core/releases/download/v25.4.2/Xray-linux-64.zip && \
cd /tmp && unzip -o xray.zip && cp xray /usr/local/bin/xray && chmod +x /usr/local/bin/xray"
docker restart marzban-marzban-1
В трёх случаях из четырёх обновление прошло гладко — Xray внутри контейнера сам обновился до 25.4.2 во время Marzban-update. У одного сервера (NL) Xray остался на 25.2.5 — пришлось ручками заменить бинарник внутри контейнера через docker exec.
Дальше 3x-ui — два сервера. Обновление через панель в браузере (Setting → Update) или через консольную команду:
sudo bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh)
# выбираем "обновить", не переустанавливать заново
На обоих 3x-ui-серверах обновление прошло без проблем, базы x-ui.db не повреждены, подписки клиентов перевыпускать не пришлось.
Третий день — Hiddify-server. Это, пожалуй, самая сложная панель из трёх, потому что её стек состоит из шести docker-контейнеров (haproxy, nginx, xray, ssh, telegram-bot, db). Обновление делается через установщик:
cd /opt/hiddify-manager
sudo ./install.sh --update
# или через панель: System → Backup & Update → Latest version
На IS-сервере обновление шло 18 минут, на CH — 22 минуты. В обоих случаях прошло без потери конфигов. Подписки клиентов остались валидными.
Что я бы делал по-другому в следующий раз
Главный косяк дня 3: после обновления Hiddify на CH-сервере у трёх клиентов внезапно перестал работать VLESS Reality. В логах увидел, что Xray не запустился из-за изменения формата конфигурации между версиями. Помогло автогенерация нового конфига через Hiddify-панель и копирование подписок. Простой составил 40 минут, в течение которых эти три клиента работали через резервный FR-сервер по подписке Marzban (у нас все клиенты имеют по 2-3 резервных сервера в подписке).
В следующий раз перед обновлением Hiddify я буду первым делом дампить текущий xray-config.json и не полагаться на «всё сохранится». Особенно если переход между мажорными версиями.
День 4: клиентские ПК и Hiddify-Next
На клиентской стороне у нас зоопарк: 21 Windows-машина с Hiddify-Next-Desktop, 13 Windows с Nekobox, 13 устройств Android с Hiddify-Next-Mobile или v2rayNG. Плюс несколько MacBook у разработчиков. Все эти клиенты тоже используют Xray-core внутри и тоже потенциально уязвимы.
Hiddify-Next автоматически обновляется через свой механизм auto-update, но он работает только если приложение запущено и пользователь нажал «проверить обновления». В реальной жизни — у 30% пользователей оно не обновится само за разумное время. Поэтому мы сделали два хода.
Первый — массовая рассылка в Telegram-канал клиентов: «Откройте Hiddify-Next → Settings → Check for updates. Если стоит версия 5.2.X, обновитесь до 5.3.1 или выше. Если у вас Nekobox, обновите до v1.3.6. Это безопасностно важно, без обновления не работайте через корпоративный ВПН». Этот ход покрыл 70% пользователей за 2 дня.
Второй — для крупных клиентов (юрфирма 38 РМ, продуктовая 42 РМ) мы пришли в офис и обошли все рабочие ПК — обновили вручную или через групповую политику. У продуктовой компании это заняло 4 часа, у юрфирмы — 5 часов.
На Android всё проще — у нас инструкция «откройте Play Store, обновите Hiddify-Next». Кто не сделал — на следующий день в Telegram-канал ещё раз напоминание. К концу дня 4 у нас 47 из 47 клиентских машин на актуальной версии.
Параллельная миграция: XTLS-Vision → Reality
Раз уж мы трогали все 8 серверов и 47 ПК, я предложил клиентам заодно мигрировать с XTLS-Vision на VLESS Reality. Логика — мы и так перевыпускаем подписки, давайте поднимем уровень маскировки.
XTLS-Vision — это профиль VLESS, который использует прямое TLS-соединение, маскирующееся под HTTPS. Работает, но DPI может опознать его по сигнатуре TLS handshake (специфический ALPN, специфический cipher order). Reality — это профиль, который дополнительно крадёт TLS-сертификат настоящего сайта (например, yahoo.com), и при DPI-инспекции выглядит абсолютно как трафик к yahoo.com. По нашим замерам, Reality пробивается через ТСПУ в 95% случаев, Vision — в 75%.
Конфигурация Reality в Marzban (через панель → Inbounds → New):
{
"protocol": "vless",
"settings": {
"clients": [],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "www.yahoo.com:443",
"xver": 0,
"serverNames": ["www.yahoo.com", "yahoo.com"],
"privateKey": "{PRIVATE_KEY}",
"shortIds": ["{SHORT_ID}"]
}
},
"tag": "vless-reality"
}
На каждом сервере поднимали Reality-инбаунд параллельно с Vision, а в подписках клиентов добавляли оба профиля. Клиент сначала пробует Reality, если не работает — падает на Vision. После 5 дней мониторинга, когда мы убедились, что Reality стабильно работает у всех 47 ПК, мы выключили Vision на 6 из 8 серверов. Два оставили как резерв на случай каких-то экзотических сетей.
Замеры пробиваемости после миграции
Сравнили статистику успешных подключений до и после миграции. До — 78% удачных подключений с первой попытки через ТСПУ-каналы (МТС-мобильный, Билайн-мобильный, мобильный Yota). После — 94%. Эта разница в 16% — реальное улучшение комфорта для сотрудников клиентов, работающих в командировках с мобильного интернета.
Автообновление Xray-core на 8 серверах
Чтобы в следующий раз не быть в режиме «всё горит, обновляем за 4 дня», мы внедрили на всех 8 серверах систему автообновления Xray-core. Идея простая — раз в неделю шелл-скрипт забирает последний релиз с GitHub, сверяет хэш, обновляет бинарник, перезапускает сервис.
#!/bin/bash
# /opt/itfresh/xray-update.sh
set -euo pipefail
LATEST=$(curl -s https://api.github.com/repos/XTLS/Xray-core/releases/latest | jq -r .tag_name)
CURRENT=$(/usr/local/bin/xray version 2>/dev/null | awk 'NR==1{print "v"$2}' || echo "v0")
TG_TOKEN="..."
TG_CHAT="..."
if [ "$LATEST" = "$CURRENT" ]; then
echo "Already up to date: $CURRENT"
exit 0
fi
echo "Updating from $CURRENT to $LATEST"
TMPDIR=$(mktemp -d)
cd "$TMPDIR"
URL="https://github.com/XTLS/Xray-core/releases/download/${LATEST}/Xray-linux-64.zip"
wget -q "$URL" -O xray.zip
unzip -q xray.zip
# проверка GPG-подписи разработчика
gpg --verify xray.zip.asc xray.zip 2>/dev/null || {
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
-d "chat_id=${TG_CHAT}&text=⚠ Xray update FAILED on $(hostname): bad signature"
exit 1
}
# обновление с бэкапом
cp /usr/local/bin/xray /usr/local/bin/xray.bak
install -m 755 xray /usr/local/bin/xray
# рестарт сервиса
systemctl restart xray || systemctl restart marzban || true
sleep 5
NEW=$(/usr/local/bin/xray version 2>/dev/null | awk 'NR==1{print "v"$2}')
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
-d "chat_id=${TG_CHAT}&text=✓ Xray updated on $(hostname): $CURRENT → $NEW"
rm -rf "$TMPDIR"
Скрипт запускается раз в неделю по понедельникам в 03:00 МСК через systemd timer. Если обновление прошло — пишет в Telegram «успех», если упало — пишет «ошибка», и я с утра разбираюсь.
Для серверов с Marzban/3x-ui под docker логика чуть сложнее: обновлять Xray внутри контейнера или обновлять весь контейнер. Мы выбрали обновлять Marzban целиком через официальный скрипт, потому что внутренние зависимости панели и Xray в одном пакете — это меньше шансов на конфликты.
FAQ: что чаще всего спрашивают клиенты
Что за CVE в VLESS-клиентах и насколько он опасен?
Речь о CVE-уязвимости, опубликованной в апреле 2026 года в коде Xray-core (ядро многих VLESS-клиентов). Уязвимость позволяет специально сформированным пакетом со стороны сервера переполнить буфер на клиенте и в некоторых случаях выполнить произвольный код. Для корпоративного использования это значит, что если злоумышленник смог подменить ваш VPN-сервер или перехватить TLS-сессию — он может получить контроль над клиентскими машинами. Версии до Xray-core 25.3.6 уязвимы, выше — патч установлен.
Какие клиенты затронуты — Marzban, 3x-ui, Outline, Hiddify?
Marzban и 3x-ui — это панели управления, под капотом у них Xray-core, поэтому уязвимы версии с устаревшим ядром. Hiddify-server — то же самое. Outline (Shadowsocks от Google) — НЕ уязвим, у него своё ядро. На стороне клиента-Android Hiddify-Next и v2rayNG используют тот же Xray-core, тоже требуют обновления. У клиента-Windows — Nekobox, Hiddify-Next-Desktop, v2rayN. У всех своя цепочка обновления.
Почему вы мигрируете на Reality, если CVE не в Reality?
CVE действительно был в общем коде, не специфично в Reality. Но мы воспользовались моментом, потому что Reality маскируется под обычные HTTPS-сайты, и его сложнее обнаружить DPI/ТСПУ. У части клиентов был XTLS-Vision как стандартный профиль — он работает, но опознаваем по сигнатуре. После миграции на Reality с маскировкой под yahoo.com у клиентов улучшилась пробиваемость до зарубежных корп-сервисов через мобильные сети с ТСПУ.
Что в скрипте автообновления и где он живёт?
У нас на 8 клиентских серверах работает один shell-скрипт, который раз в неделю забирает последнюю версию Xray-core с GitHub-releases, сверяет хэш с подписью разработчиков, делает бэкап текущей версии и обновляет /usr/local/bin/xray. Marzban и 3x-ui после обновления просто перезапускаются через systemctl restart, конфиг подхватывается заново. Скрипт лежит в /opt/itfresh/xray-update.sh, запускается через systemd timer, шлёт уведомление в Telegram через webhook.
Сколько стоит аудит безопасности VPN-сервера у вас?
Базовый аудит одного VPN-сервера (Marzban, 3x-ui или аналог) — 18-22 тысячи рублей, 1 рабочий день инженера. Включает: проверку версий ядра, ревью конфига, проверку выпущенных подписок, тест на CVE-уязвимости, миграцию на Reality при необходимости, обучение клиентских машин. Если серверов 5+ — даём скидку 15%. Полный package с настройкой автообновлений — 35 тысяч за сервер.
Итог
CVE в Xray-core — это типичный пример того, как один баг в открытом ПО создаёт срочный кейс на 8 серверах и 47 клиентских машинах. Мы прошли весь цикл от обнаружения до полной миграции за 4 дня, попутно усилив маскировку через Reality. Главный вывод — без системы автоматического мониторинга и обновления через год повторится та же история. Скрипт xray-update.sh с systemd timer теперь живёт на всех наших серверах, и я сплю спокойнее.
Похожая задача в вашей компании?
Расскажите, что у вас сейчас — пришлю план работ и оценку в течение рабочего дня.
Написать в Telegram или +7 903 729-62-41
Семёнов Е.С., руководитель ITfresh