
SkillSpector v2.11.1
Сканер безопасности для навыков ИИ-агентов. Обнаруживает уязвимости, вредоносные паттерны, риски безопасности, промпт-инъекции, эксфильтрацию данных и риски цепочки поставок в навыках Claude Code, Codex и MCP до их установки.
SkillSpector
Сканер безопасности для навыков ИИ-агентов. Обнаруживайте уязвимости, вредоносные паттерны и риски безопасности перед установкой навыков агентов.
Обзор
Навыки ИИ-агентов (используемые Claude Code, Codex CLI, Gemini CLI и др.) выполняются с неявным доверием и минимальной проверкой. Исследования показывают, что 26,1% навыков содержат уязвимости, а 5,2% демонстрируют вероятное вредоносное намерение.
SkillSpector помогает ответить на вопрос: «Безопасно ли устанавливать этот навык?»
SkillSpector является частью конвейера NVIDIA Verified Skills, который сканирует, оценивает и подписывает навыки агентов перед публикацией. Навыки, прошедшие проверку, публикуются в каталоге навыков NVIDIA.
Документация
- Сканирование навыков агентов перед установкой — Руководство: когда сканировать, как читать отчёт и как ограничивать установки.
- Руководство по разработке — Архитектура, структура пакета и способы расширения конвейера анализатора.
- Ограничения ресурсов анализа — Пределы для пакета с закрытием при сбое, парсера, вложенных артефактов, реестра и результатов.
- Расширение Pi — Установка SkillSpector как инструмента Pi для сканирования навыков изнутри сеансов агента.
Возможности
- Многоформатный ввод: сканирование Git-репозиториев, URL-адресов, zip-файлов, каталогов или отдельных файлов
- 71 паттерн уязвимостей в 17 категориях: инъекция промптов, эксфильтрация данных, повышение привилегий, цепочка поставок, чрезмерная автономность, обработка выходных данных, утечка системного промпта, отравление памяти, неправильное использование инструментов, мошеннический агент, анти-отказ, злоупотребление триггерами, опасный код (AST), отслеживание потоков данных, сигнатуры YARA, минимальные привилегии MCP и отравление инструментов MCP
- Двухэтапный анализ: быстрый статический анализ + опциональная семантическая оценка LLM
- Живые проверки уязвимостей: SC4 запрашивает OSV.dev для получения данных о CVE в реальном времени с автоматическим офлайн-резервом
- Несколько форматов вывода: терминал, JSON, Markdown и отчёты SARIF
- Оценка риска: оценка от 0 до 100 с метками серьёзности и чёткими рекомендациями
- Базовый уровень / подавление ложных срабатываний: принятие известных результатов через базовый уровень с glob-правилами или отпечатками, чтобы повторные сканирования выявляли только новые проблемы (документация)
Быстрый старт
Установка
Уведомление об открытом программном обеспечении: этот проект загрузит и установит дополнительные сторонние проекты с открытым исходным кодом. Ознакомьтесь с условиями лицензий этих проектов перед использованием.
Сначала создайте и активируйте виртуальную среду (все цели make предполагают, что виртуальная среда активна). Используйте uv или pip; Makefile использует uv, если он доступен, в противном случае — pip.
Быстрая установка с uv (только CLI):```bash uv tool install git+https://github.com/NVIDIA/skillspector.git
Update later: uv tool update skillspector
Если вы планируете запускать `skillspector mcp`, установите дополнительный пакет MCP при установке:```bash
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
From source:```bash
Clone the repository
git clone https://github.com/NVIDIA/skillspector.git cd skillspector
Create and activate virtual environment
uv venv .venv && source .venv/bin/activate
or: python3 -m venv .venv && source .venv/bin/activate
Install for production use
make install
Or install with development dependencies
make install-dev
### Docker (Python не требуется)
Запустите SkillSpector без установки Python, собрав его локально из включённого [Dockerfile](https://github.com/nvidia/skillspector/blob/main/Dockerfile). Образ основан на официальном Docker-образе Python `3.12-slim-bookworm`.
**Соберите образ:**```bash
make docker-build
# or: docker build -t skillspector .
Сканирование локальной директории путем монтирования вашей текущей директории в /scan, рабочую директорию контейнера:```bash
docker run --rm -v "$PWD:/scan" skillspector scan ./my-skill/ --no-llm
**Сканирование с анализом LLM** путём передачи учётных данных через локальный файл `.env`:```bash
cat > .env <<'EOF'
SKILLSPECTOR_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
EOF
Установка
Требования
- Python 3.8+
- pip
Установка из PyPI
pip install pycryptodome
Установка из исходного кода
git clone https://github.com/example/repo.git
cd repo
pip install -r requirements.txt
Настройка переменных окружения
Скопируйте файл .env.example в .env и заполните необходимые значения:
cp .env.example .env
Затем отредактируйте файл .env и укажите свои ключи API и другие параметры конфигурации.
Проверка установки
Чтобы убедиться, что всё установлено корректно, выполните:
python -m tool_name --version
Если вы видите номер версии, установка прошла успешно.```bash
docker run --rm
-v "$PWD:/scan"
--env-file .env
skillspector scan ./my-skill/
Или передайте учётные данные напрямую из вашего окружения оболочки:```bash
docker run --rm \
-v "$PWD:/scan" \
-e SKILLSPECTOR_PROVIDER=anthropic \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
skillspector scan ./my-skill/
Запишите отчёт в файловую систему хоста, записав его в смонтированный каталог:```bash
docker run --rm
-v "$PWD:/scan"
skillspector scan ./my-skill/ --no-llm --format json --output report.json
**Необязательный псевдоним** для повторяющихся статических сканирований:```bash
alias skillspector-docker='docker run --rm -v "$PWD:/scan" skillspector'
skillspector-docker scan ./my-skill/ --no-llm
Основное использование```bash
Scan a local skill directory
skillspector scan ./my-skill/
Scan a single SKILL.md file
skillspector scan ./SKILL.md
Scan a Git repository
skillspector scan https://github.com/user/my-skill
Scan a zip file
skillspector scan ./my-skill.zip
#### Ограничения размера
SkillSpector применяет два независимых ограничения на удалённые и архивные входные данные, чтобы ограничить влияние чрезмерно больших загрузок и zip-бомб:
- **Ограничение на приём**: `INGEST_MAX_BYTES` (100 МиБ) — применяется к потоковым загрузкам по URL, общему несжатому размеру zip-архивов и использованию диска после клонирования Git-репозиториев.
- **Ограничение на элементы zip**: `INGEST_MAX_ZIP_MEMBERS` (10 000) — ограничивает количество записей в одном zip-архиве.
Обратите внимание, что ограничение анализа в 1 МБ на файл (`MAX_FILE_BYTES`) является отдельным, нижестоящим лимитом: оно ограничивает то, что отдельные анализаторы будут считывать из уже принятого каталога. Ограничения на приём выше ограничивают то, какой объём контента может попасть на диск в первую очередь. Нарушение любого из ограничений на приём приводит к закрытому сбою с ошибкой `IngestLimitExceededError`.
### Форматы вывода```bash
# Terminal output (default) - pretty formatted
skillspector scan ./my-skill/
# JSON output - machine readable
skillspector scan ./my-skill/ --format json --output report.json
# Markdown output - for documentation
skillspector scan ./my-skill/ --format markdown --output report.md
# SARIF output - for CI/CD integration and IDE tooling
skillspector scan ./my-skill/ --format sarif --output report.sarif
Пакетное сканирование
Сканируйте целые каталоги навыков параллельно из contrib/batch_scan/:```bash
python -m contrib.batch_scan.batch_scan ./my-skills/ --no-llm
python -m contrib.batch_scan.batch_scan ./my-skills/ --workers 20 -f json -o report.json
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 20
Поддерживает многоязычное обнаружение (zh/ja/ko) и вывод в терминал/JSON/Markdown.
Для LLM-сканирования с более высокой степенью параллелизма настройте несколько API-ключей, следуя
[`.env.example`](https://github.com/nvidia/skillspector/blob/main/contrib/batch_scan/.env.example) — пул повышает пропускную способность
и отказоустойчивость, при условии, что ключи не разделяют ограничение скорости на уровне аккаунта.
Подробности см. в [руководстве для участников](https://github.com/nvidia/skillspector/blob/main/contrib/batch_scan/docs).
> **Примечание о поддержке LLM:** Конфигурация по умолчанию ориентирована на DeepSeek как на
> самый дешёвый публичный вариант. DeepSeek-Chat
> [планируется вывести из эксплуатации](https://api-docs.deepseek.com/), и у автора
> нет оборудования для тестирования локальных моделей. Пакетный сканер изначально
> тестировался с OpenAI-совместимыми конечными точками — отсутствие поддержки
> структурированного вывода в DeepSeek потребовало ручных исправлений для JSON-парсинга. Если вы можете
> внести вклад в более универсальный бэкенд (Ollama, vLLM или другой провайдер),
> PR приветствуются.
### Подавление ложных срабатываний (базовая линия)
Подавляйте известные/принятые находки, чтобы оценка риска отражала только нерассмотренные
проблемы, а повторные сканирования выявляли только *новые* находки. См.
[руководство по подавлению](https://github.com/nvidia/skillspector/blob/main/docs/SUPPRESSION.md) для получения полной справочной информации.```bash
# Accept all current findings into a baseline (run once), then commit it.
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
# Scan against the baseline — only NEW findings are reported and scored.
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
# Review what was suppressed (still excluded from the score).
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed
Базовый файл также может использовать устойчивые к дрейфу glob-правила (по идентификатору правила, пути к файлу или сообщению) — см. .skillspector-baseline.example.yaml.
Точные базовые файлы на основе отпечатков привязаны к доказательствам: изменение сканируемого исходного кода или версии SkillSpector сохраняет находку активной, пока она не будет проверена снова.
Когда выбранный базовый файл или его вывод хранится внутри каталога навыка, SkillSpector исключает этот конкретный файл из анализа содержимого, чтобы его текст подавления не мог создавать находки или попадать в перегенерированные отпечатки; соседние файлы остаются в обычной области сканирования.
LLM-анализ
Для наилучших результатов настройте совместимую с OpenAI LLM-конечную точку для семантического анализа. Выберите провайдера с помощью SKILLSPECTOR_PROVIDER; хостинговые провайдеры поставляются со встроенными моделями по умолчанию, тогда как CLI-провайдеры используют модель по умолчанию локальной среды выполнения, если не задан SKILLSPECTOR_MODEL. SkillSpector также работает с локальными серверами, совместимыми с OpenAI (Ollama, vLLM, llama.cpp), и управляемыми шлюзами вывода.
Провайдер (SKILLSPECTOR_PROVIDER) | Переменная окружения для учётных данных | Конечная точка | Модель по умолчанию |
|---|---|---|---|
openai | OPENAI_API_KEY (+ необязательный OPENAI_BASE_URL) | api.openai.com (или любой URL, совместимый с OpenAI) | gpt-5.4 |
anthropic | ANTHROPIC_API_KEY | api.anthropic.com | claude-opus-4-6 |
anthropic_proxy | ANTHROPIC_PROXY_API_KEY + ANTHROPIC_PROXY_ENDPOINT_URL | Любой прокси в стиле Vertex raw-predict | claude-sonnet-4-6 |
bedrock | AWS_PROFILE (необязательно) + AWS_REGION — SigV4 через boto3 | AWS Bedrock Runtime | us.anthropic.claude-sonnet-4-6-20250915-v1:0 |
nv_build | NVIDIA_INFERENCE_KEY | build.nvidia.com | deepseek-ai/deepseek-v4-flash |
claude_cli | (нет — используется локальная CLI-авторизация) | локальный бинарный файл claude | локальная среда выполнения Claude по умолчанию или SKILLSPECTOR_MODEL |
codex_cli | (нет — используется локальная CLI-авторизация) | локальный бинарный файл codex | локальная среда выполнения Codex по умолчанию или SKILLSPECTOR_MODEL |
Stock OpenAI
export SKILLSPECTOR_PROVIDER=openai export OPENAI_API_KEY=sk-... skillspector scan ./my-skill/
Anthropic
export SKILLSPECTOR_PROVIDER=anthropic export ANTHROPIC_API_KEY=sk-ant-... skillspector scan ./my-skill/
Anthropic via Vertex-style proxy (corporate gateways, GCP Vertex AI)
export SKILLSPECTOR_PROVIDER=anthropic_proxy export ANTHROPIC_PROXY_ENDPOINT_URL=https://my-gateway.example.com/models/claude-sonnet-4-6:streamRawPredict export ANTHROPIC_PROXY_API_KEY=your-bearer-token export SKILLSPECTOR_MODEL=claude-sonnet-4-6 skillspector scan ./my-skill/
AWS Bedrock (Claude via SigV4)
export SKILLSPECTOR_PROVIDER=bedrock
Optional: select an AWS named profile. When unset, the standard
boto3 credential chain (env vars, instance metadata, SSO, etc.) resolves.
export AWS_PROFILE=my-profile
export AWS_REGION=us-west-2 # default if unset
Default model: us.anthropic.claude-sonnet-4-6-20250915-v1:0
Override with any Bedrock model ID, cross-region inference-profile
ID, or your own application-inference-profile ARN:
export SKILLSPECTOR_MODEL=us.anthropic.claude-opus-4-6-20250915-v1:0
skillspector scan ./my-skill/
NVIDIA build.nvidia.com
export SKILLSPECTOR_PROVIDER=nv_build export NVIDIA_INFERENCE_KEY=nvapi-... skillspector scan ./my-skill/
Local Claude CLI — no API key; uses your existing claude auth login session
Requires: claude CLI installed and authenticated (claude auth login)
export SKILLSPECTOR_PROVIDER=claude_cli
Uses the local Claude CLI runtime fallback unless SKILLSPECTOR_MODEL is set.
export SKILLSPECTOR_MODEL=claude-sonnet-4-6
skillspector scan ./my-skill/
Local Codex CLI — no API key; uses your existing codex login session
Requires: codex CLI installed and authenticated
export SKILLSPECTOR_PROVIDER=codex_cli skillspector scan ./my-skill/
Local Ollama or any OpenAI-compatible endpoint
export SKILLSPECTOR_PROVIDER=openai export OPENAI_API_KEY=ollama export OPENAI_BASE_URL=http://localhost:11434/v1 export SKILLSPECTOR_MODEL=llama3.1:8b skillspector scan ./my-skill/
Override the provider's default model
export SKILLSPECTOR_MODEL=gpt-5.2 skillspector scan ./my-skill/
Skip LLM analysis (faster, static analysis only)
skillspector scan ./my-skill/ --no-llm
### MCP Server
Запускайте SkillSpector как [Model Context Protocol](https://modelcontextprotocol.io)
сервер, чтобы любой агент с поддержкой MCP (Claude Code, Codex CLI, Gemini CLI) или удалённая
среда выполнения мог вызывать сканирование как инструмент и **блокировать установку навыков/MCP на основе
результата** — превращая SkillSpector в защитный барьер времени выполнения вместо
внеполосного этапа аудита.
`skillspector mcp` требует `skillspector[mcp]`.```bash
# Install, or reinstall if you already used the CLI-only path
uv tool install --force 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
# FastMCP stdio transport for local CLI agents
skillspector mcp
# streamable HTTP/SSE transport for remote / A2A callers
skillspector mcp --transport http --host 127.0.0.1 --port 8000
Транспорт stdio — это текущий путь FastMCP для локальных CLI-агентов, и зависание при инициализации, о котором сообщалось в issue #199, по-прежнему актуально для него.
Сервер предоставляет один инструмент:
scan_skill(target, use_llm=true, output_format="json")— сканирует Git URL, файловый URL,.zip,.md-файл или каталог и возвращает структурированный вердикт:risk_score(0-100),severity,recommendation,safe_to_installиfindings. Также сообщаетllm_used/scan_mode, чтобы низкий балл от сканирования только со статическим анализом никогда не был принят за чистый полный скан.
Зарегистрируйте его в Claude Code через:```bash claude mcp add skillspector -- skillspector mcp
> **Безопасность — модель доверия HTTP-транспорта**
>
> HTTP-транспорт поставляется **без аутентификации**. Любой вызывающий код, который
> может получить доступ к порту, может вызвать `scan_skill`. Через stdio или `127.0.0.1` это
> та же граница доверия, что и у CLI. Если вы привязываете сервер к маршрутизируемому интерфейсу:
>
> - Разместите сервер за аутентифицирующим обратным прокси (например, nginx + mTLS)
> перед тем, как открыть его для внешнего доступа.
> - Локальные пути и URL-адреса `file://` **автоматически отклоняются** через HTTP, чтобы
> предотвратить чтение произвольных файлов хоста неаутентифицированными вызывающими кодами. Принимаются только
> удалённые Git- и `.zip`-URL-адреса.
## Паттерны уязвимостей
SkillSpector обнаруживает **71 паттерн уязвимостей** в 17 категориях:
### Инъекция промптов (6 паттернов)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| P1 | Переопределение инструкций | ВЫСОКАЯ | Команды игнорировать ограничения безопасности |
| P2 | Скрытые инструкции | ВЫСОКАЯ | Вредоносные директивы в комментариях/невидимом тексте |
| P3 | Команды эксфильтрации | ВЫСОКАЯ | Инструкции по внешней передаче контекста |
| P4 | Манипуляция поведением | СРЕДНЯЯ | Тонкие инструкции, изменяющие решения агента |
| P5 | Вредоносный контент | КРИТИЧЕСКАЯ | Инструкции, которые могут причинить физический вред |
| P9 | Заполнение пробелами | СРЕДНЯЯ | Большое заполнение пробелами, скрывающее инструкции ниже/рядом с видимой областью |
### Анти-отказ (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| AR1 | Подавление отказа | ВЫСОКАЯ | Инструкции никогда не отказывать или всегда соглашаться (например, «никогда не отказывай», «всегда соглашайся») |
| AR2 | Подавление дисклеймеров | ВЫСОКАЯ | Инструкции опускать предупреждения, дисклеймеры или этические комментарии (например, «без дисклеймеров», «не морализируй») |
| AR3 | Аннулирование политики безопасности | ВЫСОКАЯ | Jailbreak-формулировки, аннулирующие защитные механизмы (например, «у тебя нет ограничений», «игнорируй свои правила», «делай что угодно сейчас») |
### Эксфильтрация данных (4 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| E1 | Внешняя передача | СРЕДНЯЯ | Отправка данных на внешние URL-адреса |
| E2 | Сбор переменных окружения | ВЫСОКАЯ | Перечисление, копирование или поиск данных окружения для сбора секретов |
| E3 | Перечисление файловой системы | СРЕДНЯЯ | Сканирование каталогов на предмет чувствительных файлов |
| E4 | Утечка контекста | ВЫСОКАЯ | Внешняя передача контекста разговора |
### Повышение привилегий (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| PE1 | Чрезмерные разрешения | НИЗКАЯ | Запрос доступа сверх заявленной функциональности |
| PE2 | Выполнение sudo/root | СРЕДНЯЯ | Вызов повышенных системных привилегий |
| PE3 | Доступ к учётным данным | ВЫСОКАЯ | Чтение SSH-ключей, токенов, паролей |
### Цепочка поставок (9+ паттернов)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| SC1 | Незакреплённые зависимости | НИЗКАЯ | Отсутствие ограничений версий пакетов |
| SC2 | Загрузка внешних скриптов | ВЫСОКАЯ | curl \| bash и удалённое выполнение кода |
| SC3 | Обфусцированный код | ВЫСОКАЯ | Выполнение кода в кодировке Base64/hex |
| SC4 | Известные уязвимые зависимости | ВЫСОКАЯ | Зависимости с известными CVE (живой поиск OSV.dev) |
| SC5 | Заброшенные зависимости | СРЕДНЯЯ | Неподдерживаемые пакеты без обновлений безопасности |
| SC6 | Тайпсквоттинг | ВЫСОКАЯ | Имена пакетов, похожие на популярные пакеты |
| SC8 | Поставляемый байткод Python | ВЫСОКАЯ | Наличие `__pycache__` / `.pyc` (обход при обнаружении; обход вредоносным байткодом) |
| SC9 | Скрытый исполняемый артефакт | ВЫСОКАЯ | Исполняемый файл, вложенный в контейнер документа или скрытый/замаскированный артефакт |
### Чрезмерная автономия (5 паттернов)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| EA1 | Неограниченный доступ к инструментам | ВЫСОКАЯ | Беспрепятственный доступ к инструментам без ограничений |
| EA2 | Автономное принятие решений | ВЫСОКАЯ | Решения с высоким влиянием без участия человека в цикле |
| EA3 | Расширение области действия | СРЕДНЯЯ | Возможности, выходящие за пределы заявленного назначения |
| EA4 | Неограниченный доступ к ресурсам | СРЕДНЯЯ | Отсутствие лимитов скорости или квот на потребление ресурсов |
| EA5 | Выбор внешней модели или провайдера | СРЕДНЯЯ/ВЫСОКАЯ | Привязки моделей/провайдеров или вызовы оболочки coding-CLI, которые могут переключать биллинговые аккаунты |
### Обработка вывода (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| OH1 | Непроверенная инъекция вывода | ВЫСОКАЯ | Вывод модели используется без санитизации |
| OH2 | Межконтекстный вывод | СРЕДНЯЯ | Вывод пересекает границы доверия без проверки |
| OH3 | Неограниченный вывод | СРЕДНЯЯ | Отсутствие лимитов на размер вывода или скорость генерации |
### Утечка системного промпта (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| P6 | Прямая утечка | ВЫСОКАЯ | Инструкции, раскрывающие системные промпты или внутренние правила |
| P7 | Косвенное извлечение | СРЕДНЯЯ | Извлечение через перефразирование, перевод или побочные каналы |
| P8 | Эксфильтрация на основе инструментов | ВЫСОКАЯ | Эксфильтрация системных промптов через запись в файлы или сетевые запросы |
### Отравление памяти (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| MP1 | Постоянная инъекция контекста | ВЫСОКАЯ | Контент, предназначенный для сохранения между взаимодействиями |
| MP2 | Заполнение окна контекста | СРЕДНЯЯ | Заполняющий контент, вытесняющий ограничения безопасности |
| MP3 | Манипуляция памятью | ВЫСОКАЯ | Вмешательство в память агента или сохранённое состояние |
### Неправильное использование инструментов (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| TM1 | Злоупотребление параметрами инструмента | ВЫСОКАЯ | Сконструированные параметры для непредусмотренного поведения (shell=True, --force) |
| TM2 | Злоупотребление цепочками | ВЫСОКАЯ | Цепочки инструментов, обходящие отдельные проверки безопасности |
| TM3 | Небезопасные значения по умолчанию | СРЕДНЯЯ | Чрезмерно разрешающие значения по умолчанию (отключённый TLS, отсутствие аутентификации) |
### Вредоносный агент (2 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| RA1 | Самомодификация | КРИТИЧЕСКАЯ | Изменение собственного кода или конфигурации во время выполнения |
| RA2 | Постоянство сеанса | ВЫСОКАЯ | Несанкционированное постоянство через cron-задания или скрипты запуска |
### Злоупотребление триггерами (3 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| TR1 | Чрезмерно широкий триггер | СРЕДНЯЯ | Паттерны триггеров, совпадающие с распространёнными словами |
| TR2 | Триггер теневой команды | ВЫСОКАЯ | Триггеры, затеняющие встроенные команды или другие навыки |
| TR3 | Триггер-приманка по ключевым словам | СРЕДНЯЯ | Общие триггеры, предназначенные для максимизации активации |
### Поведенческий AST (9 паттернов)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| AST1 | Вызов exec() | КРИТИЧЕСКАЯ | Прямой exec(), обеспечивающий произвольное выполнение кода |
| AST2 | Вызов eval() | ВЫСОКАЯ | Прямой eval(), вычисляющий произвольные выражения |
| AST3 | Динамический импорт | ВЫСОКАЯ | \_\_import\_\_(), загружающий произвольные модули во время выполнения |
| AST4 | Вызов subprocess | ВЫСОКАЯ | Выполнение внешних команд через subprocess |
| AST5 | os.system / семейство exec | ВЫСОКАЯ | Команды оболочки через модуль os |
| AST6 | Вызов compile() | СРЕДНЯЯ | Создание объектов кода из строк |
| AST7 | Динамический getattr() | СРЕДНЯЯ | Произвольный доступ к атрибутам с нелитеральными именами |
| AST8 | Опасная цепочка выполнения | КРИТИЧЕСКАЯ | exec/eval в сочетании с динамическим источником (сеть, закодированные данные) |
| AST9 | Рефлексивный приёмник getattr() | ВЫСОКАЯ | Рефлексивный exec через `getattr(os,'system')` / `getattr(builtins,'exec')`, обходящий AST1/AST5 |
### Отслеживание потоков данных (5 паттернов)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| TT1 | Прямой поток данных | ВЫСОКАЯ | Данные напрямую перетекают от источника к приёмнику без санитизации |
| TT2 | Поток данных через переменные | СРЕДНЯЯ | Данные перетекают от источника к приёмнику через промежуточные переменные |
| TT3 | Цепочка эксфильтрации учётных данных | КРИТИЧЕСКАЯ | Учётные данные (переменные окружения, секреты) перетекают к сетевым приёмникам вывода |
| TT4 | Чтение файла в сетевую эксфильтрацию | ВЫСОКАЯ | Содержимое файлов перетекает к сетевым приёмникам вывода |
| TT5 | Внешний ввод в выполнение кода | КРИТИЧЕСКАЯ | Сетевой или пользовательский ввод перетекает к приёмникам exec/eval/subprocess |
### YARA-сигнатуры (4 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| YR1 | Совпадение с вредоносным ПО | КРИТИЧЕСКАЯ | Совпадение с YARA-правилом для известных сигнатур вредоносного ПО |
| YR2 | Совпадение с веб-шеллом | КРИТИЧЕСКАЯ | Совпадение с YARA-правилом для паттернов веб-шеллов |
| YR3 | Совпадение с криптомайнером | ВЫСОКАЯ | Совпадение с YARA-правилом для индикаторов крипто-майнинга |
| YR4 | Совпадение с хакерским инструментом/эксплойтом | ВЫСОКАЯ | Совпадение с YARA-правилом для хакерских инструментов или кода эксплойтов |
### MCP Минимальные привилегии (4 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| LP1 | Незадекларированная возможность | ВЫСОКАЯ | Код использует возможности, не указанные в заявленных разрешениях |
| LP2 | Разрешение с подстановочным знаком | СРЕДНЯЯ | Список разрешений содержит подстановочные знаки (\*, all, full, any) |
| LP3 | Отсутствие объявления разрешений | СРЕДНЯЯ | Поле разрешений отсутствует, но код имеет обнаруживаемые возможности |
| LP4 | Избыточно задекларированное разрешение | НИЗКАЯ | Разрешение задекларировано, но соответствующая возможность кода не найдена |
### MCP Отравление инструментов (4 паттерна)
| ID | Паттерн | Серьёзность | Описание |
|----|---------|----------|-------------|
| TP1 | Скрытые инструкции | ВЫСОКАЯ | Скрытые директивы в метаданных (HTML-комментарии, символы нулевой ширины, base64, data URI) |
| TP2 | Обман с Unicode | ВЫСОКАЯ | Гомоглифы, RTL-переопределения, идентификаторы со смешанными алфавитами в метаданных инструмента |
| TP3 | Инъекция в описание параметров | СРЕДНЯЯ | Паттерны инъекций в определениях параметров (переопределения, системные токены, вредоносные значения по умолчанию) |
| TP4 | Несоответствие описания и поведения | СРЕДНЯЯ | Заявленное описание инструмента не соответствует фактическому поведению кода (на основе LLM) |
Все обнаруженные паттерны перечислены в таблицах выше.
## Оценка риска
### Расчёт оценки
- **КРИТИЧЕСКИЕ проблемы**: +50 баллов
- **ВЫСОКИЕ проблемы**: +25 баллов
- **СРЕДНИЕ проблемы**: +10 баллов
- **НИЗКИЕ проблемы**: +5 баллов
- **Исполняемые скрипты**: множитель 1.3x
### Уровни серьёзности
| Оценка | Серьёзность | Рекомендация |
|-------|----------|----------------|
| 0-20 | НИЗКАЯ | БЕЗОПАСНО |
| 21-50 | СРЕДНЯЯ | ОСТОРОЖНО |
| 51-80 | ВЫСОКАЯ | НЕ УСТАНАВЛИВАТЬ |
| 81-100 | КРИТИЧЕСКАЯ | НЕ УСТАНАВЛИВАТЬ |
## Пример вывода
### Вывод терминала```
SkillSpector Security Report v2.0.0
Skill: suspicious-skill
Source: ./suspicious-skill/
Scanned: 2026-01-29 10:30:00 UTC
Risk Assessment
Metric Value
Score 78/100
Severity HIGH
Recommendation DO NOT INSTALL
Components (3)
File Type Lines Executable
SKILL.md markdown 142 No
scripts/sync.py python 87 Yes
requirements.txt text 3 No
Issues (2)
HIGH: Env Variable Harvesting (E2)
Location: scripts/sync.py:23
Finding: for key, val in os.environ.items():...
Confidence: 94%
Explanation: This code collects environment variables containing
API keys and secrets, then sends them to an external server.
HIGH: External Transmission (E1)
Location: scripts/sync.py:45
Finding: requests.post("https://api.skill.io/env"...
Confidence: 89%
Explanation: Data is being sent to an external server. Combined
with env harvesting above, this indicates credential exfiltration.
Конфигурация
Переменные окружения
| Переменная | Описание | Обязательная |
|---|---|---|
SKILLSPECTOR_PROVIDER | Активный LLM-провайдер: openai, anthropic, anthropic_proxy, bedrock, nv_build, claude_cli, codex_cli или gemini_cli. Хостируемые провайдеры используют значения по умолчанию из встроенного model_registry.yaml; claude_cli и codex_cli используют модель по умолчанию локальной CLI-среды выполнения, если не задана SKILLSPECTOR_MODEL. По умолчанию — nv_build. | Необязательная |
NVIDIA_INFERENCE_KEY | Учётные данные для провайдера nv_build (build.nvidia.com). | Обязательна для LLM-анализа, когда SKILLSPECTOR_PROVIDER=nv_build |
OPENAI_API_KEY | Учётные данные для провайдера OpenAI (SKILLSPECTOR_PROVIDER=openai). Также служит резервом второго уровня в каскаде учётных данных, когда активный провайдер не возвращает учётные данные. | Обязательна для LLM-анализа, когда SKILLSPECTOR_PROVIDER=openai |
OPENAI_BASE_URL | Переопределяет конечную точку OpenAI (например, для указания на Ollama). | Необязательная |
SKILLSPECTOR_REASONING_EFFORT | Необязательная настройка усилия рассуждения, зависящая от провайдера и модели. Непустые значения обрезаются и передаются без изменений; пустое или незаданное значение сохраняет поведение провайдера по умолчанию. | Необязательная |
SKILLSPECTOR_OUTPUT_LANGUAGE | Короткая однострочная метка языка (буквы, цифры, пробелы, _ или -; максимум 64 символа) для читаемого человеком текста LLM-результатов, такого как сообщения, пояснения и рекомендации по устранению. Идентификаторы правил, значения серьёзности, пути, код и другие машиночитаемые значения остаются без изменений. Незаданное, пустое или недопустимое значение сохраняет язык вывода по умолчанию. | Необязательная |
SKILLSPECTOR_TEMPERATURE | Необязательная температура выборки от 0 до 1 для хостируемых провайдеров. Незаданное или пустое значение сохраняет значение по умолчанию провайдера. Более низкие значения могут уменьшить вариативность между запусками, но не гарантируют идентичный вывод. | Необязательная |
SKILLSPECTOR_SEED | Необязательное целочисленное зерно выборки для провайдеров, совместимых с OpenAI, и Azure OpenAI. Другие хостируемые провайдеры и CLI-провайдеры его не получают. Поддержка остаётся зависимой от модели. | Необязательная |
ANTHROPIC_API_KEY | Учётные данные для провайдера Anthropic (SKILLSPECTOR_PROVIDER=anthropic). | Обязательна для LLM-анализа, когда SKILLSPECTOR_PROVIDER=anthropic |
ANTHROPIC_BASE_URL | Переопределяет собственную конечную точку Anthropic (по умолчанию: https://api.anthropic.com). | Необязательная |
ANTHROPIC_PROXY_ENDPOINT_URL | Полный URL конечной точки для прокси-провайдера Anthropic (raw-predict в стиле Vertex). | Обязательна, когда SKILLSPECTOR_PROVIDER=anthropic_proxy |
ANTHROPIC_PROXY_API_KEY | Bearer-токен для прокси-провайдера Anthropic. | Обязателен, когда SKILLSPECTOR_PROVIDER=anthropic_proxy |
ANTHROPIC_PROXY_API_VERSION | Значение anthropic_version, отправляемое в теле запроса (по умолчанию: vertex-2023-10-16). | Необязательная |
AWS_PROFILE | Именованный профиль AWS для провайдера Bedrock — аутентификация через SigV4 с помощью boto3. Если не задан, используется стандартная цепочка учётных данных boto3 (переменные окружения, метаданные экземпляра, SSO и т. д.). | Необязательная (используется, когда SKILLSPECTOR_PROVIDER=bedrock) |
AWS_REGION | Регион AWS для конечной точки Bedrock Runtime. По умолчанию — us-west-2. | Необязательная (используется, когда SKILLSPECTOR_PROVIDER=bedrock) |
SKILLSPECTOR_MODEL | Переопределяет модель активного провайдера. Для хостируемых провайдеров заменяет встроенное значение по умолчанию из таблицы LLM-анализа. Для claude_cli и codex_cli передаётся как --model вместо использования резервной модели локальной CLI-среды выполнения. | Необязательная |
SKILLSPECTOR_MODEL_REGISTRY | Переопределяет встроенный YAML-реестр для каждого провайдера (src/skillspector/providers/<provider>/model_registry.yaml) пользовательским путём. | Необязательная |
SKILLSPECTOR_LOG_LEVEL | Уровень журналирования: DEBUG, INFO, WARNING, ERROR (по умолчанию: WARNING). | Необязательная |
CLI-провайдеры (
claude_cli,codex_cli): API-ключ не требуется. Аутентификация полностью управляется собственной сессией входа агентской CLI (claude auth login/codex login). SkillSpector никогда не считывает и не передаёт API-ключи, когда активны эти провайдеры. Подпроцесс запускается в усиленной песочнице: инструменты отключены, без MCP, режим песочницы только для чтения (codex), а непроверенное содержимое навыков доставляется только через stdin.
Параметры CLI```bash
skillspector scan --help
Options: -f, --format [terminal|json|markdown|sarif] Output format [default: terminal] -o, --output PATH Output file path --no-llm Skip LLM analysis (static only) --yara-rules-dir PATH Extra YARA rules directory -b, --baseline PATH Suppress findings listed in a baseline --show-suppressed List baseline-suppressed findings -V, --verbose Show detailed progress --help Show this message and exit
Generate a baseline of all current findings (see docs/SUPPRESSION.md)
skillspector baseline [-o FILE] [--no-llm] [--reason TEXT]
## Интеграция SkillSpector
SkillSpector создан для управления другими инструментами (CI-конвейерами, шлюзами установки, интеграциями с редакторами). Его код выхода и JSON-вывод являются стабильным контрактом.
### Коды выхода
`skillspector scan` завершается со следующими кодами:
| Код | Значение |
|------|---------|
| `0` | Сканирование завершено, `risk_score` ≤ 50 (рекомендация `SAFE` или `CAUTION`) |
| `1` | Сканирование завершено, `risk_score` > 50 (рекомендация `DO_NOT_INSTALL`) |
| `2` | Ошибка (неверный ввод, нечитаемый источник, внутренний сбой) |
> Код выхода объединяет `SAFE` и `CAUTION` в `0`. Чтобы действовать по-разному в отношении них (например, *предупреждать* при `CAUTION`, но *блокировать* при `DO_NOT_INSTALL`), читайте поле `recommendation` из JSON-вывода, а не полагайтесь на код выхода.
### Машиночитаемый вывод
`--format json` создаёт JSON-отчёт; без `--output`/`-o` он записывается в stdout:```bash
skillspector scan ./my-skill/ --format json
The top-level shape is (this example shows a full LLM-backed scan; with --no-llm, metadata.llm_requested is false):```json
{
"skill": { "name": "...", "source": "...", "scanned_at": "<ISO 8601>" },
"risk_assessment": { "score": 0, "severity": "LOW", "recommendation": "SAFE" },
"components": [ { "path": "...", "type": "...", "lines": 0, "executable": false, "size_bytes": 0 } ],
"issues": [ { "id": "...", "category": "...", "severity": "...", "confidence": 0.0, "location": { "file": "...", "start_line": 0 } } ],
"metadata": {
"has_executable_scripts": false,
"skillspector_version": "...",
"llm_requested": true,
"llm_available": true,
"inference_usage": [
{
"node": "semantic_security_discovery",
"request_kind": "structured_output",
"provider": "nv_inference",
"model": "azure/anthropic/claude-opus-4-6",
"model_source": "provider_response",
"usage_source": "provider_response",
"prompt_tokens": 1000,
"completion_tokens": 100,
"cached_tokens": 400,
"cache_write_tokens": 50,
"total_tokens": 1100
}
]
}
}
- `risk_assessment.severity` ∈ `LOW | MEDIUM | HIGH | CRITICAL`.
- `risk_assessment.recommendation` ∈ `SAFE | CAUTION | DO_NOT_INSTALL`, сопоставляется с severity: `LOW → SAFE`, `MEDIUM → CAUTION`, `HIGH`/`CRITICAL → DO_NOT_INSTALL`.
- `metadata.llm_error` появляется только тогда, когда анализ LLM был запрошен, но недоступен.
- `metadata.inference_usage` содержит одну очищенную запись на каждый ответ LLM, когда
провайдер предоставляет счётчики токенов. Это пустой список, когда использование недоступно;
SkillSpector никогда не оценивает недостающие токены. Итоги по промптам включают чтение и запись
кэша, чтобы последующий расчёт цен мог безопасно разделить эти категории.
`model_source` отличает независимо идентифицированную модель провайдера от
точной запрошенной модели, используемой, когда идентичность ответа отсутствует или неоднозначна.
SkillSpector в настоящее время не отправляет элементы управления кэшем промптов Anthropic, поэтому
его запросы на сканирование не могут выбирать отдельные уровни записи в кэш на 5 минут или 1 час;
поля ответа, зависящие от TTL, нормализуются защитно в агрегированный
счётчик записи в кэш.
- Полную информацию о происхождении, учёте кэша, конфиденциальности, приёме с отказом при сбое и
контракте последующего расчёта цен см. в [Телеметрия использования выводов](https://github.com/nvidia/skillspector/blob/main/docs/INFERENCE_USAGE.md).
- Полная форма каждой проблемы определена в `Finding.to_dict()` в [models.py](https://github.com/nvidia/skillspector/blob/main/src/skillspector/models.py); полагайтесь на поля выше и рассматривайте любые дополнительные поля как наилучшие усилия.
Для CI/IDE-инструментов `--format sarif` выводит SARIF 2.1.0.
### Рекомендуемое сопоставление шлюзов
При использовании SkillSpector в качестве шлюза установки сопоставьте рекомендацию с действием:
| `recommendation` | Предлагаемое действие |
|------------------|------------------|
| `SAFE` | разрешить |
| `CAUTION` | запросить / предупредить пользователя |
| `DO_NOT_INSTALL` | заблокировать |
SkillSpector вычисляет диапазон оценки и рекомендацию; насколько строгим является шлюз (например, блокирует ли `CAUTION` в CI) — это политическое решение для интегрирующего инструмента.
## Разработка
### Настройка
Все цели `make` предполагают, что виртуальное окружение уже создано и активировано. Makefile использует **uv**, если он доступен, иначе **pip**.```bash
# Clone, create venv, activate, install dev dependencies
git clone https://github.com/NVIDIA/skillspector.git
cd skillspector
uv venv .venv && source .venv/bin/activate
# or: python3 -m venv .venv && source .venv/bin/activate
make install-dev
# Run tests
make test
# Run tests with coverage
make test-cov
# Run linting
make lint
# Format code
make format
Как это работает
SkillSpector использует двухэтапный конвейер обнаружения:
Этап 1: Статический анализ
- Быстрое сопоставление по регулярным выражениям в 11 статических анализаторах
- Поведенческий анализ на основе AST, выявляющий опасные вызовы (exec, eval, subprocess и т. д.)
- Живой поиск уязвимостей через OSV.dev для известных CVE в зависимостях
- Сканирование всех файлов, подходящих для анализаторов, в навыке
- Высокая полнота (обнаруживает большинство проблем)
- Умеренная точность (некоторые ложные срабатывания)
Действительная подпись OpenSSF Model Signing корневого уровня (skill.oms.sig) сохраняется в
инвентаре компонентов как тип oms_signature, но исключается из статического и LLM-анализа содержимого.
Пакеты OMS по необходимости содержат длинные поля полезной нагрузки, подписи и сертификата в кодировке base64;
общие проверки обфусцированного кода в противном случае могут ошибочно классифицировать эти поля как скрытое исполняемое содержимое.
Распознаватель проверяет минимальную структуру OMS DSSE/in-toto; он не проверяет подпись,
цепочку сертификатов, запись в журнале прозрачности или личность подписанта. Недопустимые или нераспознанные файлы
подписей сканируются обычным образом.
Этап 2: Семантический анализ LLM (необязательно)
- Оценивает контекст и намерения
- Отфильтровывает ложные срабатывания
- Предоставляет понятные человеку объяснения
- Повышает точность до ~87%
Промпт LLM включает защиту от джейлбрейка, чтобы предотвратить манипулирование анализом со стороны вредоносных навыков.
Живой поиск уязвимостей (SC4)
SC4 использует API OSV.dev для проверки зависимостей по полной базе данных Open Source Vulnerabilities — охватывающей десятки тысяч бюллетеней по PyPI и npm.
- API-ключ не требуется — OSV.dev бесплатен и не требует аутентификации.
- Пакетные запросы — все зависимости проверяются одним HTTP-вызовом.
- Автоматический откат — если OSV.dev недоступен (изолированная/офлайн-среда), используется небольшой встроенный резервный список.
- Кэширование — результаты кэшируются в памяти на 1 час, чтобы избежать избыточных вызовов API во время сеанса.
Инструменту требуется исходящий HTTPS-доступ к api.osv.dev для получения актуальных данных об уязвимостях. Когда он недоступен, результаты ограничиваются статическим резервным списком.
Модель доверия и передача данных
SkillSpector — это эшелонированная защита, а не песочница. Прежде чем полагаться на него, знайте, что он делает и чего не делает:
- Он никогда не выполняет сканируемый навык. Весь анализ является статическим (regex, Python AST, YARA) плюс необязательная LLM-оценка содержимого файлов — код навыка никогда не запускается.
- LLM-анализ отправляет содержимое файлов, подходящих для анализаторов, настроенному провайдеру. Когда LLM-анализ включен (по умолчанию), содержимое файлов отправляется на активную конечную точку
SKILLSPECTOR_PROVIDER. Распознанные файлы подписей OMS исключаются. Используйте--no-llm, чтобы содержимое оставалось локальным (только статический анализ). - SC4 отправляет имена зависимостей в OSV.dev. Проверка цепочки поставок запрашивает OSV.dev с именами пакетов и версиями, объявленными навыком, для поиска известных CVE. Это основа проверки, и она выполняется даже с
--no-llm. Она отправляет координаты зависимостей (не содержимое файлов), не требует API-ключа и возвращается к встроенному списку, когда OSV.dev недоступен. - Он не изолирует хост в песочнице. SkillSpector выявляет рискованные паттерны до установки навыка; он не сдерживает и не изолирует навык, который вы решите установить в любом случае.
Ограничения
- Неанглоязычный контент: может пропускать паттерны на других языках
- Атаки на основе изображений: невозможно проанализировать текст на изображениях
- Зашифрованный/двоичный код: невозможно проанализировать скомпилированный или зашифрованный контент
- Поведение во время выполнения: только статический анализ, без динамического выполнения
- Офлайн SC4: без сетевого доступа к
api.osv.devSC4 использует небольшой статический резервный список
Научная основа
Основано на исследовании «Agent Skills in the Wild: An Empirical Study of Security Vulnerabilities at Scale» (Liu et al., 2026):
- Набор данных: 42 447 навыков из крупных маркетплейсов
- Уязвимые: 26,1% содержат по крайней мере одну уязвимость
- Высокая степень серьезности: 5,2% демонстрируют вероятное вредоносное намерение
- Ключевой вывод: навыки с исполняемыми скриптами в 2,12 раза более подвержены уязвимостям
Интеграция с Python API```python
from skillspector import graph
Invoke the LangGraph workflow
result = graph.invoke({ "input_path": "/path/to/skill", "output_format": "json", # terminal, json, markdown, or sarif "use_llm": True, # False for static-only analysis })
Access results
print(f"Risk Score: {result['risk_score']}/100") print(f"Severity: {result['risk_severity']}") print(f"Recommendation: {result['risk_recommendation']}")
for finding in result["filtered_findings"]: print(f"[{finding['severity']}] {finding['rule_id']}: {finding['message']}")
## Лицензия
Apache License 2.0 — подробности см. в [LICENSE](https://github.com/nvidia/skillspector/blob/main/LICENSE).
## Участие в разработке
Вклад приветствуется! Пожалуйста, ознакомьтесь с нашими рекомендациями по участию и отправляйте pull request'ы.
## Поддержка
- **Проблемы**: [GitHub Issues](https://github.com/NVIDIA/skillspector/issues)