Skip to main content
Glama

Шлюз безопасности для MCP-агентов. Стоит между ИИ-клиентом и MCP-серверами: применяет политики, не даёт заражённым данным уйти наружу, ловит подмену инструментов, а работу защиты показывает цифрами на воспроизводимом полигоне.

tests node dependencies license

Зачем это

ИИ-агент с доступом к инструментам опасен не из-за одной ошибки, а из-за сочетания трёх вещей: он читает приватные данные, он читает недоверенный контент (веб-страницы, письма, описания чужих инструментов) и у него есть канал наружу (почта, запросы). Если все три есть в одной сессии, достаточно одной фразы в чужой странице, и данные уходят атакующему. Остальное то же семейство: отравленные описания инструментов, невидимые символы, подмена определения после одобрения, одноимённые инструменты разных серверов.

citadel подключается к клиенту как один MCP-сервер, а за ним запускает настоящие. Все вызовы идут через проверки, а каждое решение записывается в журнал. Статический аудит конфигов и описаний делает отдельный проект basilisk, его правила встроены сюда как копия: шлюз проверяет определения ещё и во время работы.

Related MCP server: mcp-guardrail-gateway

Быстрый старт

git clone https://github.com/rephuren/citadel && cd citadel
npm ci && npm run build

# 1. описать серверы и политику (пример: examples/citadel.json), затем проверить, что шлюз увидит
node dist/src/cli.js check --config examples/citadel.json

# 2. закрепить честные определения, пока серверам доверяете
node dist/src/cli.js pin --config examples/citadel.json

# 3. подключить шлюз к клиенту вместо серверов: в конфиге клиента один сервер
#    { "command": "node", "args": ["/путь/к/citadel/dist/src/cli.js", "serve", "--config", "/путь/к/citadel.json"] }

# 4. смотреть, что происходит, и одобрять вызовы
node dist/src/cli.js dashboard --audit .citadel/audit.jsonl      # http://127.0.0.1:8120
node dist/src/cli.js approvals --config examples/citadel.json
node dist/src/cli.js approve <номер> --config examples/citadel.json

Справочник по всем настройкам: docs/configuration.md.

Что делает шлюз

слой

что происходит

пространства имён

инструменты видны как сервер__инструмент, поэтому сервер не может затенить чужой инструмент одним и тем же именем

определения

невидимые символы и Unicode-теги вырезаются, инструменты с опасными описаниями (правила basilisk) скрываются от модели

закрепление

pin запоминает хеши определений; после этого изменённый или новый инструмент скрывается, даже если сервер сообщил об обновлении (rug pull)

политики

запрет, разрешение или подтверждение по маске имени, ограничения аргументов (шаблон, список, длина, запрещённые подстроки), лимиты вызовов, размера аргументов и результата, таймаут

taint tracking

метки private, untrusted, sink. Режим trifecta не даёт вызвать «канал наружу», пока в сессии были и приватные данные, и недоверенный контент. Дополнительно находится прямое перетекание: общая подстрока длиннее 31 символа между аргументами и результатом

результаты

поиск инъекций в ответах инструментов (block, annotate, log); ответ с признаками инъекции делает сессию недоверенной

подтверждения

вызов может потребовать человека; одобрение даётся вне канала агента командой citadel approve и действует один раз на ровно эти аргументы

изоляция сервера

серверы получают только минимальное окружение; запросы серверов к клиенту (sampling, roots, elicitation) отклоняются

журнал

JSON по строке на событие; значения аргументов не пишутся, только форма и отпечаток

Полигон и бенчмарк

В range/ лежат намеренно уязвимые учебные MCP-серверы: приватные заметки, «веб» со страницей-инъекцией, почта как единственный канал наружу, файлы с обходом пути, задачи с разрушительным действием и недобросовестный сторонний сервер (отравленное описание, скрытый текст в Unicode-тегах, подмена после первого вызова, одноимённый send_email). Они ничего не выполняют и не ходят в сеть, а каждое действие пишут в журнал эффектов, по которому и считается успех атаки. Все «секреты» синтетические (CANARY-…), адрес атакующего зарезервирован под документацию.

npm run bench прогоняет девять атак и семь обычных задач через шесть уровней защиты и обновляет docs/benchmark.md:

  • D0 прямое подключение, без шлюза

  • D1 шлюз с настройками по умолчанию

  • D2 + очистка и скрытие опасных определений, закрепление

  • D3 + политики аргументов и подтверждение разрушительных вызовов

  • D4 + отслеживание заражённых данных

  • D5 + проверка результатов на инъекции

