Перейти к содержимому
OmniRoute source

Socket.dev / supply-chain finding attestation (Русский)

Исходные файлы:

  • src/mitm/cert/install.ts — публичные installCert() / uninstallCert(), платформозависимые installCertWindows/Mac/Linux.
  • src/mitm/systemCommands.ts — общие вспомогательные функции execFile / spawn / PowerShell, используемые путями установки.

Условие запуска: пользователь нажимает «Включить MITM-прокси» на локальной панели управления по адресу /dashboard/cli-tools/mitm. Маршрут доступен только через loopback-интерфейс — см. строгое правило №17 в CLAUDE.md и src/server/authz/routeGuard.ts::isLocalOnlyPath(). Утёкший JWT, раскрытый через туннель, не может активировать этот путь кода.

Выполняемые привилегированные операции (для каждой платформы):

ОС Команда(-ы)
Windows certutil -addstore Root <cert> через UAC
macOS sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <cert>
Linux sudo cp <cert> <distro-trust-dir> + sudo update-ca-certificates (Debian) / sudo update-ca-trust (RHEL/SUSE)
Linux+Firefox/Chromium обновление базы данных NSS для каждого профиля через certutil -d sql:<profile>

Эти же команды используются в mitmproxy, Charles Proxy, Fiddler и Caddy. Факт их наличия в OmniRoute задокументирован в docs/security/STEALTH_GUIDE.md.

Меры по устранению в v3.8.6:

  • runElevatedPowerShell() больше не использует -EncodedCommand <base64utf16le>. Полезная нагрузка для запуска с повышенными привилегиями записывается в отдельный для каждого вызова временный файл .ps1 (режим 0o600, внутри приватного каталога mkdtempSync) и указывается через -File. Файл удаляется в блоке finally. Это устраняет классическую сигнатуру повышения привилегий через PowerShell с использованием base64, отмеченную ИИ-классификатором Socket.dev.
  • installCertWindows содержит встроенный блок SECURITY-AUDITOR-NOTE:, ссылающийся на этот документ.

Почему мы сохраняем эту функциональность: MITM-прокси — это документированная возможность, описанная в docs/security/STEALTH_GUIDE.md и docs/frameworks/MITM-PROXY.md. Её удаление нарушило бы работу набора функций моста агентов.


§2 — Импорт учётных данных Zed (app/api/providers/zed/import/route.js)

Заголовок раздела «§2 — Импорт учётных данных Zed (app/api/providers/zed/import/route.js)»

Исходные файлы:

  • src/app/api/providers/zed/discover/route.ts (добавлен в v3.8.6)
  • src/app/api/providers/zed/import/route.ts
  • src/lib/zed-oauth/keychain-reader.ts
  • src/lib/zed-oauth/credentialFingerprint.ts (добавлен в v3.8.6)

Условие запуска: пользователь нажимает «Импортировать из Zed» на странице провайдеров локальной панели управления. Доступ к конечной точке ограничен с помощью requireManagementAuth. Сам редактор Zed записывает API-ключи провайдеров в хранилище ключей ОС под документированными именами служб — см. https://zed.dev/docs/ai/llm-providers.

Поведение v3.8.5 (на которое указал Socket.dev):

POST /import обнаруживал учётные данные и автоматически сохранял их в локальном хранилище SQLite за один запрос. Без подтверждения для каждой учётной записи, без отпечатка — только «найдено N токенов, все импортированы».

Меры по снижению риска в v3.8.6 — двухэтапное подтверждение:

  1. POST /api/providers/zed/discover возвращает { candidates: [{ provider, service, account, fingerprint }] }. Необработанный токен никогда не передаётся. Отпечаток вычисляется как sha256(service|account|token).slice(0,16).
  2. Панель управления отображает список кандидатов, оператор выбирает, какие из них импортировать, и отправляет { confirmedAccounts: [{ service, account, fingerprint }] } в POST /api/providers/zed/import.
  3. Конечная точка импорта повторно считывает хранилище ключей на сервере и фильтрует по (service, account, fingerprint). Подделанный или повторно воспроизведённый ответ обнаружения не может заставить конечную точку импорта сохранить посторонний токен — если актуальный токен изменился с момента обнаружения, отпечаток больше не совпадёт, и учётные данные будут пропущены.

