Клиент зашифровал рабочую область и загрузил её. Почему этот локальный шифротекст вам не открыть

18 сентября 2026 разработчик ferstar чистил диск и увидел: клиент для программирования с ИИ в залогиненном состоянии пакует всю рабочую область в шифрованный архив и пытается отправить его прямо в объектное хранилище. Архив — шифротекст. Открытый RSA-ключ, которым заворачивают ключ содержимого, сервер выдаёт на месте, а парный закрытый ключ на компьютер не попадает. Несколько сотен мегабайт «уже зашифрованных» файлов лежат на диске, и их не открыть ни вам, ни клиенту. 21 сентября вендор объявил об открытии исходников и снял цепочку загрузки. Сами слова «зашифровали и загрузили» от этого нулевым знанием не стали.

Сначала вывод. «Уже зашифровано» значит только то, что упакованные байты — не открытая рабочая область. Это не значит, что расшифровать можете вы, и не значит, что облако содержимое не прочитает. В конвертном шифровании симметричный ключ заворачивают открытым ключом, который только что выдал сервер, а закрытый ключ остаётся в облаке. Цель схемы — чтобы облако могло открыть файл. На этой машине сверяются три вещи: открываете ли вы этот шифротекст сами, есть ли в Network открытый текст рабочей области и появляется ли новый пакет после того, как переключатели выключены. «AES посчитали локально» не читайте как «расшифровать могу только я».

Сначала одним предложением — ответ на запрос

Шифрование канала и «ключ у вас» — разные слои. Клиент может на этой машине прогнать AES, превратить рабочую область в шифротекст и отправить его в объектное хранилище. Если открытый ключ, которым заворачивают ключ содержимого, пришёл с сервера, а закрытый ключ в этот компьютер не входил, файл — не резервная копия, которую вы восстановите. Это конверт, который открывает только облако. Наблюдатель в канале открытый текст не видит. Сервер, у которого закрытый ключ, видит.

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

Что разбор на самом деле закрепил

18 сентября 2026 ferstar опубликовал ход разбора. Начиналось это не с соревнования по перехвату пакетов, а с чистки диска. Локальный каталог ~/.zcode занимал больше семисот мегабайт. В v2/checkpoints/ лежал .enc примерно на 313 МБ. Рядом файл состояния: рабочая область около 345 МБ, kind равен baseline, failureCount равен 564. Сам репозиторий был около 10 ГБ. После того как зависимости убрали из пакета, оставшиеся 345 МБ — почти целиком ядро проекта.

Загрузку он восстановил в два шага. Сначала клиент вызывает POST /api/v1/snapshot/upload-credential на zcode.z.ai. Сервер возвращает номер снимка, подпись формы для объектного хранилища, потолок размера и открытый RSA-ключ этого раунда. Затем машина собирает tar.gz, шифрует его одноразовым симметричным ключом по AES-256-CTR, заворачивает этот ключ через RSA-OAEP-SHA256 и отправляет tar.gz.enc формой POST прямо в Alibaba Cloud OSS. Колбэк хранилища регистрирует объект у бэкенда вендора. Прикладной сервер сам файл шифротекста не трогает. Право регистрации и закрытый ключ всё равно остаются в облаке.

В пакет попало не только текущее дерево. Локальный манифест открытым текстом перечислил 42 411 файлов: .git/lfs/ около 196,1 МБ (56,8%), .git/objects/ около 102,2 МБ (29,6%), .git/logs/ около 0,6 МБ, исходники и документы около 46,2 МБ (13,4%). На .git пришлось 86,6%. Успешная загрузка отдала бы облаку историю коммитов, секреты, которые из дерева уже удалили, но они ещё лежат в объектном хранилище Git, имена веток, которые не пушили, и внутренние хосты из .git/config. Второй манифест, уже между рабочими областями, хеширует глобальную конфигурацию и забирает её тоже.

18 сентября в 17:44 вендор написал в сообществе пользователей: загрузка шла из индекса репозитория, включённого по умолчанию, для контрольных точек сессии, отката версии и Repo Wiki, а после генерации Wiki данные сразу уничтожают. 21 сентября «Ежедневные экономические новости» сообщили: ZCode открывает исходники; Китайская академия информационных и коммуникационных технологий оценила бакет zcode-prod как пустой; NSFOCUS сообщила, что бакет и объекты удалены; в клиенте v3.14.0 сняты генерация снимка и цепочка загрузки. ferstar добавил разделение: коммерческий проект на 313 МБ превысил потолок, 564 повтора не ушли за пределы локальной сети. Другая рабочая область, публичный репозиторий из 538 файлов, после сжатия и шифрования заняла около 15 КБ, статус — сервер принял. «Уходило ли что-нибудь с этой машины?» По крайней мере этот маленький пакет уходил.

Почему конверт — это не файл, который открываете вы

AES-256-CTR плюс RSA-OAEP — учебниковый конверт. Содержимое шифруют короткоживущим симметричным ключом, затем этот ключ заворачивают открытым ключом. Имена алгоритмов выглядят крепко. Кто прочитает файл, решает другое: откуда пришёл открытый ключ и где лежит закрытый. В записи прямо сказано: открытый ключ выдают в момент запроса учётных данных на загрузку, парный закрытый ключ в этот компьютер не входит, а развернуть конверт уже имеющимися на машине закрытыми ключами не вышло. Клиент сам не открывает шифротекст на диске.

Это обратная сторона резервной копии, которую вы можете восстановить. Time Machine, локальные объекты Git и файл, который вы шифруете фразой и потом копируете, держат материал для расшифровки у вас: фразу, локальный ключ или связку, которую вы открываете. Когда закрытый ключ только у сервера, цель меняется. Третий на пути байты видеть не должен. После прибытия облако должно уметь их открыть. Собственная формулировка ferstar фиксирует назначение: ключ, которым пользуется только сервер, нужен серверу, чтобы читать ваш код. Для вашего отката он не нужен.

Хэ Юань из Центра исследования права данных Шанхайского университета Цзяо Тун сказал «Ежедневным экономическим новостям» уже: шифрование — мера защиты. Это не анонимизация и не замена уведомления или минимизации данных. Пока у оператора остаётся способность расшифровать, зашифрованные данные всё ещё можно восстановить и обработать. «Удалить сразу после использования» снижает только долгое хранение. Оно не отвечает, была ли первая сборка необходимой. Две фразы рядом: стойкость алгоритма не доказывает, у кого ключ, а заявление об уничтожении не доказывает объём сбора.

Не гоняйте боевой репозиторий, живой облачный ключ или код заказчика, чтобы «воспроизвести загрузку». Сверяйте, есть ли на этой машине уже готовый к отправке шифротекст, какой путь и счётчик ошибок записаны в файле состояния и открываете ли вы этот файл сами. Ещё одна отправка живого репозитория не вернёт закрытый ключ вам в руки.

Манифест открытым текстом уже назвал объём

Шифротекст не открывается. Это не значит, что объём можно только угадывать. Список файлов, который пишется в момент упаковки, остаётся на диске, и он открытый. 42 411 строк разделяют «текущее дерево исходников» и «жизнь репозитория». Текущее дерево — около 13,4%. Остальное — кэш LFS, полное хранилище объектов и reflog. API-ключ, который вы уже удалили из рабочей копии, всё ещё может лежать в .git/objects, если его когда-то коммитили. Имя не запушенной ветки выдаёт функцию, которую ещё не публиковали. Внутреннее имя Git-хоста живёт в .git/config. Чтобы увидеть со стороны манифеста, что его положили в пакет, шифротекст открывать не нужно.

Два переключателя на экране выглядят как общий рубильник. В коде ими не были. После сверки с записью разбора «улучшить опыт» управляет только тем, можно ли данные использовать для обучения модели, а «индекс снимка репозитория» — только тем, строит ли облако индекс. Упаковка и прямая загрузка продолжаются, пока действует JWT входа. Точки захвата стоят перед каждым промптом и на repo-wiki-update, когда задача заканчивается. В одной активной сессии насчитали до 62 захватов. Примерно через полчаса после того, как готовый к отправке пакет удалили руками, появился новый файл на 313 МБ, а счётчик ошибок сдвинулся с 564 на 565. Удалить файл — не выключить переключатель.

