← Все статьи

Безопасность скилов и анти-паттерны

Безопасность скилов и анти-паттерны

Скил - это удобно ровно до того момента, пока он не получает доступ к данным и командам. А он получает: ходит в сеть, читает файлы, дёргает API, иногда исполняет команды. И вот тут один невнимательный скил превращается в открытую дверь. Ты хотел автоматизировать рутину, а заодно положил ключ под коврик и оставил его всем желающим.

Беда в том, что дыры в скилах выглядят безобидно. Ключ, вписанный прямо в текст скила, - “ну я же только для себя”. Запрет “опасных” команд по списку - “вроде всё перекрыл”. Права пошире - “на всякий случай, чтоб не переделывать”. Каждое решение по отдельности кажется разумным. А вместе это решето, через которое утекают секреты и проходят чужие команды.

И есть вторая беда, тише первой: скил-графоман. Он делает слишком много. Удаляет, публикует, шлёт наружу - там, где его об этом не просили. Чем больше скил умеет, тем больше у него способов навредить. Поэтому разговор про безопасность скилов - это не только “как закрыть дыры”, но и “что скилу вообще не положено трогать”.

В чём идея

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

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

Правило второе, и оно ломает интуицию, - allowlist вместо denylist. Denylist это “запрещаю вот эти плохие штуки”. Звучит надёжно, а на деле это решето: ты перечисляешь то, что вспомнил, а злоумышленник находит то, что ты забыл. Allowlist наоборот: “разрешено только вот это, короткий список, остальное - нет”. Белый список почти всегда короче чёрного и не оставляет щелей.

Правило третье - секрет-гигиена. Ключи и пароли живут в окружении (env) или в менеджере секретов, а не в тексте скила, не в команде и не в логах. Секрет, переданный через аргумент команды, виден в истории и логах - это тот же самый секрет в коде, только сбоку. Правило простое: в файле скила не должно быть ни одного ключа.

Правило четвёртое - минимум прав. Скил просит ровно столько доступа, сколько нужно для задачи. Не “доступ ко всем папкам и сети на всякий случай”, а строго необходимое. Чем уже права, тем меньше радиус поражения, если что-то пойдёт не так.

И главное, ради чего весь урок: лучшая фича скила - то, что он сознательно НЕ делает. У хорошего скила есть явная граница: он не удаляет, не публикует, не отправляет данные наружу, если это не его задача. Эта граница - не недоработка, а защита. Чем уже то, что скил умеет, тем меньше у него способов навредить. А иногда самый безопасный скил - тот, которого нет: если задачу спокойно решает обычная просьба к ассистенту, отдельный скил с доступами не нужен.

Почему это работает? Потому что безопасность - это не про длинный список запретов, а про сужение возможностей. Меньше прав, меньше секретов в коде, короче белый список, уже граница - меньше поверхности для атаки. А проверять всё это можно механически, по пунктам, что и делает скил-аудитор.

Как себе сделать

Не проверяй скилы руками по памяти - отдай это своему ассистенту. Claude Code, GitHub Copilot, Cursor, Gemini - любой. Пусть он сам пройдёт по чек-листу и выдаст вердикт. Просто скопируй промпт:

Создай мне скил-аудитор, который проверяет другой скил на безопасность.
Срабатывай на просьбы вроде "проверь скил на безопасность", "сделай аудит скила", "что не так с этим скилом".
Аудитор читает проверяемый скил (его описание и вспомогательные файлы) и проходит по чек-листу, для каждого пункта помечает ok или risk с короткой причиной:
1) инъекции - чужой текст из запроса или из внешнего ответа не должен попадать в команду или адрес как есть;
2) allowlist вместо denylist - перечислено, что разрешено, а не попытка запретить всё плохое;
3) секрет-гигиена - ключи берутся из окружения, а не лежат в тексте скила, в команде или в логах;
4) минимум прав - запрошено ровно столько доступа, сколько нужно, без широких прав на всякий случай;
5) чистое окружение - скил не тащит за собой лишние переменные окружения и не светит их в выводе или логах;
6) что скил сознательно НЕ делает - есть ли у него явная граница (не удаляет, не публикует, не шлёт наружу).
В конце дай вердикт: pass, warn или fail. Ставь fail, если есть секрет в коде, инъекция или denylist вместо allowlist.
Аудитор только читает и пишет отчёт - он не исполняет проверяемый скил и не меняет файлы.

Как понять, что заработало: подсунь аудитору заведомо дырявый скил - с ключом прямо в тексте и с запретом по списку. Если он сам, без подсказок, пометит секрет и denylist как risk и выдаст вердикт fail с парой правок - аудитор живой. Дальше прогоняй через него любые свои скилы перед тем, как давать им доступы.

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

Смотреть полностью

Коротко