Переменная окружения OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true сохраняет поведение v3.8.5 для операторов, которые ещё не обновили свою автоматизацию. Она будет удалена в v3.9.

Почему мы сохраняем эту возможность: импорт из Zed — наиболее удобный способ первоначальной настройки для пользователей, которые уже используют Zed и хотят скопировать ключи своих провайдеров в OmniRoute без повторной вставки.


§3 — execFile / spawn / PowerShell с повышенными привилегиями (21843.js)

Заголовок раздела «§3 — execFile / spawn / PowerShell с повышенными привилегиями (21843.js)»

Исходные файлы: src/mitm/systemCommands.ts.

Почему отмечено: чанк повторно экспортирует execFileWithPassword, runElevatedPowerShell и общий вспомогательный модуль quotePowerShell. ИИ-классификатор Socket.dev расценивает их как универсальный «инструментарий для выполнения команд на хосте и повышения привилегий». В OmniRoute они используются только в процессе установки MITM-сертификата (§1), а также функцией execFileWithPassword для выполнения команд через sudo.

Меры по снижению риска в v3.8.6:

  • Рефакторинг runElevatedPowerShell (см. §1).
  • Встроенный блок SECURITY-AUDITOR-NOTE: в runElevatedPowerShell и execFileWithPassword документирует вызывающие стороны из списка разрешённых и закреплённый список исполняемых файлов.
  • Вызов spawn() в execFileWithPassword содержит маркер nosemgrep со списком разрешённых исполняемых файлов, которые может принимать вспомогательная функция, — путь от пользовательского ввода к finalCommand/finalArgs отсутствует.

§4 / §6 — Супервизор службы 9router (api/services/9router/{start,restart}/route.js)

Заголовок раздела «§4 / §6 — Супервизор службы 9router (api/services/9router/{start,restart}/route.js)»

Исходные файлы:

  • src/app/api/services/9router/_lib.ts — фабрика супервизора.
  • src/app/api/services/9router/{start,stop,restart,status,install,update,auto-start}/route.ts.
  • src/lib/services/ServiceSupervisor.ts — универсальный запуск процессов / опрос состояния / буфер журналов.

Условие запуска: пользователь нажимает «Установить» / «Запустить» на странице встроенных служб в локальной панели управления.