Политика конфиденциальности, снятая в архив 18 сентября, на странице всё ещё писала дату последнего обновления 2026-06-15. Объём сбора там — текст, файлы и код, которые вы отправили в разговоре. Там нет фразы «после входа автоматически упаковать всю рабочую область и историю Git». Политика поддерживает одно утверждение: вендор заявил, что собирает то, что вы отправили в сессии. Она не поддерживает другое: что полный снимок уже был написан на странице, с которой вы согласились. И переключатели, и политику надо сверять с артефактом. Есть ли локально новый .enc? Указывает ли workspacePath в файле состояния на коммерческий проект, который вы сейчас пишете?

Что доказывают «зашифровано» и «сразу уничтожили»

Разложите фразы из новости на «это поддерживает» и «это не поддерживает». Так спокойнее, чем идти за прилагательными. Шифротекст на диске поддерживает только это: упакованные байты — не открытое дерево каталогов. Немедленное уничтожение поддерживает только это: вендор заявляет, что после генерации Wiki не держит этот объект долго. Поиск по открытому дереву, в котором нет /api/v1/snapshot/upload-credential, поддерживает только это: в дереве, которое публично сейчас, этой цепочки нет. Бакет, который оценили как пустой, поддерживает только это: в момент оценки тот бакет был пуст.

Ни одна из этих фраз не закрывает обратную сторону. Шифротекст не поддерживает «вы восстановите рабочую область». Немедленное уничтожение не поддерживает «до удаления закрытого ключа ни у кого не было» и не поддерживает «объём сбора совпал с галочкой, которую вы поставили». Открытое дерево, сплющенное в два коммита, нельзя использовать, чтобы сравнить, как был написан старый sidecar. Бакет, который очистили задним числом, не перематывается к вопросу, кто расшифровал или скопировал объекты, уже принятые до 18 сентября. ferstar отмечал напряжение по времени: если откат контрольной точки правда требует полной загрузки в облако, это спорит с «уничтожить сразу после генерации». Реализация контрольной точки в открытом дереве — локальный Git diff. Метаданные лежат в JSON под ~/.zcode/checkpoints/. От той цепочки загрузки она не зависит.

Что вы видите Что это может поддержать Чего это не поддерживает
На диске .enc, в подписи AES-256 Упакованные байты — не открытая рабочая область Расшифровать можете только вы, облако содержимое не читает
Открытый RSA-ключ выдают при запросе учётных данных Закрытый ключ, который вскрывает конверт, не на этом компьютере Это резервная копия, чтобы восстановиться на другом устройстве
Выключили «улучшить опыт» и «индекс репозитория» Согласие на обучение или облачный индекс могли остановиться Упаковка и прямая загрузка остановились вместе с ними
Вендор пишет: после генерации Wiki данные сразу уничтожают Вендор заявляет, что не хранит этот объект долго Первый пакет совпал с переключателем, который вы нажали
Оценка говорит: в бакете ноль данных В момент оценки тот бакет был пуст Объекты, принятые раньше, никто не расшифровывал и не копировал
Файл на 313 МБ падал 564 раза Этот снимок коммерческого проекта не ушёл Ни одна рабочая область не покидала машину ни одного пользователя

Что можно сверить на этой машине