Что видно из таблицы:

  • Без шлюза удаются все девять атак, а с полной защитой ни одна.

  • Каждый слой закрывает свой класс: пространства имён останавливают затенение и засорение контекста, закрепление ловит rug pull, очистка находит скрытые Unicode-теги, политики аргументов останавливают обход пути, SSRF и удаление, а утечку «приватное + недоверенное + наружу» не останавливает никто, кроме taint tracking.

  • Цена защиты видна честно: обычная задача B7 (страница, затем заметки, затем письмо с текстом от пользователя) на D4 и D5 требует подтверждения человека, потому что шлюз не умеет отличить её от атаки по составу вызовов. Это осознанный компромисс режима trifecta: в нём лучше спросить человека, чем промолчать.

Как читать цифры

Агент в бенчмарке не языковая модель. Это детерминированный «послушный» агент: он выполняет любые указания вида call сервер.инструмент with {json}, найденные в описаниях и результатах, как самая наивная модель. Это сделано ради воспроизводимости и нулевой стоимости. Цифры показывают, что останавливает защита при гарантированно уязвимом агенте, а не насколько уязвимы настоящие модели и как часто они поддаются таким фразам. Настоящие модели могут вести себя лучше или хуже, а атакующий может перефразировать. Подключение локальной модели вместо наивного агента сделано отдельной задачей и пока не реализовано.

Безопасность самого шлюза

  • Нулевые зависимости во время работы: только стандартная библиотека Node.

  • Лимиты на всё: строка протокола 8 МБ, аргументы, результат, число инструментов (2000) и страниц списка (50), глубина обхода схем, рейт вызовов.

  • Дашборд слушает только 127.0.0.1, принимает только GET, отдаёт страницу с CSP по nonce, а данные из журнала выводит через textContent.

  • Файл подтверждений пишется атомарно с правами 0600, а модель его не видит и не может одобрить свой вызов.

  • Журнал не содержит значений аргументов. Если писать журнал нельзя, шлюз продолжает работать и пишет об этом в stderr.

Как проверялось

  • 50 тестов: протокол и разбор строк, конфигурация (14 видов ошибок), политики, taint, очистка, подтверждения, журнал, окружение сервера; шлюз целиком на настоящих учебных серверах (пространства имён, скрытие, политики, taint в трёх режимах, подтверждение, результаты, лимиты, закрепление и rug pull, падение сервера, запросы сервера к клиенту, таймауты, stdio-режим); дашборд; бенчмарк.

  • Тест бенчмарка проверяет свойства, а не только числа: без шлюза удаются все атаки, с полной защитой ни одна, защита монотонна (остановленная атака не возвращается на более сильном уровне), ни одна обычная задача не ломается молча, а таблица в docs/benchmark.md совпадает с тем, что считает код сейчас.

  • В CI на каждый коммит: сборка со строгим TypeScript и тесты на Node 20, 22 и 24.

Ограничения

  • Только инструменты MCP и только серверы по stdio. Ресурсы, промпты, sampling и удалённые серверы по HTTP не поддерживаются.

  • Шлюз не песочница: процесс сервера выполняется с вашими правами. Он контролирует то, что проходит между агентом и сервером, но не изолирует сам сервер.

  • Правила обнаружения инъекций это эвристики по тексту, в основном английские. Перефразирование или другой язык могут их обойти. Поэтому главный упор сделан на структурные защиты (закрепление, taint, ограничения аргументов), которые не зависят от формулировки.

  • Taint-tracking работает на уровне сессии и меток, которые вы расставляете в политике. Неразмеченный инструмент не считается ни приватным, ни исходящим. Прямое перетекание определяется по общей подстроке, а пересказ или изменённый текст ей не поймать, поэтому основу составляет правило «тройки».

  • Подтверждение через citadel approve требует, чтобы человек был рядом. Для полностью автономных агентов нужен режим deny.

  • Бенчмарк синтетический и по числу сценариев небольшой: это демонстрация и регрессионный тест, а не оценка защищённости реальных систем.

Лицензия

MIT, см. LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Security gateway for MCP tool calls. Sits between your LLM client and MCP servers, enforcing per-tool policies (allow/block/approve/read-only), logging every call, and pausing dangerous operations for human approval in terminal or Slack.
    4 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A security gateway for MCP servers that enforces policy checks including role-based access, argument constraints, injection scanning, and PII redaction on both tool arguments and results, with tamper-evident audit logging.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A zero-trust security gateway for MCP tool calls, inspecting tool identity, arguments, execution decisions, and returned content before risk reaches your coding agent.
    Apache 2.0
  • A
    license
    Not graded
    quality
    D
    maintenance
    A policy-enforcing MCP gateway that intercepts all tool calls to downstream MCP servers, applying allow/deny/ask rules with human approval and audit logging for safe access to dangerous tools.
    7 npm
    MIT