Уже реализованные меры защиты:

  • Все маршруты /api/services/* имеют статус LOCAL_ONLY согласно src/server/authz/routeGuard.ts (жёсткое правило №17). Проверка обращения через loopback-интерфейс выполняется до любой проверки аутентификации — утёкший JWT не позволит получить к ним доступ.
  • Строка 9router в БД создаётся со значениями status='not_installed', auto_start=0 (см. src/lib/db/migrations/071_services.sql:19). Служба не запускается при первом старте.
  • spawn() вызывается с путём к бинарному файлу, возвращённым resolveSpawnArgs(apiKey, PORT) в src/lib/services/installers/ninerouter.ts, где задан фиксированный список разрешённых поддерживаемых бинарных файлов.
  • Stdout/stderr буферизуются в памяти (ограничение — 5 МБ, см. _lib.ts) — запись на диск не выполняется, если пользователь не включит журналирование в панели управления.

Меры по снижению риска в v3.8.6: функциональных изменений нет. Минимальный профиль сборки (OMNIROUTE_BUILD_PROFILE=minimal) заменяет src/lib/services/installers/ninerouter.ts заглушкой для пользователей, которые хотят физически удалить из сборки пути с повышенными привилегиями.

Почему мы сохраняем эту возможность: 9router — необязательная локально устанавливаемая сопутствующая служба (аналог плагина WordPress), которая активируется исключительно по явному согласию пользователя.


§5 — Обратная запись учётных данных OmniRoute Cloud Sync (api/keys/[id]/route.js)

Заголовок раздела «§5 — Обратная запись учётных данных OmniRoute Cloud Sync (api/keys/[id]/route.js)»

Исходные файлы:

  • src/lib/cloudSync.ts — syncToCloud() / updateLocalTokens().
  • src/app/api/keys/[id]/route.ts — вызывает syncKeysToCloudIfEnabled().

Условие срабатывания: isCloudEnabled() возвращает true (задаётся через панель управления) и настроена переменная CLOUD_URL. Если оба параметра отключены, исходящий сетевой вызов конечной точки Cloud не выполняется.

Поведение v3.8.5 (ошибка, которую Socket.dev корректно обнаружил):

updateLocalTokens() перезаписывала accessToken, refreshToken и providerSpecificData данными из ответа Cloud, когда cloudUpdatedAt > localUpdatedAt. Без HMAC, подписи или контрольной суммы. Неверно настроенный или вредоносный CLOUD_URL (либо MITM-атака на канал) мог незаметно подменить OAuth-токены провайдера.

Меры защиты в v3.8.6:

  1. Проверка HMAC: verifyCloudSignature(rawBody, sigHeader) проверяет заголовок X-Cloud-Sig (HMAC-SHA256(OMNIROUTE_CLOUD_SYNC_SECRET, rawBody)) перед разбором JSON. Если секрет задан, подпись обязательна. Если он не задан (устаревший режим), в журнал записывается предупреждение, а ответ принимается — в v3.9 секрет станет обязательным.
  2. Явное включение секретных полей: accessToken / refreshToken / providerSpecificData перезаписываются только при OMNIROUTE_CLOUD_SYNC_SECRETS=true. В режиме по умолчанию синхронизируются только метаданные, не содержащие учётных данных (expiresAt, status, lastError*, rateLimitedUntil, updatedAt). Это критическое изменение для пользователей, которые полагались на удалённую синхронизацию токенов: им необходимо явно включить эту возможность.

Почему мы сохраняем эту функцию: Cloud Sync — единственный способ для арендатора OmniRoute Cloud централизовать учётные данные команды. Исправление делает модель угроз прозрачной: «сервер подписывает, клиент проверяет, оператор явно разрешает».


Пользователи, которым нужен совместимый с Socket артефакт, могут собрать его командой:

Окно терминала
OMNIROUTE_BUILD_PROFILE=minimal npm run build

NormalModuleReplacementPlugin в webpack подменяет четыре модуля заглушками:

Модуль Заглушка
src/mitm/cert/install.ts src/mitm/cert/install.stub.ts
src/lib/zed-oauth/keychain-reader.ts src/lib/zed-oauth/keychain-reader.stub.ts
src/lib/cloudSync.ts src/lib/cloudSync.stub.ts
src/lib/services/installers/ninerouter.ts src/lib/services/installers/ninerouter.stub.ts

Каждая заглушка экспортирует тот же интерфейс, но каждая функция во время выполнения выбрасывает featureDisabledError(name). Маршруты, зависящие от отключённого модуля, возвращают HTTP 503 с понятным сообщением вместо активации чувствительного пути выполнения кода.

Полученный пакет предназначен для публикации под именем omniroute-secure. Инструкции по публикации см. в docs/ops/PUBLISHING_SECURE.md.


В долгосрочной перспективе мы планируем разделить пакет npm на модули, которые можно проверять по отдельности. Задачу для отслеживания хода работ см. в этапе v4 в трекере задач GitHub.


Исходный код OmniRoute (a58000c7685f)

HagiCode

HagiCode — агентная среда разработки со структурированными процессами, параллельным выполнением несколькими агентами и интерфейсами Hero Dungeon.

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

Главный экран HagiCode в светлой теме
  • SmartСтруктурированные процессы превращают намерение в исполнимый путь от идеи до готового изменения.
  • EfficientМультиагентные процессы параллельно продвигают исследование, реализацию и проверку.
  • FunHero Dungeon делает длительную совместную разработку наглядной и увлекательной.
Перейти на HagiCode