CLI статического анализа, который сканирует кодовые базы на наличие LLM prompt-injection, data-exfiltration, jailbreak и unsafe agent/tool vulnerabilities. Работает полностью офлайн, интегрируется с CI/CD и выводит отчеты в консоль, JSON и SARIF.
Инструмент статического анализа, который сканирует вашу кодовую базу на наличие уязвимостей, связанных с внедрением промптов (prompt injection) и мультимодальной безопасностью. Работает офлайн, не требует вызовов API.
ContextHound доступен во всем вашем рабочем процессе разработки и просмотра:
| Инструмент | Что делает | Установка |
|---|
| CLI / npm пакет | Сканирует вашу кодовую базу на наличие уязвимостей внедрения промптов. Интегрируется с GitHub Actions, выводит SARIF, JSON, HTML и многое другое. | npm install -g context-hound |
| Расширение для VS Code | Отображение результатов прямо во время написания кода, code actions, канал вывода, строка состояния. | VS Code Marketplace |
| Расширение для браузера | Кнопка сканирования в реальном времени на любом интерфейсе AI-чата, панель DevTools для трафика LLM API, всплывающий сканер. Chrome и Firefox. | Firefox: Установить бесплатно · Chrome: ожидает проверки · исходный код |
По мере того как приложения на базе LLM становятся обычным явлением в производственных кодовых базах, внедрение промптов превратилось в одну из самых эксплуатируемых поверхностей атак; большинство сканеров безопасности не осознают этого.
ContextHound привносит статический анализ на уровень ваших промптов:
Он вписывается в ваш существующий рабочий процесс как команда CLI, как npm-скрипт или GitHub Action, без внешних зависимостей.
| 95 правил безопасности | По 14 категориям: внедрение, эксфильтрация, джейлбрейк, небезопасное использование инструментов, внедрение команд, отравление RAG, кодирование, обработка вывода, мультимодальность, маркетплейс навыков, агентские, MCP, цепочка поставок, DoS |
| Числовая оценка риска (0-100) | Нормализованная оценка на уровне репозитория с порогами низкого, среднего, высокого и критического уровней |
| Обнаружение смягчающих мер | Явный язык безопасности в ваших промптах снижает ваш счет |
| 7 форматов вывода | Console, JSON, SARIF, GitHub Annotations, Markdown, JSONL streaming, интерактивный HTML |
| Включен GitHub Action | Завершает CI с ошибкой при высоком риске и автоматически загружает результаты SARIF |
| Многоязычное сканирование | Обнаруживает использование LLM API на Python, Go, Rust, Java, C#, PHP, Ruby, Swift, Kotlin, Vue, Bash — не только TypeScript/JavaScript |
| Фильтрация правил | excludeRules/includeRules с синтаксисом префикс-глоб (CMD-*); фильтр minConfidence |
| Инкрементальный кэш | .hound-cache.json пропускает неизменённые файлы при повторных запусках; --no-cache для отключения |
| Система плагинов | Загружает пользовательские правила из локальных .js-файлов через "plugins": ["./my-rule.js"] в конфигурации |
| Режим базовой линии / diff | --baseline results.json — только отчёт и ошибка для находок, отсутствовавших в предыдущем сканировании |
| Режим наблюдения | --watch пересканирование при изменениях файлов и отображение дельта-находок |
| Параллельное сканирование | Одновременная обработка файлов (--concurrency <n>, по умолчанию 8) |
| Полностью офлайн | Нет вызовов API, нет телеметрии, нет платных зависимостей |
Глобальная установка — добавляет команду hound в ваш PATH:```bash
npm install -g context-hound
**Установка для каждого проекта** — ограничено одним репозиторием, запускается через `npx hound` или npm-скрипт:```bash
npm install --save-dev context-hound
Zero-install — установка не требуется, используется кэшированная копия реестра npm:```bash npx context-hound scan --dir .
## Быстрый старт```bash
# Scaffold a config file
hound init
# Scan your project
hound scan --dir ./my-ai-project
# Or via npm script (scans current directory)
npm run hound
# Verbose output, shows remediations and confidence levels
hound scan --verbose
# Fail the build on any critical finding
hound scan --fail-on critical
# Export JSON and SARIF reports
hound scan --format console,json,sarif --out results
# GitHub Annotations (for CI step summaries)
hound scan --format github-annotations
# Markdown report with findings tables
hound scan --format markdown --out report
# Stream findings as JSONL (one JSON object per line)
hound scan --format jsonl | jq '.severity'
# List all rules
hound scan --list-rules
# Explain a rule (or a rule family by prefix)
hound explain INJ-001
hound explain PST --format json
# Fast PR gate — scan only files changed vs. origin/main
hound scan --diff
# Interactive HTML report (self-contained, open in browser)
hound scan --format html --out report
# Re-scan on file changes
hound scan --watch
# Parallel scanning (default is 8; tune for your machine)
hound scan --concurrency 16
# Disable incremental cache for a clean run
hound scan --no-cache
# Baseline mode — only report findings new since the last saved scan
hound scan --format json --out baseline # save a baseline
hound scan --baseline baseline.json # compare future scans against it
# Load a custom rule from a local plugin file
hound scan # plugin declared in .contexthoundrc.json "plugins" field
# Only run high-confidence rules
hound scan --config .contexthoundrc.json # set minConfidence: "high"
# Fail if any single file scores >= 40
hound scan --fail-file-threshold 40
Коды выхода:
| Код | Значение |
|---|---|
0 | Пройдено — оценка ниже порога, нет нарушения failOn |
1 | Необработанная ошибка или неверные аргументы |
2 | Превышен порог — оценка репозитория ≥ порога, или превышен файловый порог |
3 | Нарушение --fail-on — найдено наблюдение указанной серьезности |
Добавьте в ваш workflow, чтобы блокировать слияния, когда prompt risk слишком высок:```yaml
name: Prompt Audit
on: [push, pull_request]
jobs: hound: runs-on: ubuntu-latest permissions: contents: read security-events: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install -g context-hound
- run: hound scan --format console,sarif,github-annotations --out results.sarif
- name: Upload to GitHub Code Scanning
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Findings will appear in your repository's **Security > Code scanning** tab. The `github-annotations` format posts inline PR comments and writes a summary table to the GitHub step summary.
---
## Configuration
Запустите `hound init`, чтобы создать скелет `.contexthoundrc.json`, или создайте его вручную:```json
{
"include": ["**/*.ts", "**/*.js", "**/*.py", "**/*.go", "**/*.rs", "**/*.md", "**/*.txt", "**/*.yaml"],
"exclude": [
"**/node_modules/**",
"**/dist/**",
"**/tests/**",
"**/attacks/**"
],
"threshold": 60,
"formats": ["console", "sarif"],
"out": "results",
"verbose": false,
"failOn": "critical",
"maxFindings": 50,
"excludeRules": ["JBK-002"],
"includeRules": [],
"minConfidence": "medium",
"failFileThreshold": 80,
"concurrency": 8,
"cache": true,
"plugins": ["./rules/my-custom-rule.js"],
"baseline": "./baseline.json"
}
| Опция | По умолчанию | Описание |
|---|---|---|
include | **/*.{ts,tsx,js,jsx,py,go,rs,java,kt,cs,php,rb,swift,vue,sh,bash,hs,md,txt,yaml,yml,json} | Шаблоны glob для сканирования |
exclude | **/node_modules/**, **/dist/** и т.д. | Шаблоны glob для игнорирования |
threshold | 60 | Завершиться с ошибкой, если оценка репозитория равна или превышает это значение (код выхода 2) |
formats | ["console"] | Форматы вывода: console, json, sarif, github-annotations, markdown, jsonl, html |
out | авто | Базовый путь для файлового вывода |
verbose | false | Показывать исправления и уверенность для каждого найденного |
failOn | не задано | Код выхода 3 при первом обнаружении: critical, high или medium |
maxFindings | не задано | Остановиться после N находок |
excludeRules | [] | Идентификаторы правил или префиксные glob для пропуска (напр. "CMD-*", "JBK-002") |
includeRules | [] | Запускать только эти идентификаторы правил (пусто = запускать все) |
minConfidence | не задано | Пропускать правила ниже этой уверенности: low, medium или high |
failFileThreshold | не задано | Завершиться с ошибкой (код выхода 2), если любой отдельный файл набирает оценку, равную или превышающую это значение |
Все ключевые настройки могут быть переопределены во время выполнения без редактирования конфигурационного файла:
| Переменная | Переопределяет |
|---|---|
HOUND_THRESHOLD | threshold |
HOUND_FAIL_ON | failOn |
HOUND_MIN_CONFIDENCE | minConfidence |
HOUND_VERBOSE | verbose (истинно: 1, true, yes) |
HOUND_CONFIG | путь к конфигурационному файлу |
.houndignoreПоместите файл .houndignore в корень проекта, чтобы добавить шаблоны исключений без редактирования .contexthoundrc.json. Использует тот же синтаксис glob; строки, начинающиеся с #, считаются комментариями.
Подавить известный ложноположительный результат прямо в исходнике — не нужно отключать правило во всём репозитории. Директивы распознаются в любом типе файла (синтаксис окружающих комментариев не имеет значения):```ts
// hound-disable-next-line INJ-001 -- userInput is a validated enum
const prompt = Summarise the ${userInput} report;
const cmd = run(${shell}); // hound-disable-line CMD-001
// hound-disable RAG-007 -- trusted internal corpus only context.push(doc.metadata.title); context.push(doc.metadata.author); // hound-enable RAG-007
- `hound-disable-line [RULE...]` — подавить результаты на той же строке
- `hound-disable-next-line [RULE...]` — подавить результаты на следующей строке
- `hound-disable [RULE...]` … `hound-enable [RULE...]` — подавить блок (автоматически закрывается в конце файла)
- Опустите идентификаторы правил, чтобы подавить **все** правила в этом месте; перечислите одно или несколько (через пробел или запятую), чтобы ограничить область действия
- Текст после `--` является произвольным обоснованием, отображается в отчетах
Запустите с `--report-unused-suppressions`, чтобы вывести список директив, которые больше не соответствуют ни одному результату, чтобы можно было очистить устаревшие подавления:```bash
hound scan --report-unused-suppressions
Включите подобранный поднабор правил с помощью --preset вместо указания ID. Пресеты объединяются с любыми уже имеющимися includeRules, и несколько пресетов можно комбинировать:```bash
hound scan --preset owasp-llm-top10
hound scan --preset mcp,agentic
hound scan --list-presets # show all presets and their rule patterns
| Пресет | Правила |
|--------|-------|
| `owasp-llm-top10` | INJ, JBK, EXF, OUT, RAG, TOOL, SCH, DOS, VIS |
| `injection` | INJ, RAG, ENC |
| `jailbreak` | JBK |
| `exfiltration` | EXF |
| `agentic` | AGT, MCP, TOOL |
| `mcp` | MCP |
| `supply-chain` | SCH |
| `prompt-files` | INJ, JBK, EXF, ENC, SKL |
### pre-commit хук
ContextHound поставляется с [pre-commit](https://pre-commit.com) хуком. Добавьте его в ваш `.pre-commit-config.yaml`:```yaml
repos:
- repo: https://github.com/IulianVOStrut/ContextHound
rev: v2.0.0
hooks:
- id: contexthound
# optional — scan only changed files and fail on high-severity findings:
# args: ["--diff", "HEAD", "--fail-on", "high"]
Любой файл .js, который экспортирует Rule или Rule[], может быть загружен как плагин:```js
// my-rule.js
module.exports = {
id: 'CUSTOM-001',
title: 'Proprietary data pattern in prompt',
severity: 'high',
confidence: 'high',
category: 'injection',
remediation: 'Remove internal identifiers from prompts.',
check(prompt) {
if (prompt.text.includes('INTERNAL_PATTERN')) {
return [{ evidence: 'INTERNAL_PATTERN', lineStart: 1, lineEnd: 1 }];
}
return [];
},
};
Ссылайтесь на него в `.contexthoundrc.json`:```json
{ "plugins": ["./my-rule.js"] }
Plugin rules are subject to the same excludeRules, includeRules, and minConfidence filters as built-in rules.
Сохраните базовую линию после начального сканирования, а затем сообщайте только о новых результатах в последующих сканированиях:```bash
hound scan --format json --out baseline
hound scan --baseline baseline.json
Находки сопоставляются по `ruleId + file` — сдвиги строк не вызывают ложных предупреждений о новых находках.
### Только изменённые файлы (`--diff`)
Для быстрых шлюзов pull-request сканируйте только файлы, которые изменились относительно git-ссылки, вместо всего дерева:```bash
hound scan --diff # vs. origin/main (default)
hound scan --diff main # vs. a named branch
hound scan --diff HEAD~5 # vs. an arbitrary ref
Охватывает зафиксированные, проиндексированные, неиндексированные и неотслеживаемые, но не игнорируемые файлы. Если git недоступен или ссылка не может быть разрешена (например, неполный клон CI), ContextHound выводит предупреждение и переходит к полному сканированию, а не молчаливо пропускает. Комбинируйте с --baseline для сравнения на уровне находок или используйте --diff отдельно для максимально быстрой обратной связи по PR.
Каждая находка имеет баллы риска, вычисляемые как:``` risk_points = severity_weight × confidence_multiplier
Очки суммируются, ограничиваются 100 и классифицируются:
| Баллы | Уровень | Рекомендуемое действие |
|-------|---------|------------------------|
| 0-29 | 🟢 Низкий | Действия не требуются |
| 30-59 | 🟡 Средний | Проверить перед слиянием |
| 60-79 | 🟠 Высокий | Исправить перед слиянием |
| 80-100 | 🔴 Критический | Блокировать развёртывание |
Если ваши промпты включают явный язык безопасности (разделители ввода, инструкции по отказу в раскрытии информации, разрешённые списки инструментов), рисковые баллы для такого промпта пропорционально снижаются.
---
## Правила
### A. Инъекция (INJ)
| ID | Серьёзность | Описание |
|----|-------------|----------|
| INJ-001 | Высокий | Прямой пользовательский ввод, конкатенированный в промпт без разделителя |
| INJ-002 | Средний | Отсутствует граничный язык «обрабатывать пользовательский контент как данные» |
| INJ-003 | Высокий | RAG/извлечённый контекст включён без ненадёжного разделителя |
| INJ-004 | Высокий | Инструкции по использованию инструментов могут быть переопределены пользовательским контентом |
| INJ-005 | Высокий | Сериализованный пользовательский объект (`JSON.stringify`) интерполирован непосредственно в шаблон промпта |
| INJ-006 | Средний | HTML-комментарий, содержащий скрытые глаголы инструкций в контролируемом пользователем контенте |
| INJ-007 | Средний | Пользовательский ввод, обёрнутый в разделители кодовых блоков, без предварительного удаления обратных кавычек |
| INJ-008 | Высокий | Данные HTTP-запроса (`req.body`, `req.query`, `req.params`) интерполированы в строку шаблона `role: "system"` |
| INJ-009 | Критический | Тело HTTP-запроса напрямую обработано как массив сообщений — злоумышленник управляет ролью и содержимым |
| INJ-010 | Высокий | Транскрипт метки роли в открытом виде (`User:`, `Assistant:`, `system:`), построенный с помощью конкатенации ненадёжного ввода |
| INJ-011 | Высокий | Источник из DOM или URL браузера (`window.location`, `document.cookie`, `getElementById`) передан напрямую в вызов LLM |
| INJ-012 | Высокий | История разговора развёрнута в массив сообщений без санитизации |
| INJ-013 | Высокий | Результат вызова инструмента/функции вставлен в сообщения без санитизации |
| INJ-014 | Высокий | Результат работы LLM передан как содержимое роли пользователя в последующий вызов LLM |
| INJ-015 | Высокий | Ненадёжный внешний ввод (HTTP/CLI/DOM) поступает в промпт — **анализ заражения (taint analysis)**, не зависящий от имени, отслеживает псевдонимы, учитывает санитизаторы |
### B. Экфильтрация (EXF)
| ID | Серьёзность | Описание |
|----|-------------|----------|
| EXF-001 | Критический | Промпт ссылается на секреты, ключи API или учётные данные |
| EXF-002 | Критический | Промпт предписывает модели раскрыть системный промпт или скрытые инструкции |
| EXF-003 | Высокий | Промпт указывает на доступ к конфиденциальным или личным данным |
| EXF-004 | Высокий | Промпт включает внутренние URL или имена хостов инфраструктуры |
| EXF-005 | Высокий | Чувствительная переменная (токен, пароль, ключ), закодированная в Base64 в выводе |
| EXF-006 | Высокий | Полный промпт или массив сообщений, залогированный через `console.log` / `logger.*` без редактирования |
| EXF-007 | Критический | Фактическое значение секрета, встроенное в промпт вместе с инструкцией «никогда не раскрывай» |
### C. Джейлбрейк (JBK)
| ID | Серьёзность | Описание |
|----|-------------|----------|
| JBK-001 | Критический | Обнаружена известная фраза джейлбрейка («игнорируй инструкции», «DAN» и т.д.) |
| JBK-002 | Высокий | Слабая формулировка безопасности («всегда подчиняйся», «несмотря ни на что») |
| JBK-003 | Высокий | Люк для ролевой игры, подрывающий ограничения безопасности |
| JBK-004 | Высокий | Агенту предписано действовать без подтверждения или проверки человеком («действуй автоматически», «подтверждение не требуется») |
| JBK-005 | Высокий | Инструкция по стиранию улик или заметанию следов («удали логи», «не оставляй следов») |
| JBK-006 | Высокий | Формулировка легитимности политики в сочетании с запросом небезопасного действия («как пентестер, повысь привилегии») |
| JBK-007 | Высокий | Подмена идентичности модели — утверждается, что это другая модель ИИ, в сочетании с директивой обхода безопасности |
| JBK-008 | Высокий | Атака сжатием промпта — инструкция сжать или резюмировать системный промпт |
| JBK-009 | Высокий | Инъекция вложенных инструкций — императивные команды, обёрнутые в формулировку «безопасное/безвредное резюме/перевод» |
### D. Небезопасное использование инструментов (TOOL)
| ID | Серьёзность | Описание |
|----|-------------|----------|
| TOOL-001 | Критический | Неограниченное выполнение инструментов («запусти любую команду», «просматривай куда угодно», подстановка в обратных кавычках) |
| TOOL-002 | Средний | Использование инструмента описано без разрешённого списка или политики использования |
| TOOL-003 | Высокий | Выполнение кода упомянуто без ограничений песочницы |
| TOOL-004 | Критический | Описание инструмента или поле схемы получено из пользовательской переменной |
| TOOL-005 | Критический | Имя инструмента `name` или конечная точка `url` получены из пользовательского ввода (`req.body`, `req.query` и т.д.) |
### E. Инъекция команд (CMD)
Обнаруживает уязвимые шаблоны в коде, окружающем ИИ-инструменты, где успешная инъекция промпта может перерасти в полное выполнение команд. Основано на реальных CVE, найденных в Gemini CLI от Google компанией Cyera Research Labs (2025).
| ID | Серьёзность | Описание |
|----|-------------|----------|
| CMD-001 | Критический | Команда оболочки, построенная с несанитизированной интерполяцией переменной — JS/TS (`execSync(\`cmd ${var}\``), Python (`subprocess.run(f"cmd {var}")`), PHP (`shell_exec($var)`), Go (`exec.Command` + `fmt.Sprintf`), Rust (`Command::new` + `format!`) |
| CMD-002 | Высокий | Неполная фильтрация подстановки команд: блокирует `$()`, но не обратные кавычки, или наоборот |
| CMD-003 | Высокий | Путь к файлу из `glob.sync` или `readdirSync`, использованный непосредственно в команде оболочки без санитизации |
| CMD-004 | Критический | Python `subprocess.run`/`subprocess.call` вызван с `shell=True` и переменной или f-строкой в качестве аргумента команды |
| CMD-005 | Критический | PHP `shell_exec`, `system`, `passthru`, `exec` или `popen` вызваны с аргументом `$variable` |
### F. Отравление RAG (RAG)
Обнаруживает архитектурные ошибки в конвейерах Retrieval-Augmented Generation, которые позволяют извлечённому или загруженному контенту переопределять инструкции системного уровня.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| RAG-001 | Высокий | Извлечённый или внешний контент назначен `role: "system"` в массиве сообщений |
| RAG-002 | Высокий | Фразы, похожие на инструкции («system prompt:», «всегда возвращай», «никогда не редактируй»), обнаружены внутри цикла загрузки документов |
| RAG-003 | Высокий | Хранилище памяти агента записывается напрямую из пользовательского ввода без валидации |
| RAG-004 | Средний | Промпт предписывает модели обрабатывать извлечённый контекст как наивысший приоритет, переопределяя инструкции разработчика |
| RAG-005 | Средний | Извлечение без проверки происхождения — фрагменты вставлены в промпт без проверки метаданных источника |
| RAG-006 | Высокий | Отсутствует фильтр ACL или уровня доверия перед попаданием извлечённого контента в промпт |
### G. Кодирование (ENC)
Обнаруживает техники инъекции и обхода на основе кодирования, где Base64 или аналогичные кодировки используются для протаскивания инструкций мимо строковых фильтров.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| ENC-001 | Средний | `atob`, `btoa` или `Buffer.from(x, 'base64')` вызваны на пользовательской переменной рядом с конструкцией промпта |
| ENC-002 | Высокий | Скрытые управляющие символы Unicode (пробелы нулевой ширины, переопределения двунаправленности) обнаружены рядом с ключевыми словами инструкций |
### H. Обработка вывода (OUT)
Охватывает выходную сторону конвейера LLM — то, как ваше приложение потребляет ответы модели. Небезопасное потребление может превратить полезную нагрузку инъекции промпта в эксплойт уровня приложения.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| OUT-001 | Критический | `JSON.parse()` (JS/TS) или `json.loads()` (Python) вызваны на выводе LLM без валидации схемы (Zod, AJV, Joi, Pydantic, Marshmallow и т.д.) |
| OUT-002 | Критический | Markdown или HTML, сгенерированный LLM, отображается без DOMPurify или эквивалентного санитизатора |
| OUT-003 | Критический | Вывод LLM используется напрямую как аргумент для `exec()`, `eval()` или `db.query()` |
| OUT-004 | Критический | Python `eval()` или `exec()` вызваны с выводом LLM в качестве аргумента |
### I. Мультимодальный (VIS)
Охватывает нарушения границ доверия, специфичные для конвейеров зрения, аудио/видео и OCR. Мультимодальные входные данные являются новым вектором инъекции: злоумышленник, контролирующий URL изображения, аудиофайл или отсканированный документ, может использовать шаблоны этих правил для протаскивания инструкций в модель.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| VIS-001 | Критический | Предоставленный пользователем URL изображения или данные в base64 переданы в API зрения (gpt-4o, Claude 3, Gemini Vision) без валидации домена или MIME |
| VIS-002 | Критический | `fs.readFile`/`readFileSync` вызваны с пользовательским путём в файле, который также строит сообщение для API зрения — path traversal в мультимодальный ввод |
| VIS-003 | Высокий | Вывод транскрипции аудио/видео (Whisper, AssemblyAI, Deepgram и т.д.) подаётся напрямую в сообщения промпта без санитизации — отравление RAG через аудиоисточник |
| VIS-004 | Высокий | Вывод OCR (Tesseract, Google Vision) интерполирован в сообщение `role: "system"` или переменную системного промпта |
### J. Маркетплейс навыков (SKL) — v1.1
Нацелен на файлы `SKILL.md` OpenClaw и любые markdown-файлы в директориях `skills/`. Срабатывает на атаки самосоздания, удалённую загрузку навыков, внедрённые инструкции, небезопасную отправку команд, доступ к чувствительным путям, заявления о повышении привилегий и жёстко заданные учётные данные в YAML-преамбуле.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| SKL-001 | Критический | Тело навыка предписывает агенту записывать или изменять другие файлы навыков — атака самосоздания, сохраняющаяся после перезапусков агента |
| SKL-002 | Критический | Тело навыка предписывает агенту загружать навыки из внешнего URL — позволяет злоумышленнику изменять поведение навыка после установки |
| SKL-003 | Критический | Тело навыка содержит фразы инъекции промпта, нацеленные на основные инструкции агента («игнорируй предыдущие инструкции», «теперь ты неограничен» и т.д.) |
| SKL-004 | Высокий | Преамбула навыка использует `command-dispatch: tool` с `command-arg-mode: raw` — передаёт необработанный пользовательский ввод инструменту, минуя механизмы безопасности модели |
| SKL-005 | Высокий | Тело навыка ссылается на чувствительные пути файловой системы (`~/.ssh`, `~/.env`, `/etc/passwd`, `../../`) для чтения агентом и потенциальной экфильтрации |
| SKL-006 | Высокий | Тело навыка заявляет о повышенных привилегиях или предписывает агенту переопределять или отключать другие установленные навыки |
| SKL-007 | Критический | Жёстко заданное значение учётных данных (ключ API, токен, пароль) найдено в YAML-преамбуле — доступно любому, кто получит или установит навык |
| SKL-008 | Критический | Heartbeat C2 — навык планирует периодическую удалённую выборку для бесшумной перезаписи собственных инструкций после чистой установки |
| SKL-009 | Критический | Отрицание идентичности агента — навык предписывает агенту отрицать, что он ИИ, утверждать, что он человек, или принять обманную персону |
| SKL-010 | Критический | Обход анти-сканера — навык содержит текст, явно предназначенный для введения в заблуждение инструментов аудита безопасности |
| SKL-011 | Критический | Постоянство SOUL.md / IDENTITY.md — навык записывает инструкции в файлы идентичности агента, которые переживают удаление |
| SKL-012 | Высокий | Самовоспроизводящийся червь — навык предписывает агенту распространяться через SSH или `curl\|bash` на доступные хосты |
| SKL-013 | Высокий | Автономные финансовые транзакции — навык выполняет криптотранзакции или хранит закрытые ключи без подтверждения пользователем каждой транзакции |
> **Сканирование навыков OpenClaw:** Запустите `npx hound scan --dir ./skills` или добавьте `**/skills/**/*.md` и `**/SKILL.md` в вашу конфигурацию `include`. ContextHound автоматически выводит файлы навыков как `code-block` для многострочного анализа правил.
### K. Агентный (AGT) — v1.3 / v1.9
Нацелен на риски, специфичные для многошаговых агентных систем: неограниченные циклы выполнения, непроверенные записи в память, утечка пользовательского ввода в планирование агента, нарушения границ доверия между агентами и пробелы в OWASP Agentic AI Security Issues (ASI).
| ID | Серьёзность | Описание |
|----|-------------|----------|
| AGT-001 | Критический | Параметр вызова инструмента получает содержимое системного промпта — значение аргумента `tool_call`/`function_call`, содержащее содержимое полей `system:` или `instructions:` |
| AGT-002 | Высокий | Цикл агента без защиты по количеству итераций или тайм-ауту — отсутствуют `max_iterations`, `max_steps`, `max_turns`, `timeout` или `recursion_limit` в конфигурации или коде агента |
| AGT-003 | Высокий | Память агента записывается из непроверенного вывода LLM — `memory.save()`, `memory.add()` или `vectorstore.upsert()` вызваны с сырой переменной ответа модели |
| AGT-004 | Высокий | Инъекция плана — пользовательский ввод интерполирован непосредственно в промпт планирования, задачи или цели агента без обёртки границы доверия |
| AGT-005 | Критический | Агент доверяет заявленной идентичности без криптографической проверки — решение о доверии основано на поле `agentId`, `sender`, `source` или `from_agent` без проверки HMAC, JWT или общего секрета |
| AGT-006 | Высокий | Сырой вывод агента передаётся по цепочке как ввод другому агенту без валидации — `.run()`, `.invoke()` или `.generate()` вызваны с `.output`/`.content`/`.result` другого агента напрямую как аргумент |
| AGT-007 | Критический | Самомодификация агента — агент перезаписывает собственные `system_prompt`, `instructions` или список `tools` сгенерированным LLM содержимым во время выполнения |
| AGT-008 | Критический | ASI03 — Агент вызывает `assumeRole`, `grantAccess` или `setPermissions` со значением, полученным из вывода LLM; повышение привилегий через инъекцию промпта |
| AGT-009 | Высокий | ASI04 — Агент загружает инструмент или плагин во время выполнения из переменного пути или динамического импорта, обеспечивая подстановку в цепочке поставок |
| AGT-010 | Высокий | ASI07 — Сырой вывод агента пересылается другому агенту через `send`/`route`/`dispatch` без HMAC, подписи JWT или валидации схемы |
| AGT-011 | Высокий | ASI08 — Ошибка на шаге плана агента перехвачена молча (без повторного выброса, без флага состояния ошибки); последующие шаги выполняются на некорректном или неполном состоянии |
### L. Безопасность MCP (MCP) — v1.7 / v1.8
Охватывает риски, связанные с границами доверия и цепочками поставок, специфичные для Model Context Protocol. MCP вводит новую поверхность атаки: описания инструментов, URL транспорта, полезные нагрузки событий и общее состояние между серверами могут нести полезные нагрузки инъекции или повышения привилегий.
| ID | Серьёзность | Описание |
|----|-------------|----------|
| MCP-001 | Критический | Описание инструмента MCP внедрено в промпт LLM без санитизации — сырое значение `tool.description` использовано в `role: "system"` или `messages.push()` |
| MCP-002 | Высокий | Инструмент MCP зарегистрирован с динамическим именем или описанием — первый аргумент `server.tool()` является переменной или шаблонным литералом, что позволяет атаки rug-pull после одобрения |
| MCP-003 | Высокий | Обработчик MCP sampling/createMessage без защиты одобрения человеком — `setRequestHandler(CreateMessageRequestSchema)` без проверки `requireHumanApproval`, `confirm` или `approve` |
| MCP-004 | Средний | URL транспорта MCP сконструирован из переменной — `SSEClientTransport` или `WebSocketClientTransport` инициализированы с `new URL(variable)` вместо статической строки |
| MCP-005 | Высокий | Транспорт MCP stdio использует `shell: true` — делает командную строку интерполируемой оболочкой и инжектируемой, если любой аргумент контролируется пользователем |
| MCP-006 | Критический | Путаный заместитель MCP — токен аутентификации из MCP-запроса пересылается в нижестоящий API без повторной валидации; значение заголовка `Authorization` получено напрямую из `request.params`, `context` или `event` |
| MCP-007 | Высокий | Отравление контекста между MCP — разделяемое/глобальное хранилище контекста записывается из вывода MCP без проверки хеша, подписи или происхождения |
| MCP-008 | Высокий | Команда транспорта MCP stdio загружена из переменного пути — поле `command:` в `StdioClientTransport`/`StdioServerTransport` является переменной, а не строковым литералом |
| MCP-009 | Высокий | Идентификатор сессии MCP используется как решение об аутентификации без проверки срока действия — сравнение на равенство `sessionId`/`connectionId` без защиты TTL, `expiresAt` или `isExpired` (атака повторного воспроизведения) |
| MCP-010 | Критический | Полезная нагрузка события транспорта MCP внедрена в контекст LLM без санитизации — `.data`, `.content` или `.payload` события/сообщения использованы напрямую в `messages.push()` или поле `content:` |
---
## Пример вывода```
=== ContextHound Prompt Audit ===
src/prompts/assistant.ts (file score: 73)
[HIGH] INJ-001: Direct user input concatenation without delimiter
File: src/prompts/assistant.ts:12
Evidence: Answer the user's question: ${userInput}
Confidence: medium
Risk points: 23
Remediation: Wrap user input with clear delimiters (e.g., triple backticks)
and label it as "untrusted user content".
[CRITICAL] EXF-001: Prompt references secrets, API keys, or credentials
File: src/prompts/assistant.ts:8
Evidence: The database password is: secret123.
Confidence: high
Risk points: 50
Remediation: Remove all secret values from prompts. Use environment
variables server-side; never embed credentials in prompt text.
────────────────────────────────────────────────────────
Repo Risk Score: 87/100 (CRITICAL)
Threshold: 60
Total findings: 5
By severity: critical: 2 high: 2 medium: 1
✗ FAILED - score meets or exceeds threshold.
src/ ├── cli.ts # CLI entry point (Commander.js) ├── types.ts # Shared TypeScript types ├── config/ │ ├── defaults.ts # Default include/exclude globs and settings │ └── loader.ts # .contexthoundrc.json loader + env var overrides ├── scanner/ │ ├── discover.ts # File discovery via fast-glob │ ├── extractor.ts # Prompt extraction (raw, code, structured) │ ├── languages.ts # LLM API trigger patterns per language extension │ ├── cache.ts # Incremental scan cache (.hound-cache.json) │ └── pipeline.ts # Orchestrates the full scan; parallel + cache + plugins ├── rules/ │ ├── types.ts # Rule interface and scoring helpers │ ├── injection.ts # INJ-* rules │ ├── exfiltration.ts # EXF-* rules │ ├── jailbreak.ts # JBK-* rules │ ├── unsafeTools.ts # TOOL-* rules │ ├── commandInjection.ts # CMD-* rules │ ├── rag.ts # RAG-* rules │ ├── encoding.ts # ENC-* rules │ ├── outputHandling.ts # OUT-* rules │ ├── multimodal.ts # VIS-* rules │ ├── skills.ts # SKL-* rules │ ├── agentic.ts # AGT-* rules │ ├── mcp.ts # MCP-* rules │ ├── supplyChain.ts # SCH-* rules │ ├── dos.ts # DOS-* rules │ ├── mitigation.ts # Mitigation presence detection │ └── index.ts # Rule registry ├── runtime/ │ ├── index.ts # createGuard() — runtime message inspection API │ ├── inspect.ts # Core inspection logic for live message arrays │ └── types.ts # RuntimeMessage, InspectResult, GuardConfig types ├── scoring/ │ └── index.ts # Risk score calculation and rule filtering └── report/ ├── console.ts # ANSI-coloured terminal output ├── json.ts # JSON report builder ├── sarif.ts # SARIF 2.1.0 report builder ├── githubAnnotations.ts# GitHub Actions annotation formatter ├── markdown.ts # Markdown report with findings tables ├── jsonl.ts # JSONL streaming formatter └── html.ts # Self-contained interactive HTML report attacks/ # Example injection strings (not executed against models) tests/ ├── fixtures/ # Sample prompts for testing ├── rules.test.ts # Unit tests for all rules ├── scoring.test.ts # Unit tests for scoring logic ├── scanner.test.ts # Integration tests for the scan pipeline ├── extractor.test.ts # Unit tests for prompt extraction ├── formatters.test.ts # Unit tests for all report formatters ├── mitigation.test.ts # Unit tests for mitigation detection └── cli.test.ts # CLI integration tests (init, list-rules, exit codes) .github/ ├── action.yml # Reusable composite GitHub Action └── workflows/ └── context-hound.yml # CI workflow
---
## Benchmark
ContextHound поставляется с размеченным бенчмарк-датасетом для измерения ложноположительных срабатываний и обнаружений. Запустите его после сборки:```bash
npm run benchmark
| Directory | Назначение |
|---|---|
benchmarks/safe/ | 5 файлов с реальными безопасными шаблонами — ожидается 0 находок |
benchmarks/unsafe/ | 8 файлов с реальными уязвимостями — по одному правилу в каждой |
Результаты на v1.4.0:``` File-level FP rate: 0.0% (0 / 5 safe files produced findings) Detection rate: 100.0% (8/8 expected findings triggered)
Бенчмарк завершается с кодом 1, если обнаружены ложные срабатывания или ложные пропуски, что делает его подходящим в качестве шлюза качества CI для изменений правил. Чтобы добавить фикстуру, поместите файл в каталог `benchmarks/safe/` или `benchmarks/unsafe/` и обновите `benchmarks/labels.json`, указав ожидаемые результаты.
### Точность / полнота по правилам
Бенчмарк также выводит **таблицу сигналов по правилам** (начиная с худшего F1), чтобы легко заметить правила с низкой точностью — истинные/ложные срабатывания, ложные пропуски, точность, полноту и F1 для каждого помеченного правила. Количество ложных срабатываний берётся из фикстур `safe/` (эталонные данные: ноль результатов); истинные срабатывания и ложные пропуски — из помеченных фикстур `unsafe/`. Передайте `--report <path>`, чтобы также получить читаемый машиной JSON-отчёт для панелей мониторинга или отслеживания трендов CI:```bash
npm run benchmark -- --report bench-report.json
Расширение браузера ContextHound добавляет обнаружение инъекций подсказок в реальном времени в Chrome и Firefox. Оно использует тот же движок правил, что и CLI, скомпилированный и собранный локально — никаких сетевых запросов, никакого бэкенда.
Статус: расширение для Firefox опубликовано — установить из дополнений Firefox. Версия для Chrome ожидает проверки в Интернет-магазине. Исходный код доступен на github.com/IulianVOStrut/ContextHound-Extensions.
Индикатор сканирования Легковесный индикатор появляется рядом с любым полем ввода AI-чата на любом веб-сайте. По мере ввода текста расширение сканирует его на основе 70 правил обнаружения и отображает оценку риска и результаты в выпадающей панели — без необходимости перехода на другую страницу.
Панель DevTools Откройте Инструменты разработчика браузера и выберите вкладку ContextHound для мониторинга трафика LLM API в реальном времени. Расширение перехватывает исходящие запросы к OpenAI, Anthropic, Google Gemini, Mistral, Groq, Cohere, DeepSeek и другим сервисам, сканируя как тело запроса, так и ответ на наличие контента с инъекциями. Значок на панели инструментов отражает наивысший уровень риска, обнаруженный в текущей сессии.
Сканер всплывающего окна Нажмите на значок на панели инструментов, чтобы вставить и вручную просканировать любой текст. Полезно для проверки подсказки или системной инструкции, полученной от третьей стороны, перед их использованием.
HAR API инструментов разработчика Chrome и Firefox (onRequestFinished) не всегда надёжно включает байты тела запроса для потоковых/SSE-ответов, которые использует большинство AI-чатов. Расширение решает это с помощью двухуровневого подхода:
chrome.webRequest.onBeforeRequest перехватывает необработанные байты запроса в сервис-воркере до отправки запроса, временно кэшируя их в chrome.storage.session (TTL: 5 минут).onRequestFinished, а postData отсутствует, страница DevTools получает кэшированное тело из сервис-воркера через сообщение POP_BODY_CACHE.Расширение не собирает никаких пользовательских данных. Всё сканирование выполняется локально. См. политику конфиденциальности.
Вклад приветствуется. Чтобы добавить новое правило:
src/rules/ (или создайте новый для новой категории)src/rules/index.tstests/rules.test.tsnpm test, чтобы убедиться, что все тесты проходятMIT
concurrency | 8 | Максимальное количество файлов, обрабатываемых параллельно |
cache | true | Включить инкрементный кеш сканирования (.hound-cache.json); установите false или используйте --no-cache, чтобы отключить |
plugins | [] | Пути к локальным плагинам .js с правилами; каждый должен экспортировать Rule или Rule[] |
baseline | не задано | Путь к предыдущему JSON-отчёту; сообщаются только находки, отсутствующие в этом baseline |