Lasso MCP Gateway: щит между AI-агентами, тулами и вашими секретами?

от автора

Введение

С развитием AI-агентов и Model Context Protocol (MCP) актуальной становится проблема безопасности при работе с различными инструментами. Что если ваш AI-агент случайно прочитает конфиденциальный файл с токенами доступа и «случайно» поделится ими с вами в своем ответе, а учитывая логирование ваших запросов, он точно попадет на сервер провайдера вашего агента, а возможно еще и IDE, в которой этот агент и обитает, это создаст ряд неприятностей.

Ярким примером тулы, которая выполняет поиск по вашим локальным файлом является mcp-filesystem. Один шаг не туда и вам придется бежать за ревоком токена, а если он еще и от организации, ваши админы явно не скажут вам спасибо.

Не забываем про то, как у XAI токен просто лежал на github пару месяцев: статья

Для решения этой проблемы команда Lasso Security разработала MCP Gateway — прокси-сервер, который встает между AI-агентом и MCP-тулами, обеспечивая санитизацию чувствительной информации.

В этой статье я поделюсь результатами тестирования Lasso MCP Gateway в двух сценариях: интеграция с Cursor IDE и локальная реализация с собственным агентом на PydanticAI.

Что умеет Lasso MCP Gateway

1) Перехватывает вызовы всех MCP-инструментов перед их выполнением
2) Маскирует в basic вариации (бесплатной):

  • azure client secret

  • github tokens

  • github oauth

  • gcp api key

  • aws access token

  • jwt token

  • gitlab session cookie

  • huggingface access token

  • microsoft teams webhook

  • slack app token\

Есть интеграция с presidio и самим lasso. Позволяет логировать вызовы через xetrack

Общий принцип работы

Идея MCP-gateway заключается в том, что он становится неким прокси между агентом и тулами. То есть он подключается не просто как отдельный MCP тул, а как MCP-тул, под которым работают другие тулы. То есть любой вызов плагина по типу read_file create_file и тд будет происходит после того как mcp-gateway дал условное одобрение и провел санитизацию.

схема работы из репозитория на github

схема работы из репозитория на github

Эксперименты

Тестирование в Cursor

Настройка и установка Следуя примеру из readme.md я подключил mcp-gateway к cursor, добавил путь к логированию через xetrack. Как выглядит:

{   "mcpServers": {     "mcp-gateway": {       "command": "uvx",       "args": [         "mcp-gateway",         "--mcp-json-path",         "/home/user/.cursor/mcp.json",         "--plugin",         "basic",         "--plugin",          "xetrack"       ],       "env": {         "XETRACK_LOGS_PATH": "logs/",         "XETRACK_DB_PATH": "tracing.db"       },       "servers": {         "filesystem": {           "command": "npx",           "args": [             "-y",             "@modelcontextprotocol/server-filesystem",             "."           ]         }       }     }   } }

Эксперимент 1: Чтение файла с HuggingFace токеном

Создал файл

echo 'HF_TOKEN = "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"' > tokens.txt

в нем теперь хранится выдуманный токен из Huggingface

Следуя снова же примеру из readme.md пишу запрос

запрос в самом верху

запрос в самом верху

Cursor получил уже очищенный контекст и вернул мне <HUGGINGFACE_TOKEN>.

Подробнее:

в тулу передался параметр:

{   "path": "~/lasso-mcp/sts/tokens.txt"   }

внутри tokens.txt хранится мой выдуманный hf token

тула произвела очистку:

{ "_meta": null, "content": [ { "type": "text", "text": "HF_TOKEN = \"<HUGGINGFACE_TOKEN>\n", "annotations": null } ], "isError": false } 

затем тула вернула респанс cursor агенту и он вернул очищенный токен:

<HUGGINGFACE_TOKEN>

Эксперимент 2: Обход через контекст агента

Интересный нюанс: когда я попросил агента создать файл с кодом, передав токен непосредственно в чате, MCP Gateway не смог заблокировать эту операцию. Санитизация происходит только при чтении файлов, но не при генерации/обработке моего запроса
(что в принципе и не удивительно).

пишем явно наш ключ в диалоге

пишем явно наш ключ в диалоге
Cursor создал файл и явно вписал туда мой токен

Cursor создал файл и явно вписал туда мой токен

Когда я позже попросил прочитать созданный файл, MCP Gateway снова сработал корректно. Однако Cursor «помнил» о токене из контекста беседы и просто обновил информацию, вернув мой токен мне же обратно.

прочитал файл

прочитал файл
MCP-Gateway подчистил токен, но Cursor то помнит наш диалог

MCP-Gateway подчистил токен, но Cursor то помнит наш диалог
финальный ответ и слитый токен

финальный ответ и слитый токен

Эксперимент 3

Создаем .env файл с выдуманным ключом от OpenAI: ключ:

OPENAIKEY=sk-qwejxakdjruewhjnsvasdj

Результат работы агента с явным вызовом mcp-gateway через наш запрос:

Слитый токен

Слитый токен

В общем говоря, если ваш токен не находится в списке токенов из начала, не надейтесь, что вам повезет и он не будет слит.

Local Implementation

Тестовые данные

Для локальной реализации был создан файл с 5-ю вариациями токенов:

HF_TOKEN = "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" OPENAI_TOKEN = "sk-proj-SDASDFASDSDDSFDFSDADSdfsdfaHAJKDD5JASMDBXAHEG4123XDLKCXCDFSDFSAZXCN" JWT_TOKEN ="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik..." GITHUB_TOKEN_CLASSIC = "ghp_mS5asdaSJASHDqwDSAD4KD" GITHUB_TOKEN = "github_pat_33SDSDJKJXKCJXIHFGAdfdsfkS4333Nwqe13weqeirurururrrr"