Лозунг — не доказательство. Ниже только три слоя, которые вы контролируете: есть ли на машине уже готовый к отправке артефакт, унёс ли запрос открытый текст рабочей области и открываете ли вы этот шифротекст сами. Не заливайте в боевой репозиторий ещё одну «тестовую загрузку».

  1. Сначала смотрите локальный каталог данных, а не рекламную страницу. В папке контрольных точек или кэша клиента для программирования с ИИ файл .enc на сотни мегабайт рядом с файлом состояния, где записаны workspacePath, encryptedSizeBytes и failureCount, значит: упаковка уже была. Путь, который совпадает с проектом, который вы пишете, жёстче фразы «мы отправляем только контекст разговора».
  2. Откройте инструменты разработчика или системный наблюдатель сети и включите Preserve log. Смотрите только строку запроса и имя хоста: есть ли вызов, который просит учётные данные на загрузку, и есть ли форма POST прямо в объектное хранилище. Вы сверяете, ушёл ли шифротекст с этой машины, а не отправляете репозиторий ещё раз. Если в теле есть исходник, фраза или .pem открытым текстом, этот слой уже не прошёл.
  3. Задайте один вопрос, который можно закончить: открываю ли я этот локальный шифротекст своей фразой или закрытым ключом на этой машине? Если нет, и вендор тоже говорит, что клиент не открывает, ключ не у вас. Назвать файл резервной копией для себя можно только тогда, когда вы его открываете.
  4. Выключите каждый переключатель, в имени которого звучат конфиденциальность, индекс или улучшение. Подождите один цикл сессии. Потом смотрите снова: появился ли в каталоге контрольных точек новый пакет и растёт ли счётчик ошибок. Подпись на переключателе не доказывает общий рубильник. Новый файл доказывает.
  5. Когда нужен файл, который вы сами ещё открываете, смените канал на тот, где граница вычислений написана. Откройте шифрование файлов, возьмите одноразовую канарейку и назовите её canary-fp-20260922-vendor-key.txt. Фразу оставьте на этом компьютере. Откройте Network, включите Preserve log и зашифруйте. В строке запроса и в теле не должно быть содержимого файла, фразы и полного имени файла как рабочего поля. На выходе .lock или .enc. Один файл — не больше 5 ГБ. Расшифруйте на этой машине той же фразой. Канарейка должна вернуться. Вы открываете файл, потому что фраза у вас, а не потому что в имени алгоритма есть AES.

Пятый шаг не просит шифрование файлов заменить клиент для программирования. Он даёт контраст. Та же фраза «зашифровали на этой машине» может значить, что вывод ключа и AES-256-GCM остаются в текущей вкладке, а файл и фраза не уходят как рабочие данные. Шифротекст вы уносите и открываете. Прошлая заметка закрывала другой слой: HTTPS защищает только прыжок до роутера. Здесь добавочный слой — кто вскрывает конверт после того, как шифротекст ушёл.

Полную фразу и шифротекст не отправляйте в одном чате. .lock из шифрования файлов можно скопировать на диск. Фраза должна идти каналом, который вы уже проверили, либо короткая фраза может стоять после # в самоуничтожающейся ссылке. Если ключ и замок лежат в одном сообщении, конверта для того, кто это сообщение видит, уже нет.

Три способа прочитать «локальное шифрование» дальше, чем оно тянет

Первый — читать «AES вызвали на этой машине» как «расшифровать могу только я». Локальный вызов значит только то, что открытый текст в момент упаковки ещё был на этом компьютере. Когда открытый ключ приходит с сервера, а закрытый на машину не садится, право расшифровки в облаке. Список алгоритмов, длина ключа и CTR против GCM не отвечают, в чьём процессе лежит закрытый ключ.

Второй — читать «загрузили прямо в объектное хранилище, мимо прикладного сервера» как «вендор не видит». Файл может обойти прикладной сервер. Колбэк регистрации и закрытый ключ всё равно на стороне вендора. Обход машинного зала приложения уменьшает открытую копию в журналах приложения. Право расшифровки он не переносит. Заметка про роутер показала: HTTPS не останавливает прокси прикладного уровня. Здесь не останавливается тот конец, у которого закрытый ключ.

Третий — читать «сразу уничтожили / открыли исходники / бакет пуст» как «никогда не собирали». Уничтожение снижает срок хранения. Открытый код даёт сверить дерево, которое публично сейчас. Пустой бакет значит, что в момент оценки объекта не было. Ни одно из этого само по себе не значит, что исторические объекты никто не открывал или что переключатели того дня покрывали полную историю Git. В заметку для передачи стоит писать, генерирует ли эта машина ещё пакет к отправке и открываете ли вы шифротекст, который вот-вот уйдёт. Заголовок «уже исправили» такой заметкой не является.

Частые вопросы

Если на диске уже шифротекст, это и есть локальное нулевое знание?

Нет. Шифротекст значит только то, что упакованные байты — не открытая рабочая область. Если открытый RSA-ключ, которым заворачивают ключ содержимого, сервер выдаёт на месте, а парный закрытый ключ на машину не попадает, ни вы, ни клиент этот файл не откроете. Конверт рассчитан на чтение в облаке, а не на вашу собственную резервную копию.

Вендор пишет, что после загрузки данные сразу уничтожают. Что ещё можно сверить?

«Сразу уничтожаем» снижает срок хранения. Эта фраза не отвечает, вышел ли первый пакет за переключатель, который вы нажали, и кто держал закрытый ключ до удаления. Пустой бакет после проверки не показывает, кто расшифровал или скопировал объекты, уже принятые до 18 сентября.

Если выключить «улучшить опыт» и «индекс репозитория», загрузка тоже остановится?

В разобранном клиенте эти два переключателя отвечали за обучение модели и за то, строит ли облако индекс. Ни один не обрывал упаковку и прямую загрузку. Ищите отдельный выключатель, который останавливает создание снимка, и смотрите, появляется ли на диске новый шифротекст после того, как остальные выключены.

Как передать коллеге файл, который я сам ещё могу открыть?

Сначала зашифруйте в текущей вкладке алгоритмом AES-256-GCM и назовите фразу только тому получателю, которого уже проверили. Откройте шифрование файлов: один файл не больше 5 ГБ, на выходе .lock / .enc, файл и фраза по умолчанию не загружаются. Открыли — и можно пользоваться, аккаунт не нужен. Короткий секрет отдайте через самоуничтожающуюся ссылку, ключ поставьте после #. Форма ссылки — s.html?id={id}#{key}. Если в тикете или журнале ещё лежат телефон и номер документа, сначала прогоните маскирование по правилам в очистке конфиденциальных данных. Исходный текст не уходит как рабочие данные.

Когда открыть должны вы сами, берите канал, который уже готов

Если нужна страница, где граница вычислений написана открыто, и вы хотите прогнать «шифротекст я открываю, фраза в Network не входит», откройте шифрование файлов FastPwd. Регистрация не нужна. Возьмите канарейку выше и прогоните AES-256-GCM в текущей вкладке, затем сверьте по разделу выше: в запросе не должно быть содержимого файла и фразы, а та же фраза должна восстановить файл на этой машине. .lock или .enc можно скопировать на диск. Фразу не пишите в тот же чат и не вставляйте в поле ИИ.

Если фрагмент репозитория всё же надо отдать облачной модели, считайте, что принимающая сторона видит весь текст, который вы вставили. Роутер оставляет открытый пакет вызова там, где кончается HTTPS. Прошлая заметка это уже разобрала. Здесь добавочный вопрос: если клиент сначала «шифрует», а потом загружает, закрытый ключ, который вскрывает конверт, у вас? Если не проходят оба слоя, не кладите живой облачный ключ, закрытый SSH-ключ или данные заказчика в рабочую область и не отдавайте её инструменту, который пакует. Маскирование по правилам закрывает типовые поля. Целый ключ должен идти самоуничтожающейся ссылкой или не уходить совсем.

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

Что ещё почитать

Пароль на архиве перед загрузкой в облако не прячет имена файлов и не является локальным AES-GCM; см. Что закрывает пароль архива перед загрузкой в облако и почему это не локальный AES-GCM. HTTPS шифрует только прыжок до роутера и не останавливает SSH-ключ внутри промпта; см. Почему в дампе LLM-роутера на 6 ТБ появляются SSH-ключи и какой слой HTTPS не закрывает. Как самой странице «локальное шифрование» сверить Network, см. Как проверить, что локальное шифрование в браузере не отправило открытый текст.