Подробные статьи о технологиях, определяющих будущее.

Ваш API-клиент — это хранилище ключей: проведите аудит

Безопасность API-клиента важнее, чем кажется. Как проверить настольные dev-инструменты на тихую установку плагинов, телеметрию и утечки данных.

Сейф на клавиатуре ноутбука, от которого тянутся светящиеся кабели к соседним устройствам.
Ваш API-клиент хранит ключи, а некоторые инструменты лезут далеко за пределы своих границ.

Разработчик открывает HTTP-клиент на своём Mac. И больше ничего. Ни кликов, ни диалогов согласия, ни галочки «включить AI-функции». На следующий день его кодинг-агент не может авторизоваться на удалённом MCP-сервере, который он никогда не настраивал, направляет работу с API через скиллы, которые он никогда не устанавливал, и тащит с собой криптографически доверенный стартовый хук, который он никогда не одобрял. Это не гипотеза. Так выглядит то, что показывают доказательства в недавнем, очень подробно задокументированном баг-репорте: настольное приложение Postman автоматически ставит плагины в Codex и Claude Code, пишет в глобальные конфиги агентов и пытается пометить собственный session-хук как доверенный. Если вас волнует безопасность API-клиентов, этот инцидент должен изменить ваш подход к каждому настольному dev-инструменту на машине.

Что на самом деле сделало настольное приложение Postman

Отбросим возмущение и посмотрим на криминалистику, потому что репортёр проделал работу, которую большинство из нас не делает. В собственном лог-файле Postman зафиксировано событие auto-existing-upgrade: на уже установленном приложении, где пользователь залогинен, скрипт запустился и отчитался claude-code:installed,codex:installed. Без запроса. В глобальной конфигурации Codex у пользователя появился новый marketplace, указывающий на git-репозиторий Postman, включённый плагин и запись о доверии к хуку. В настройках Claude Code появился включённый плагин и записи об установке с временными метками из того же окна. В ~/.local/bin появился бинарник Postman CLI. А удалённое MCP-подключение было направлено на серверы Postman, которое затем не смогло авторизоваться и завалило ошибками. Именно поэтому пользователь вообще всё заметил.

Два момента стоит перечитать дважды. Во-первых, установленный хук запуска сессии инструктирует агента: перед ответом на любую нетривиальную задачу по API-разработке (проектирование, тестирование, моки, документация, деплой) нужно загрузить скилл Postman. Это не интеграция по запросу, а одно приложение переписывает поведение по умолчанию в другом, чужом приложении. Во-вторых, исходный код установщика явно получает хеш хука и записывает его в состояние доверенных хуков агента. Механизм доверия существует затем, чтобы пользователь одобрял хуки. Когда установщик одобряет собственный хук, это программный эквивалент подписи собственного разрешения.

Репортёр был осторожен: он прямо отмечает, что одна только запись о доверии не доказывает, кто её создал, и не делает заявлений об экфильтрации. Эта сдержанность делает отчёт убедительнее, а не слабее. Доказано достаточно: тихое изменение посторонних инструментов, широкая поведенческая инструкция, внедрённая в старт сессии агента, и попытка обойти механизм пользовательского согласия. На любом security-ревью, которое я проводил, такая комбинация означает, что продукт снимают с парка машин до расследования.

Почему ваш API-клиент — это хранилище учётных данных

Вот часть, которую команды стабильно недооценивают. API-клиент — это не текстовый редактор с кнопкой отправки. Здесь живут ваши bearer-токены, сессионные куки, mTLS-сертификаты, секреты OAuth-клиентов и подписанные заголовки запросов. Сюда вставляют переменные окружения с URL баз данных и ключами сторонних сервисов. Если вы используете шаблоны вида {{api_secret}}, подставленное значение проходит через приложение при каждом запросе, и в зависимости от телеметрии вендора потенциально оно попадает и в их систему логирования. Один практик, расследовавший вопросы соответствия HIPAA, описал именно это: в исходящем логировании найдены подставленные значения секретов, а приложение деградировало, когда этот эндпоинт заблокировали. Я не могу независимо проверить каждую деталь, но это совпадает с архитектурным паттерном, который я видел в других «полезных» настольных инструментах: полное логирование запросов поставляется как функция.

Теперь добавим угол агентов. Когда инструмент ставит плагин в ваш кодинг-агент и регистрирует session-хук, его инструкции попадают в контекст процесса, который может читать вашу кодовую базу, выполнять shell-команды и хранить собственный набор учётных данных. Радиус поражения уже не «мои коллекции API утекут», а «каждый секрет, доступный из окружения агента, находится в одном неудачном промпте или одном скомпрометированном скилле от неправильного эндпоинта». Ранее мы писали о том, как CLI-инструменты, устанавливающие фоновые демоны, незаметно расширяют свою поверхность атаки; это тот же паттерн, только с более умной нагрузкой. Демон, который виден в ps, почти вежлив по сравнению с инструкцией-хуком, живущей в хранилище доверия чужого вендора.

Если честно оценить модель угроз, вывод неудобный: настольный API-клиент находится на пересечении секретов, сетевого доступа и всё чаще контрольной плоскости агентов. Он заслуживает такой же проверки, как менеджер паролей или CI-раннер. Почти никто его так не проверяет. Именно этот пробел эксплуатирует инцидент, и поэтому ответ должен быть процедурным, а не эмоциональным.

Почему опт-ауты вендора и переключатели в настройках не работают

Первый порыв после такого инцидента — порыться в настройках приложения в поисках переключателя телеметрии, выключить его и двигаться дальше. Я видел, как целые команды так делали и называли это исправлением. Это театр, и на то есть три причины.

  • Согласие может зависеть от версии. Установка Postman была запущена флагом фичи на уже существующем аккаунте, где пользователь был залогинен. Переключатель, который есть сегодня, не говорит, какие флаги выкатят завтра, а автообновление означает, что завтра наступит без вашего разрешения.
  • Переключатели регулируют то, что задокументировано, а не то, что возможно. Настройка приватности управляет путями в коде, которые вендор решил открыть. Установщик плагинов не был документированной опцией, это был скриптованный путь обновления. Нельзя отключить переключатель, которого не видишь.
  • Решения о доверии принимаются вне приложения. Попытка одобрить хук произошла внутри конфигурации Codex, а не Postman. Даже идеально себя ведущая панель настроек исходного приложения не показала бы этого.

Более глубокий провал структурный: опт-ауты перекладывают бремя бдительности на сторону с наименьшим объёмом информации. Вендор знает, что умеет обновлятель; вы не знаете. Вендор знает, на какие эндпоинты приложение стучится домой; вы гадаете. Любой контроль, который требует от менее информированной стороны постоянно обгонять более информированную, рано или поздно провалится. Именно поэтому проблемы доверия в маркетплейсах плагинов IDE продолжают кусать людей: граница безопасности, которой вы, как вам кажется, управляете, — не та, которую пересекают.

Доверие к вендору не бесполезно, но оно не может быть контролем. Это фактор при выборе, что ставить, а не механизм, который удерживает установленное ПО в честности. Когда вы это усвоите, стратегия аудита напишется сама: проверять поведение снаружи, постоянно, инструментами, которые вендор не контролирует.

Почему одноразовые аудиты безопасности тоже не работают

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

Я сам попадался на эту же дыру. Несколько лет назад я одобрил клиент синхронизации после тщательного ревью: чистый захват трафика, разумные права, никаких механизмов персистентности. Через полгода обновление добавило LaunchAgent и слушающий сокет. Мы заметили это только потому, что на ноутбуке с нестабильным VPN в логах файрвола постоянно появлялись странные повторные подключения. Никто ничего не пересматривал, потому что ни один процесс этого не требовал. Одобрение было снимком, а софт — фильмом.

Итак, оба дешёвых решения не работают: доверие к настройкам вендора не срабатывает, потому что интересное поведение не живёт в настройках, а одноразовые аудиты не срабатывают, потому что интересное поведение выходит после аудита. Работает другой подход: считать состояние собственной машины источником истины и отслеживать его изменения. Это менее гламурно, чем закупочное ревью, но ловит реальность, а не намерения.

Лупа над печатной платой, на которой одна дорожка пробивает границу.
Аудит «на один раз» видит плату один раз; поведение меняется каждый раз, когда запускается обновление.

Как по-настоящему проверить настольные инструменты разработчика

Рабочий подход опирается на три опоры: снимать состояние, которое важно, следить за трафиком и изолировать то, что нельзя полностью проверить. Ничего из этого не требует корпоративных инструментов. Нужны дисциплина и часа примерно на настройку.

Как находить тихие установки плагинов с помощью снимков конфигов

У каждого кодинг-агента и dev-инструмента на вашей машине есть небольшой набор файлов, которые определяют его поведение: ~/.codex/config.toml, ~/.claude/settings.json и каталог плагинов, конфиги MCP, rc-файлы shell, ~/Library/LaunchAgents, ~/.local/bin. Эти файлы и есть граница согласия. Всё, что меняет их без вашего ведома, — именно то, что вы хотите поймать. Поэтому хешируйте их ежедневно и сравнивайте:

#!/usr/bin/env bash
# snapshot-agent-configs.sh — hash every file your agents and shells read,
# then diff against yesterday. Run from cron or launchd.
set -euo pipefail
SNAP_DIR="$HOME/.config-audit"
mkdir -p "$SNAP_DIR"
TODAY="$SNAP_DIR/$(date +%F).txt"
find \
"$HOME/.codex" \
"$HOME/.claude" \
"$HOME/.config" \
"$HOME/.local/bin" \
"$HOME/Library/LaunchAgents" \
-type f 2>/dev/null \
| sort \
| xargs shasum -a 256 > "$TODAY"
PREV=$(ls -t "$SNAP_DIR"/*.txt 2>/dev/null | sed -n '2p' || true)
if [ -n "${PREV:-}" ]; then
if ! diff -u "$PREV" "$TODAY" > "$SNAP_DIR/latest.diff"; then
echo "config drift detected — see $SNAP_DIR/latest.diff" \
| mail -s "agent config drift" you@example.com || \
cat "$SNAP_DIR/latest.diff"
fi
fi

Это примитивно, и это нормально. Если бы это работало на машине репортёра, изменение config.toml в Codex, новые записи о плагинах Claude и бинарник CLI в ~/.local/bin высветились бы в одном диффе на следующее утро. Соотношение сигнала к шуму отличное, потому что эти каталоги в остальное время тихие: ваши собственные правки — единственные легитимные изменения, и вы знаете, когда их вносили. Добавьте к этому вывод launchctl list | grep -v com.apple в тот же снимок, и вы поймаете механизмы персистентности в день их появления.

Следите за исходящим трафиком, а не только за файлами

Целостность файлов говорит, что изменилось на диске, но не скажет, что покинуло машину. Для исходящего трафика нужна видимость по приложениям. В macOS Little Snitch или открытый файрвол LuLu оба будут предупреждать о новых исходящих соединениях по процессам: в первый раз, когда апдейтер Postman или свежий бинарник CLI потянется к незнакомому хосту, вы получите запрос, а не свершившийся факт. В Linux то же делает opensnitch. Если нужна ручная проверка того, что болтливое приложение делает прямо сейчас:

# Every established outbound connection, grouped by process
sudo lsof -iTCP -sTCP:ESTABLISHED -P -n | awk '{print $1, $9}' | sort | uniq -c | sort -rn
# Watch one vendor's traffic live (find the process name first)
sudo tcpdump -i any -n host mcp.postman.com

Смотрите на две вещи: на адреса, не связанные с заявленной функцией инструмента, и на соединения, которые держатся, когда приложение простаивает. HTTP-клиент должен молчать, когда вы не нажимаете «отправить». Сами по себе телеметрические эндпоинты не являются приговором, но, как показывает история с расследованием HIPAA, важна полезная нагрузка. Если клиент подставляет {{secrets}} на стороне клиента и на сервер отправляет полные детали запроса, «анонимные данные об использовании» не анонимны. Узнать это можно только захватом и чтением, желательно во время сессии, в которой вы намеренно загрузили в переменную окружения канареечный токен, то есть уникальный поддельный учётный данные, и посмотрели, не уходит ли он куда-то, куда не должен. Канареечные токены превращают «мы думаем, что они могли» в «мы знаем, что они сделали».

Изолируйте то, чему не можете полностью доверять

Последняя опора принимает, что поймать всё не получится. Поэтому ограничьте радиус поражения. Запускайте инструменты, которые работают с учётными данными, в отдельном пользователе ОС или лёгкой VM, чтобы их доступ к файловой системе заканчивался на границе песочницы. В macOS и Linux второй пользователь стоит недорого, а такие инструменты, как firejail в Linux, могут запрещать целые деревья каталогов для каждого приложения. Держите реальные production-секреты вне настольных инструментов полностью: используйте короткоживущие токены, ограниченные сервисные аккаунты и подпись запросов с истечением срока. Если инструменту для работы нужен долгоживущий production-ключ, сама эта потребность уже находка. Мы уже писали о том, что изоляция важнее мониторинга, когда цена промаха высока: для агентов и для инструментов, которые их настраивают, изоляция — тот слой, который продолжает работать в день, когда в мониторинге обнаружилась слепая зона.

Плейбук отката после инцидентов с инструментами

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

  1. Сначала сохраните доказательства. Скопируйте логи, конфиги и номера версий в безопасное место до удаления. Собственный main.log Postman стал здесь дымящимся пистолетом, а скрипты удаления любят его стирать.
  2. Удалите приложение и его помощников. Бандл приложения плюс всё, что оно положило в ~/.local/bin, Application Support и кеши.
  3. Очистите конфиги агентов. Удалите записи marketplace, блоки включённых плагинов, определения MCP-серверов и закешированные каталоги плагинов на каждом хосте агента, а не только на очевидном.
  4. Отзовите записи о доверии. Удалите все trusted_hash для хуков, которые вы не одобряли. Затем проверьте остальные хуки в том же файле: если один провезли контрабандой, проверьте и остальные.
  5. Проверьте персистентность. LaunchAgents, LaunchDaemons, элементы входа, записи cron, дополнения в rc-файлах shell.
  6. Перевыпустите всё, что через него проходило. Любой учётный данные, которые жили в окружениях или коллекциях инструмента, считайте скомпрометированными. Ротация раздражает, но реагирование на инцидент хуже.
  7. Убедитесь, что удаление прочное. Держите скрипт снимков запущенным несколько недель. Переустановка с другим флагом — известный паттерн.

В этом списке нет одного пункта: завести тикет и ждать. Сделать это тоже стоит, публичные и хорошо задокументированные отчёты — способ, которым остальные узнают о проблеме, но ваша гигиена не может зависеть от дорожной карты вендора.

Силуэт человека, отключающего и сматывающего кабели с серверного оборудования.
Хороший инцидент-респонс методичен: сохранить, удалить, очистить, перевыпустить, проверить.

Главный урок о безопасности инструментов разработчика

Соблазн свести эту историю только к траектории одной компании велик: любимый лёгкий инструмент поднял сотни миллионов долларов, нанял целую армию и теперь должен оправдать многомиллиардную оценку логинами, подписками и AI во всём. Нарратив удовлетворительный и в основном верный, но он слишком легко отпускает всех остальных. Та же структура стимулов сегодня лежит под половиной инструментов на вашей машине. Каждый вендор, у которого есть AI-история, хочет свой плагин в вашем агенте, свой MCP-сервер в вашем конфиге и свой хук в старте вашей сессии. Некоторые будут спрашивать. Доказательства говорят, что как минимум один решил, что спрашивать необязательно.

Реакция рынка уже видна и поучительна: офлайн-first, git-ориентированные API-клиенты вроде Bruno, Kreya и Yaak переживают момент именно потому, что их модель доверия читаема. Файлы в репозитории, запросы с вашей машины, аккаунт не нужен. Когда формат хранения инструмента — папка текстовых файлов, его аудит — это git diff. Это не ностальгия, а архитектура безопасности. Инцидент с supply chain в LiteLLM преподал тот же урок со стороны реестров пакетов: артефакты, которые можно проверить и зафиксировать, — те, которые можно защитить.

Согласие, которое живёт во флаге фичи, — не согласие. Если инструмент может менять своё поведение, не меняя номер версии, ваше одобрение инструмента ничего не значит.

Поэтому вот позиция, которую я готов защищать: перестаньте оценивать настольные dev-инструменты по фичам и начните оценивать их по обратимости. Могу ли я увидеть всё, что инструмент пишет? Могу ли я сравнить его конфиг через diff? Могу ли я запустить его без аккаунта, офлайн, за файрволом, который ведёт журнал? Могу ли я удалить его полностью, включая всё, что он трогал за пределами своего каталога? Инструменты, которые проходят эти вопросы, обычно скучные, а скучность — именно то, что вы хотите видеть между своими учётными данными и сетью. Те, что не проходят, как бы хорош ни был автокомплит, должны жить в песочнице или вообще вне машины. Ваш API-клиент — это хранилище ключей. Начните относиться к нему именно так, потому что вендоры, судя по всему, уже относятся: просто не так, как вам бы хотелось.