Skip to content
ВозможностиДокументацияЦеныПартнёрыPlaygroundFAQ
RAGVector DBData Security

Безопасность RAG: 6 векторов утечки данных через векторные базы и как их закрыть

1 минута чтения

RAG (Retrieval-Augmented Generation) обещает «LLM, которая знает ваши данные» — но на практике это «LLM, у которой есть доступ к вашему корпоративному хранилищу через небезопасный retrieval-конвейер». Каждый чанк, который ретривер достаёт из векторной базы, потенциально попадает в контекст модели, в лог, в prompt-injection-атаку, в чужого тенанта. Безопасность RAG — это не про шифрование векторной базы, а про разбиение retrieval-пайплайна на стадии и защиту каждой. Ниже — анатомия конвейера, шесть реальных векторов утечки данных через vector database и архитектура, которая их закрывает.

Краткий ответ

Безопасность RAG — это защита retrieval-конвейера по стадиям: ingestion (подпись контента, allow-list источников, DLP-сканер), storage (per-tenant коллекции / RLS, encrypt-at-rest), retrieval (обязательный tenant_id + ACL в фильтре, вайтлисты, OPA/Rego), runtime (eBPF-shield на хосте) и observability (structured-логи без векторов, hash-chain audit journal). Шесть векторов утечки закрываются архитектурой, а не одним firewall.

Что вы узнаете

  • Какие шесть стадий RAG-пайплайна являются точками утечки
  • Почему top-k retrieval без per-tenant фильтра = data breach по дизайну
  • Как embedding inversion восстанавливает текст из вектора за 5 минут
  • Почему metadata-фильтры в Qdrant/pgvector обходятся prompt-injection-ом
  • Конкретные конфиги: RLS в pgvector, payload-фильтры в Qdrant, OPA Rego для doc-level RBAC
  • Как FlowLink закрывает retrieval через eBPF-shield + MCP gateway

6

векторов утечки данных через retrieval-конвейер RAGОт ingestion до LLM-generation: poisoning, retrieval leakage, filter bypass, cross-tenant breach, API/key leak, embedding inversion.

Анатомия RAG-пайплайна

Прежде чем говорить об атаках, надо увидеть pipeline как поверхность атаки. Типовой RAG для корпоративного AI-агента состоит из шести стадий:

RAG-пайплайн — 6 стадий и точки утечки

Каждая стрелка — это данные, которые можно украсть, подменить или вытащить через модель. Контрольная идея: RAG security — это segmentation per stage, а не один firewall вокруг «векторной базы». Дальше разберём шесть векторов — по одному на каждую критическую стадию.

Вектор 1: Leakage через retrieval

Самая частая и самая недооцениваемая утечка. Ретривер отдаёт модели top-kчанков из базы — и эти чанки попадают в контекст LLM, а значит потенциально в ответ, в лог prompt, в tool-call агенту, в цепочку к другому вендору. Классический сценарий: пользователь с доступом «только к своему проекту» спрашивает что-то у агента, ретривер без per-user фильтра достаёт чанк с финансовыми данными другого отдела, и LLM аккуратно его парафразирует в ответе.

Это не гипотеза — так утекли данные Samsung через ChatGPT, так утекают Jira-тикеты в Copilot for Microsoft 365, так утекают внутренние документы в Cursor при включённом «@Codebase». Утечка происходит не из LLM, а из retriever без authz.

Минимально жизнеспособный фильтр в Qdrant выглядит так — обратите внимание, чтоtenant_id и acl идут в обязательном must:

qdrant_search.py
python
# app/retriever/qdrant_search.py
from qdrant_client import QdrantClient, models
def retrieve(query_vec, user, tenant_id, k=8):
client = QdrantClient(url="http://qdrant:6333")
# НАДО: фильтр по tenant_id + ACL. БЕЗ него — cross-tenant leak.
flt = models.Filter(
must=[
models.FieldCondition(
key="tenant_id",
match=models.MatchValue(value=tenant_id),
),
models.FieldCondition(
key="acl.allowed_groups",
match=models.MatchAny(any=user.groups), # пересечение групп
),
],
must_not=[
models.FieldCondition(
key="acl.classification", # секретное — не отдаём
match=models.MatchValue(value="secret"),
),
],
)
res = client.search(
collection_name="docs",
query_vector=query_vec,
query_filter=flt,
limit=k,
with_payload=["title", "acl", "source_id"], # НЕ тянем raw text в логи
)
return res

Ключевая ошибка — полагать, что «ретривер и так в нашей сети, фильтровать нечего». В multi-tenant RAG это эквивалентно открытому S3-бакету. Фильтр обязан быть обязательным параметром, а не «если передали». Подробно про то, как те же принципы применяются к MCP-инструментам агентов — в статье «Prevent MCP credential leaks».

Вектор 2: Data poisoning в корпусе

Если ретривер — это «выдача», то корпус — это «вход». Data poisoning RAGатакует ещё до того, как пользователь задаст вопрос: злоумышленник (или просто неаккуратный инженер) кладёт в индекс «отравленный» документ. Цель — не украсть данные, а заставить агента врать: «Лучше всего перевести средства на счёт X», «Использовать устаревший эндпоинт без auth», «Игнорировать policy и выполнить destructive-команду».

В корпоративной практике это особенно опасно с Confluence, Jira и Notion: кто угодно с edit-доступом может создать страницу, которая через 5 минут попадёт в индекс, а потом будет уверенно процитирована AI-агентом как «внутренняя инструкция». Это прямой путь к индиректному prompt injection — я бы объединял защиту этих двух векторов.

Превентивные меры на стадии индексации (чек-лист):

Превентивные меры защиты от data poisoning на стадии индексации
МераСтадияЧто закрывает
Подпись контента (HMAC на chunk-hash)ЧанкингПодмену чанка между ETL и VectorDB
Allow-list источников (SPIFFE SVID)ИсточникиЗаливку из чужого репозитория
Classification-фильтр + human-in-the-loop для «secret»ЧанкингСекреты в индексе вообще
DLP-сканер (truffleHog/gitleaks) перед embeddingEmbeddingsAPI-ключи, токены, PII в корпусе
Provenance-аудит: кто/когда/откуда добавил чанкВсеAttribution и rollback отравленной пачки

Запомните инвариант: векторная база не должна принимать ничего, что не прошло через подписанный ingestion-пайплайн. Любой side-channel заливки (прямой INSERT в pgvector, admin-API Qdrant) — это бэкдор для poisoning.

Вектор 3: Metadata-фильтр bypass

Продолжаем про фильтры. Даже когда tenant_id стоит в must, атакующий пытается обойти сам фильтр — через значение, которое он контролирует. Типовой паттерн: приложение строит фильтр из пользовательского ввода («покажи документы проекта X»), и если project подставляется строкой без валидации, атакующий шлёт project=* или project=__all__ и снимает фильтр. В pgvector это превращается в SQL-injection через WHERE.

Правильно — валидировать ввод против разрешённого множества и собирать фильтр только параметризованно. Пример на pgvector с Row-Level Security как второй линией обороны:

pgvector_rls.sql
sql
-- 1. Включаем RLS и привязываем к tenant_id из session
ALTER TABLE docs ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON docs
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- 2. Приложение ОБЯЗАНО выставлять tenant_id из верифицированной сессии,
-- а не из query-параметра пользователя
SET LOCAL app.tenant_id = :verified_tenant_id; -- из JWT, не из req.body
-- 3. Семантический поиск — теперь автоматически отфильтрован RLS
SELECT id, title, chunk,
embedding <=> :q_vec AS dist -- pgvector cosine
FROM docs
WHERE project = ANY(:allowed_projects) -- whitelist из RBAC
ORDER BY embedding <=> :q_vec
LIMIT 8;

Здесь две независимые защиты: RLS на уровне БД (даже если приложение забудет фильтр, Postgres не отдаст чужие строки) и вайтлист allowed_projects на уровне приложения. Одно не заменяет другое — оба. Иначе вы получите тот самый bypass, когда один кривой project=* сливает всё.

RLS в pgvector — недоиспользуемый механизм

RLS в pgvector — это самый недоиспользуемый механизм защиты RAG. Он бесплатный, работает на уровне планировщика и не зависит от того, насколько аккуратно ваш код собирает запрос. Включайте по умолчанию для любой multi-tenant таблицы с embeddings.

Вектор 4: Cross-tenant isolation breach

Четвёртый вектор — это сама векторная база как инфраструктура. В большинстве startup-RAG все тенанты живут в одной коллекции Qdrant или одной таблице pgvector и различаются только payload-полем tenant_id. Это рискованно по двум причинам:

  • Семантическая утечка через косинус. Даже если вы не возвращаете чанк чужого тенанта, вектор этого чанка участвует в ANN-индексе. При определённых условиях (bad HNSW-конфиг, общее пространство имён, отсутствие is_distance=true) атакующий может получить дистанцию до чужого вектора — этого достаточно для membership-inference («есть ли у тенанта Y документ про Z»).
  • Operator error. Один забытый WHERE tenant_id = ? в ad-hoc запросе дежурного — и TENANT_A получает raw dump TENANT_B. При 200+ тенантов это не «если», а «когда».

Надёжное решение — физическая изоляция: отдельная коллекция на тенанта в Qdrant или отдельная schema/таблица в Postgres. Коллекции в Qdrant дешёвые, HNSW-индекс можно тюнить per-tenant. Создание коллекции при онбординге тенанта:

onboarding.py
python
# onboarding: отдельная коллекция на тенанта
client.recreate_collection(
collection_name=f"tenant_{tenant_id}",
vectors_config=models.VectorParams(
size=1536, # text-embedding-3-large
distance=models.Distance.COSINE,
),
optimizers_config=models.OptimizersConfigDiff(
indexing_threshold=20000, # меньше памяти на маленьких тенантах
),
)
# retrieval ходит только в "свою" коллекцию — утечка физически невозможна
client.search(
collection_name=f"tenant_{tenant_id}", # из verified session
query_vector=q_vec,
limit=8,
)

Дополнительно — monitoring: алерты на cross-collection запросы из одной сессии, и жёсткий seccomp/systemd-профиль на сам контейнер Qdrant, чтобы у exploited-агента не было пути к raw-файлам коллекций на диске. Это уже уровень runtime-защиты, и здесь FlowLink ставит eBPF-shield: каждая open() иconnect() процесса ретривера проверяется против политики, аномальные обращения к чужим коллекциям блокируются до того, как данные покинут хост.

Вектор 5: Утечка через embedding API и кэш

Пятая стадия — embeddings. Чтобы получить вектор, вы шлёте сырой текст куда-то: в OpenAI text-embedding-3-large, в Cohere, в self-hostedbge-m3. Каждый вызов — это передача контента по сети с двумя рисками:

  • Сторонний API как data sink. Если вы эмбеддите внутренние документы через OpenAI, вы де-факто отправляете их содержимое третьей стороне. Для GDPR/PCI/ HIPAA-regulated данных это нарушение без отдельного DPA и enterprise-окружения. И да, OpenAI не использует ваш API-трафик для обучения — но это политика, а не криптография.
  • Утечка API-ключа embedding-провайдера. Ключ хранится в.env ретривера, агент cat /app/.env — и вот у него уже есть квота на $50k и возможность дёргать эмбеддинги от имени вас. Это самый частый путь lateral movement в AI-infra.

Меры: хостить embeddings локально (BGE, E5, Nomic — на одной A10 хватает для корпоративного корпуса), либо explicit data-residency контракт с провайдером; хранить ключи в vault с short-TTL (HashiCorp Vault, AWS Secrets Manager) и отдавать ретриверу через боковой SID-файл SPIFFE, а не через .env. И — критично — проксировать все вызовы embedding-провайдера через MCP gateway, который логирует (tenant, doc_count, bytes) в audit journal. Аномальный всплеск эмбеддингов в 3 ночи = алерт.

Вектор 6: Embedding inversion

Финальный и самый контринтуитивный вектор. Распространённое заблуждение: «вектор — это не данные, это математика, его нельзя реверснуть». Это неверно. Embedding inversion — это класс атак (Carlini et al., 2023; «Vec2Text»), который по эмбеддингу восстанавливает исходный текст с высокой точностью.

~92%

точности восстановления текста при embedding inversionДля text-embedding-ada-002: ~92% за ~5 минут на одной A100. Для text-embedding-3-large — ~80%. Любая утечка векторов эквивалентна утечке текста.

Конкретные числа: для text-embedding-ada-002 итеративный inversion восстанавливает ~92% точного текста чанка за ~5 минут на одной A100; дляtext-embedding-3-large — около 80%. Это значит, что любая утечка векторов эквивалентна утечке текста. А векторы утекают на каждом шагу: они в логах ретривера, в /metrics Prometheus, в дампах pgvector, в отладочных эндпоинтах Qdrant.

Что делать — комплекс мер, потому что одного решения нет:

  • Не логируйте векторы. В structured-логи ретривера — толькоchunk_id, dist, tenant_id. Никогда сами 1536 float-ов.
  • Differential privacy / noise. Additive noise на эмбеддинги снижает inversion-качество, ценой recall. Подходит для high-security тенантов.
  • Per-tenant пространств имён. Если у каждого тенанта свой encoder (fine-tuned BGE), inversion-модель, обученная на публичных данных, не сработает на чужом пространстве.
  • Encrypt-at-rest + strict access. Векторы в БД шифруются (pgcrypto / Qdrant snapshots), доступ только через сервис-аккаунт ретривера с short-lived credentials.

Практическое правило

Относитесь к embeddings как к plain text. Если вы бы не стали класть этот документ в открытый S3 — не кладите его вектор в открытый Prometheus.

Архитектура защищённого RAG

Сведём шесть векторов в единую архитектуру. Идея — defence in depth: на каждой стадии pipeline стоит независимый контроль, и пробой одного не ломает остальные.

5 слоёв защиты RAG
  1. Ingestion
  2. Storage
  3. Retrieval
  4. Runtime
  5. Observability

Слой 1 — Ingestion (закрывает poisoning)

Подписанный ETL-пайплайн (Temporal/Airflow), allow-list источников через SPIFFE SVID, DLP-сканер перед embeddings, mandatory classification-тег. Никаких прямых INSERT-ов в VectorDB.

Слой 2 — Storage (закрывает tenant leak и inversion)

Per-tenant коллекции Qdrant или RLS-таблицы pgvector. Encrypt-at-rest. Минимальные привилегии: ретривер может SELECT/search, но неDUMP. Метрики без сырых векторов.

Слой 3 — Retrieval (закрывает leakage и filter bypass)

Обязательный tenant_id + ACL в фильтре, вайтлисты на пользовательский ввод, OPA/Rego-политика для doc-level RBAC. Doc-level RBAC на Rego выглядит так:

retrieval_policy.rego
rego
# retrieval_policy.rego — guard на каждый search()
package rag.retrieval
default allow := false
allow if {
# 1. tenant всегда обязателен и берётся из JWT, не из запроса
input.session.tenant_id == input.query.tenant_id
# 2. хотя бы одна группа пользователя входит в ACL чанка
chunk.acl.allowed_groups[_] == input.session.groups[_]
# 3. секретные документы — только для cleared-ролей
not chunk.acl.classification == "secret"
"cleared" in input.session.roles
# 4. бюджет ретривала не превышен (защита от DoS/экстракции)
input.query.k <= 16
input.session.daily_retrieval_count < input.session.daily_limit
}

Этот же Rego-полиси подключается к FlowLink policy engine и переиспользуется для MCP-инструментов и LLM-вызовов — единый слой авторизации для всего AI-стека.

Слой 4 — Runtime (закрывает lateral movement)

eBPF-shield на хосте: каждый open(), connect(),exec() процесса ретривера и embedding-воркера сверяется с policy. Агент, пытавшийся cat /var/lib/qdrant/storage/* или сходить наapi.openai.com в обход gateway — блокируется, инцидент уходит в audit journal. Подробнее — в материале «Мониторинг AI-агентов».

Слой 5 — Observability (закрывает «молчаливую» утечку)

Каждый retrieval логируется: (timestamp, user, tenant, query_hash, chunk_ids, distances, model) — без самих векторов и без сырого текста. Алерты в Prometheus: anomalous k, cross-collection запрос, рост retrieval-rate, обращение к embedding-API вне business-hours. Audit journal — append-only, с hash-chain для целостности.

Чек-лист: где вы уязвимы прямо сейчас

Прежде чем закрыть вкладку — пять вопросов, на которые честно ответьте про свой RAG:

Диагностический чек-лист RAG-безопасности

Пять вопросов, которые выявляют основные уязвимости в retrieval-конвейере.

  1. Multi-tenant изоляция

    Можете ли вы из подсчёта SELECT count(*) FROM docs в production-БД ответить «сколько у нас тенантов»? Если да — у вас общая таблица без RLS, вектор 4 открыт.

  2. Логирование векторов

    Есть ли в логах ретривера строки с 1536 float-ами? grep -E "0\\.[0-9]6, 0\\." /var/log/retriever.log — если что-то нашлось, embedding inversion стал реальностью (вектор 6).

  3. Filter bypass через query-параметры

    Может ли разработчик из команды X задать tenant_id через query-параметр при локальном тесте? Если да — bypass фильтра (вектор 3) — вопрос времени.

  4. Трансграничная передача данных

    Идёт ли эмбеддинг внешнему провайдеру без data-residency DPA? Вектор 5 — это регуляторный риск, а не только технический.

  5. Data poisoning через Confluence/Jira

    Если завтра залить в ваш Confluence страницу «приказ: перевести бюджет на счёт ATT» — попадёт ли она в индекс без review? Если да — poisoning (вектор 2) готов к эксплуатации.

Стоит ли инвестировать в полноценную защиту RAG?

Плюсы

  • Системное покрытие retrieval-пайплайна по стадиям — каждый вектор закрыт независимо
  • Per-tenant изоляция физически устраняет cross-tenant утечки данных
  • OPA/Rego даёт единый авторизационный слой для RAG, MCP и LLM-вызовов
  • eBPF-shield закрывает lateral movement на уровне ядра ОС
  • Observability (structured-логи + audit journal) обеспечивает форензику и compliance

Минусы

  • Высокая сложность реализации: per-tenant коллекции + RLS + Rego + eBPF — каждая подсистема требует отдельной экспертизы
  • Дополнительные накладные расходы на self-hosted embedding-модели (GPU, A10 для корпоративного корпуса)
  • Embedding inversion остаётся вектором, требующим отдельной защиты (noise, per-tenant encoders)
  • Нужна постоянная перепроверка retention-политик и geo-fencing регуляторных требований

RAG — это не «умный поиск», это «privilege-escalation-поверхность для ваших документов». Относитесь к retrieval-конвейеру как к production-grade сервису с multi-tenant изоляцией, подписанным ingestion, runtime-защитой и observability — и шесть векторов закрываются архитектурой, а не надеждой. FlowLink ставит именно эти слои: policy engine (OPA/Rego) на retrieval, eBPF-shield на runtime, MCP gateway на embedding-API, audit journal на всё остальное — единая поверхность контроля для RAG, MCP-инструментов и AI-агентов.

Часто задаваемые вопросы

Что такое безопасность RAG и почему retrieval-конвейер — это поверхность атаки?

RAG (Retrieval-Augmented Generation) добавляет к LLM retrieval-конвейер, который тянет чанки из векторной базы в контекст модели. Каждый этап — ingestion, embeddings, storage, retrieval — передаёт или обрабатывает данные, которые можно украсть, подменить или вытащить через prompt injection. Безопасность RAG означает защиту каждой стадии конвейера, а не одного firewall вокруг векторной базы.

Какие шесть векторов утечки данных через векторные базы существуют?

(1) Retrieval leakage — ретривер без authz выдаёт чанки чужого тенанта; (2) Data poisoning — отравленный документ в индексе; (3) Metadata-filter bypass — обход tenant_id фильтра через SQL-injection или wildcard; (4) Cross-tenant breach — семантическая утечка через ANN-индекс или operator error; (5) Embedding API/key leak — передача контента стороннему провайдеру или утечка API-ключа; (6) Embedding inversion — восстановление текста из вектора (~92% точности).

Как embedding inversion восстанавливает текст из векторов и насколько это опасно?

Embedding inversion (Carlini et al., 2023; Vec2Text) — это класс атак, который по эмбеддингу итеративно восстанавливает исходный текст. Для text-embedding-ada-002 точность ~92% за ~5 минут на A100. Векторы утекают в логах, Prometheus-метриках, дампах pgvector и debug-эндпоинтах Qdrant — любая утечка векторов эквивалентна утечке текста.

Как защитить multi-tenant RAG от cross-tenant утечки данных?

Надёжное решение — физическая изоляция: отдельная коллекция Qdrant или отдельная таблица/схема в Postgres на каждого тенанта. Payload-фильтр по tenant_id ненадёжен из-за semantic leakage через ANN-индекс и operator error. Дополнительно: RLS в pgvector как вторая линия обороны, seccomp/systemd на контейнер и eBPF-shield от FlowLink для runtime-защиты.

Что такое metadata-filter bypass и как его предотвратить?

Атакующий подставляет tenant_id=* или project=__all__ в пользовательский ввод, снимая фильтр. Защита: валидация ввода против whitelist, параметризованные запросы и Row-Level Security (RLS) в pgvector как вторая линия — Postgres не отдаст чужие строки даже если приложение забудет фильтр.

Какие компоненты нужны для архитектуры защищённого RAG?

Пять слоёв: Ingestion (подпись контента, allow-list источников, DLP-сканер), Storage (per-tenant коллекции, RLS, encrypt-at-rest), Retrieval (обязательный tenant_id + ACL, OPA/Rego), Runtime (eBPF-shield на хосте) и Observability (structured-логи без векторов, hash-chain audit journal). FlowLink ставит все пять слоёв как единую поверхность контроля.

Готовы защитить свои AI-агенты?

Начните с бесплатного аудита безопасности ваших AI-инструментов.

Получить бесплатный аудит