MCP

Не забудьте установить mcp-gateway через uv/pip или используйте uvx

Для запуска MCP-Gateway ему обязательно нужен mcp.json

{     "mcpServers": {         "mcp-gateway": {             "command": "uv",             "args": [                 "run",                 "mcp-gateway",                 "-p",                 "basic",                 "-p",                 "xetrack"             ],             "env": {                 "XETRACK_DB_PATH": "tracing.db",                 "XETRACK_LOGS_PATH": "logs/"                            },             "servers": {                 "filesystem": {                     "command": "npx",                     "args": [                         "-y",                         "@modelcontextprotocol/server-filesystem",                         "."                     ]                 }             }         }     } }

Агент

Реализовал простого агента через pydantic AI, с подключением к Lasso MCP-Gateway в базовой реализации (бесплатной) и логированием через xetrack

from typing import Optional from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider from pydantic_ai.mcp import MCPServerStdio import os from dotenv import load_dotenv import asyncio   load_dotenv()   async def get_custom_openai_provider_response(     model_name: str,     query: str,     provider_url: Optional[str] = None,     system: Optional[str] = "",     api_key: Optional[str] = None, ) -> str:     """     Func to call custom open ai provider, using `provider_url` if needed     """     lasso_gateway = MCPServerStdio(         command="uv",         args=["run","mcp-gateway","--mcp-json-path", "./mcp.json","--plugin","basic", "--plugin", "xetrack"],         env={"XETRACK_DB_PATH": "tracing.db", "XETRACK_LOGS_PATH": "logs/"}     )       model = OpenAIModel(         model_name=model_name,         provider=OpenAIProvider(base_url=provider_url, api_key=api_key),     )     agent = Agent(         model=model,         retries=5,         system_prompt=system,         mcp_servers=[lasso_gateway]     )       async with agent.run_mcp_servers():       result = await agent.run(query)         return result   async def main():     test_keys = [         "HF_TOKEN",         "OPENAI_TOKEN",         "JWT_TOKEN",         "GITHUB_TOKEN_CLASSIC",         "GITHUB_TOKEN"     ]       for key in test_keys:         query = f"Use your tools to read the ./tokens.txt and return the {key}"         print(f"Testing key: {key}")         response = await get_custom_openai_provider_response(             model_name="gpt-4.1-nano-2025-04-14",             system="Use all available tools to help user with his response, be always helpful",             query=query,             api_key=os.getenv("OPENAI_API_KEY")         )         print("#############")         print(f"Response for {key}: {response}\n")         print("#############") if __name__ == "__main__":     asyncio.run(main())

результат тестирования:

HF_TOKEN = «<HUGGINGFACE_TOKEN>
OPENAI_TOKEN = «sk-proj-…»
JWT_TOKEN = «<JWT_TOKEN>
GITHUB_TOKEN_CLASSIC = «ghp_mS5asdaSJASHDqwDSAD4KD»
GITHUB_TOKEN = «github_pat_33..

Обещанный github-токен даже не был санитизирован что в классической, что в новой версии.

Что логирует xetrack

Среди полезной информации, которую сохраняет xetrack:

  • capability_name: название инструмента (например, read_file)

  • path: путь к файлу (./tokens.txt)

  • content_text: содержимое после санитизации (HF_TOKEN = "<HUGGINGFACE_TOKEN>")

  • pattern: шаблоны поиска (если применимо)

    и не только.

Важно: xetrack НЕ логирует запросы пользователя и финальные ответы агента — только вызовы MCP-серверов, которые с ним явно связаны в вашем mcp.json.

Вывод

Summary

Достаточно игрушечное решение, которое вроде бы работает на уровне mcp/tool-call и выступает прослойкой между всеми вашими mcp-тулами. Не позволяет агенту прочитать токен доступа из существующих файлов/источников, просто санитизируя ответ перед добавлением в контекст агента.

Для кого

Может помочь: в разработке, чтобы не скормить случайно агенту ключ из условного .env и не делать revoke, однако поддерживает только ограниченное число вариаций этих ключей. Бесполезен если: Вы явно отдали агенту ключ или ваш вид ключа не поддерживается mcp-gateway, e.g. OpenAIApiKey.

Что работает хорошо:

  • Простая интеграция — настройка в клиент в виде Cursor, Windsurf, VS Code, Claude-desktop и другие, а также в ваш проект с агентом под капотом.

  • Полезное логирование — xetrack предоставляет информацию о результатах работы.

  • Работает как прокси — не нужно модифицировать существующие MCP-серверы, просто перетащить их в серверы mcp-gateway

  • Санитизация — MCP Gateway маскирует почти все поддерживаемые типы токенов при чтении файлов

Что работает плохо:

  • Не защищает от контекста — если токен передан в чате, а не прочитан из файла, защита не сработает, поскольку ваш агент его запомнит.

  • Ограниченный набор паттернов — базовая версия поддерживает только ограниченные типы токенов

Lasso MCP Gateway как идея мне кажется достаточно интересным, поскольку я сам пользуюсь умными помощниками, которые иногда получают доступ к тем файлам, к которым мне не хотелось бы, особенно это актуально для IDE-агентов, которые сами могут пройтись по проекту и собрать контекст. Это не очень приятно и базовое предложение делать .gitignore не всегда работает.

Но по факту это достаточно сырое решение, которое покрывает ограниченное количество кейсов, а в тех случаях когда вам критично хранение отдельных секретов, пока что, проще сделать свое решение.


ссылка на оригинал статьи https://habr.com/ru/articles/910556/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *