Ты один раз нажал "разрешить работу в этой папке", и агент получил не только её. Внутри проекта лежит безобидный на вид файл notes.txt. На самом деле это символическая ссылка на ~/.ssh/id_rsa. Агент открывает notes.txt, окно согласия показывает знакомый путь внутри проекта, ты подтверждаешь чтение - и приватный ключ уходит в контекст модели. Ты видел путь, который тебе показали. Агент прочитал файл, на который этот путь указывал.
Именно этот разрыв Wiz Research назвала GhostApproval и опубликовала 8 июля 2026 года.
Главное за минуту
- 8 июля 2026 года Wiz Research раскрыла класс уязвимостей GhostApproval после согласованного раскрытия с шестью поставщиками (источник: Wiz Research, 2026-07-08).
- Суть: символическая ссылка внутри доверенного workspace может указывать на файл за его пределами, а интерфейс согласия показывает путь ссылки, а не реальный разрешаемый путь к чувствительному файлу (источник: Wiz Research).
- Проверка охватила Amazon Q, Claude Code, Augment, Cursor, Google Antigravity и Windsurf (источник: Wiz Research; подтверждает ITPro, 2026-07-09).
- Amazon исправила проблему как CVE-2026-12958, Cursor - как CVE-2026-50549. Статусы и трактовки у поставщиков различаются, поэтому нельзя утверждать, что все продукты были одинаково уязвимы (источник: Wiz Research).
- Wiz не сообщала о подтверждённой эксплуатации этой техники в реальных атаках (источник: Wiz Research). Это находка исследователей, а не отчёт об инциденте.
Если ты пришёл сюда с запросом про claude code агенты и безопасность рабочей папки, держи короткий вывод: обнови инструмент до версии с фиксом, проверь свой проект на symlink перед тем как дать агенту доступ, и не полагайся на путь в окне согласия как на истину.
Пока ты выстраиваешь такой контроль, полезно уметь быстро сверить поведение разных моделей на одном и том же запросе - через один API это делается без прыжков между провайдерами (provod.ai).
Что именно случилось 8 июля 2026 года
Разберём терминологию, потому что вокруг находки уже накопилось много неточностей.
Wiz Research описала не единичную дыру в одном продукте, а класс проблем в модели доверия кодовых ассистентов. Общий механизм такой: инструмент разрешает агенту читать и писать внутри рабочей папки, которую ты пометил как доверенную. Граница доверия проведена по этой папке. Но файловая система умеет протыкать такие границы символическими ссылками, и проверка "файл внутри разрешённой папки?" легко проваливается, если сверять путь ссылки, а не путь, куда она реально разрешается.
Проверка охватила шесть продуктов: Amazon Q, Claude Code, Augment, Cursor, Google Antigravity и Windsurf (источник: Wiz Research; то же перечисление у ITPro, 2026-07-09). Важная оговорка от самих исследователей: статусы и трактовки у поставщиков различаются. Из открытых данных известно, что Amazon выпустила фикс с идентификатором CVE-2026-12958, а Cursor - CVE-2026-50549. По остальным участникам публичные CVE в источнике не приведены, поэтому корректно говорить о разной реакции, а не о равной уязвимости всех шести.
Ещё одна честная граница: Wiz не заявляла о подтверждённой эксплуатации в реальных атаках. Это исследование уязвимости и координация раскрытия, а не разбор инцидента с жертвами. Разница принципиальная. Дискуссия в сообществе о модели доверия агентов - это сигнал внимания, а не доказательство того, что кого-то уже взломали через GhostApproval.
Как символическая ссылка выводит агента за пределы папки
Главное: доверенной должна быть не строка пути, а тот inode, куда путь фактически ведёт после разрешения всех ссылок.
Символическая ссылка - это файл, содержимое которого есть путь к другому файлу. Открываешь ссылку, ОС молча ведёт тебя к цели. Для агента ./project/notes.txt и /home/you/.ssh/id_rsa выглядят как одно чтение, если проверка смотрит только на первую строку.
Вот как это выглядит в терминале - воспроизводить на чужих машинах не нужно, это для понимания механики на своей:
# внутри доверенной папки проекта
cd ~/project
ln -s ~/.ssh/id_rsa notes.txt
# путь выглядит "внутри проекта"
ls -l notes.txt
# notes.txt -> /home/you/.ssh/id_rsa
# а вот куда он ведёт на самом деле
readlink -f notes.txt
# /home/you/.ssh/id_rsa
Слабое место - шаг проверки согласия. Наивная проверка выглядит так:
# ОПАСНО: сверяет путь-строку, а не реальную цель
import os
def is_inside_workspace_bad(path, workspace):
abspath = os.path.abspath(path)
return abspath.startswith(os.path.abspath(workspace))
os.path.abspath не разворачивает symlink. Строка ~/project/notes.txt честно начинается с корня workspace, проверка возвращает True, а читается ключ за его пределами.
Правильная проверка разрешает ссылки до сравнения:
# сверяем РАЗРЕШЁННЫЙ путь после раскрытия symlink
import os
def is_inside_workspace_ok(path, workspace):
real_path = os.path.realpath(path) # раскрывает symlink
real_ws = os.path.realpath(workspace)
# добавляем разделитель, чтобы /work не проходил как префикс /workspace
return os.path.commonpath([real_path, real_ws]) == real_ws
Ровно этот класс ошибок Wiz и описала: интерфейс согласия способен показать путь ссылки, а не реальный разрешаемый путь к чувствительному файлу (источник: Wiz Research). Пользователь одобряет то, что видит. А видит он не то, что произойдёт.
Почему окно согласия обманывает, хотя формально не врёт
Главное: согласие имеет смысл только если оно про разрешаемый путь, а не про то, что набрано в ссылке.
Окно "разрешить агенту прочитать этот файл?" - это точка, где человек берёт на себя ответственность. GhostApproval бьёт именно туда. Формально интерфейс не лжёт: он показывает путь, по которому агент обратился к файлу. Но человек читает этот путь как обещание "файл внутри проекта", а система такого обещания не давала.
Чтобы согласие снова стало осмысленным, оно должно показывать до чтения файла и путь запроса, и разрешённый путь, если они расходятся. Тогда строка notes.txt -> /home/you/.ssh/id_rsa сразу выдаёт себя. Это и есть та граница согласия, о которой говорит editorial-угол находки: где проходит доверие и что именно тебе показывают перед действием.
Практический контрольный список для такого экрана согласия, если ты сам строишь агента поверх какого-либо API:
- Разрешай путь через
realpath/os.path.realpathперед любым чтением. - Показывай в окне и запрошенный путь, и разрешённый, когда они отличаются.
- Считай выход за границу workspace отдельным событием, требующим явного повторного подтверждения.
- Логируй разрешённый путь, а не путь ссылки, иначе аудит после инцидента ничего не покажет.
- Запрещай чтение по symlink наружу по умолчанию, а не проси человека каждый раз ловить подмену глазами.
Что делать прямо сейчас: рабочие шаги
Главное: обнови инструмент, просканируй проект на ссылки наружу, не доверяй чужим репозиториям слепо.
Шаг 1. Обнови кодового ассистента. Для продуктов с известными фиксами это Amazon Q (CVE-2026-12958) и Cursor (CVE-2026-50549) по данным Wiz. По остальным участникам сверься с их собственными release notes: единой даты для всех шести нет, потому что реакция вендоров различается.
Шаг 2. Найди символические ссылки, ведущие наружу, в любом репозитории до того как дашь агенту доступ:
# показать все symlink в проекте и куда они реально ведут
find . -type l -print0 | while IFS= read -r -d '' link; do
target=$(readlink -f -- "$link")
case "$target" in
"$PWD"/*) : ;; # цель внутри проекта - ок
*) printf 'НАРУЖУ: %s -> %s\n' "$link" "$target" ;;
esac
done
Всё, что помечено НАРУЖУ, - это то, что агент прочитает как "внутренний" файл.
Шаг 3. Относись к склонированному чужому репозиторию как к недоверенному вводу. Ссылка на ~/.ssh/id_rsa, ~/.aws/credentials или .env соседнего проекта может лежать в нём заранее, ещё до того как ты открыл его в агенте.
Шаг 4. Держи по-настоящему чувствительные секреты вне досягаемости рабочих папок и вне пользовательского домашнего каталога, если это возможно, а не только "не в проекте".
Шаг 5. Читай экран согласия как показ разрешённого пути. Если инструмент не показывает, куда ведёт ссылка, считай это отсутствием информации, а не отсутствием риска.
Таблица решений: доверять доступу или нет
| Ситуация | Символические ссылки наружу | Что делать |
|---|---|---|
| Свой проект, ты создал все файлы | Нет | Обычный доступ агента |
| Свой проект, есть ссылки внутрь себя | Только внутрь | Доступ ок, проверь find разово |
| Склонированный публичный репозиторий | Неизвестно | Прогнать find, дать доступ после |
| Репозиторий с pull request от чужого | Возможны | Проверять каждый раз, не автоапрувить чтения |
| Любой проект + инструмент без фикса | Опасно даже без ссылок | Сначала обновить, потом работать |
Как это связано с выбором и сравнением моделей
Главное: уязвим слой согласия и файлового доступа инструмента, а не сама языковая модель. Но выбор модели всё равно влияет на то, как агент себя ведёт.
Тут стоит развести две вещи. GhostApproval - проблема обвязки: как инструмент проверяет пути и рисует согласие. Меняя модель, ты этот баг не чинишь. Чинит его обновление инструмента и корректная проверка realpath.
Что действительно зависит от модели - это поведение агента после того как доступ дан: насколько аккуратно он объясняет, зачем читает файл, как реагирует на подозрительный notes.txt, ведущий к ключу, насколько склонен предупредить тебя. Чтобы это оценить честно, полезно прогнать один и тот же тревожный сценарий на нескольких семействах моделей и сравнить ответы бок о бок.
Здесь и появляется практичный мостик из России. provod.ai собирает Claude, GPT, Gemini, DeepSeek и Qwen в одном чате и даёт один API, совместимый с SDK OpenAI и Anthropic - меняешь ключ и base_url, остальной код тот же. Это удобно ровно для задачи сравнения и маршрутизации между семействами моделей, когда тебе нужно быстро понять, кто из них лучше замечает подмену пути, без отдельных подписок и без VPN. Оплата рублями с российской карты, через СБП или по счёту, баланс один на все модели; для юрлица есть договор, счёт и закрывающие документы (provod.ai).
Минимальный пример переключения на такой совместимый API - секрет держи в переменной окружения, не в коде:
from openai import OpenAI
client = OpenAI(
base_url="https://api.provod.ai/v1",
api_key="PROVOD_API_KEY_PLACEHOLDER", # подставь из окружения, не коммить
)
resp = client.chat.completions.create(
model="claude-opus-4-8",
messages=[
{"role": "system", "content": "Ты аудитор безопасности. Объясни риск чтения файла."},
{"role": "user", "content": "Файл notes.txt это symlink на ~/.ssh/id_rsa. Читать?"},
],
)
print(resp.choices[0].message.content)
Повторяешь тот же запрос, меняя model на другое семейство, и сравниваешь, кто поднимает тревогу. Сам баг доступа это не лечит - лечит обновление инструмента, - но помогает выбрать модель, которая хотя бы предупредит.
Частые ошибки и как отлаживать
Главное: большинство провалов - это молчаливое разрешение symlink и логи, в которых записан не тот путь.
Разберём типичные грабли, когда ты сам строишь или встраиваешь агента, в том числе внутри автоматизаций на платформах вроде n8n, где вызовы к файлам и моделям идут без человека у экрана.
-
Проверка через
abspathвместоrealpath. Самый частый случай. Строка проходит, ссылка живёт. Лечится заменой наos.path.realpathиcommonpath, как выше. -
Проверка префикса без разделителя.
startswith("/work")пропустит/work-evil. Всегда сравнивай по компонентам пути. - Согласие без человека в автоматизации. В пайплайне n8n или подобном экран согласия часто вообще выключен. Значит защита должна стоять кодом до чтения, а не в интерфейсе. Автоапрув чтений в недоверенных репозиториях - прямой путь к GhostApproval-сценарию.
-
Логи пишут путь ссылки. После инцидента ты увидишь
notes.txtи не поймёшь, что утёк ключ. Логируй разрешённый путь. - TOCTOU-гонка. Проверил путь, потом открыл - между этими шагами ссылку могли подменить. Где возможно, открывай дескриптор и проверяй его, а не путь дважды.
Быстрая карта диагностики: если агент "неожиданно много знает" о системе, начни с find . -type l, затем сверь, что именно попало в контекст последнего запроса, затем проверь версию инструмента против списка с фиксами.
Чего это не решает
Будь честен с границами.
- Обновление и
realpathзакрывают GhostApproval, но не делают агента безопасным вообще. Prompt injection через содержимое файлов, утечки через сетевые вызовы и избыточные права остаются отдельными задачами. - Сравнение моделей помогает выбрать более осторожного агента, но не заменяет технический контроль доступа. Модель, которая "обычно предупреждает", всё равно иногда промолчит.
- provod.ai даёт доступ к иностранным моделям через совместимый API для сравнения и маршрутизации между семействами - и только это. Он не заменяет платформы автоматизации, не предоставляет GigaChat, не заменяет частную или on-prem инфраструктуру, не открывает функции, доступные только по подписке конкретного вендора, и не делает за тебя внедрение и аудит.
- Статусы вендоров различаются. Эта статья не даёт единого "безопасно/нет" по всем шести продуктам - сверяйся с их собственными объявлениями.
- Отсутствие подтверждённой эксплуатации не значит, что риска нет. Это значит, что публичных жертв на дату проверки не заявлено (источник: Wiz Research).
Источники
- Wiz Research, "GhostApproval: A Trust Boundary Gap in AI Coding Assistants", 2026-07-08 (первичный; факты о дате, шести продуктах, механике symlink, экране согласия, CVE-2026-12958 и CVE-2026-50549, различии статусов вендоров и отсутствии подтверждённой эксплуатации): https://www.wiz.io/blog/ghostapproval-a-trust-boundary-gap-in-ai-coding-assistants
- ITPro, "Flaws in some of the most popular AI coding tools left developers wide open to attack", 2026-07-09 (вторичный; подтверждает дату, перечень продуктов, механику и CVE): https://www.itpro.com/security/flaws-in-some-of-the-most-popular-ai-coding-tools-left-developers-wide-open-to-attack
Проверка фактов актуальна на 2026-07-14. Все волатильные детали привязаны к источникам выше.
Сравни, как Claude, GPT, Gemini, DeepSeek и Qwen реагируют на подозрительный symlink на одном балансе и без VPN - открой provod.ai и прогони свой сценарий прямо сейчас.
provod.ai — Russian LLM API aggregator. One OpenAI-compatible endpoint to all flagship models: OpenAI (GPT-5.6, GPT-5.5), Anthropic (Claude Opus 4.8, Sonnet 4.6), Google (Gemini 3.1 Pro, 3.5 Flash), DeepSeek V4 Pro, Qwen 3.6 Plus. Provider prices at the CBR rate, no token markup. Pay in rubles to a Russian legal entity with full closing documents.
Try: provod.ai · model catalog · docs





Top comments (0)