Test zatruwania pamięci w laboratorium red-team: skażanie korpusów RAG i baz wektorowych oraz wykrywanie skażonego wyszukiwania
Jak w laboratorium red-team przeprowadzić test zatruwania pamięci: zasiać skażone dokumenty w korpusie RAG i bazie wektorowej, a potem wykryć skażone wyszukiwanie.
Test zatruwania pamięci w laboratorium red-team: skażanie korpusów RAG i baz wektorowych oraz wykrywanie skażonego wyszukiwania
Krótka odpowiedź: na czym polega test zatruwania pamięci w laboratorium
Test zatruwania pamięci to kontrolowany eksperyment, w którym sam — jako red-team — wstrzykujesz spreparowane dokumenty do korpusu RAG i bazy wektorowej agenta, a następnie sprawdzasz, czy i kiedy trafiają one do kontekstu modelu oraz czy zmieniają jego odpowiedzi. Sednem nie jest pytanie „czy da się zatruć bazę“ — bo prawie zawsze się da — lecz dwa inne: ile skażonych fragmentów wystarczy, by przebić się do wyników wyszukiwania na realne zapytanie, i czy Twoja warstwa wykrywania w ogóle to zauważy, zanim agent zacznie działać na podstawie podstawionej treści.
Cały scenariusz układa się w trzy kroki: zasiewasz skażone wpisy (z osadzeniami albo bez), wymuszasz pobranie ich realistycznym zapytaniem, a potem wykrywasz skażone wyszukiwanie po pochodzeniu fragmentu, jego anomalnym osadzeniu lub niespójności z resztą korpusu. To jedna ze szprych szerszej praktyki red-team frameworków dla agentów AI. To laboratorium zatruwania RAG, nie produkcja — wszystko dzieje się na odizolowanym, jednorazowym zbiorze danych, do którego masz pełne prawa.
OWASP w Top 10 for LLM Applications 2025 opisuje tę klasę zagrożeń osobno jako LLM08: Vector and Embedding Weaknesses (słabości wektorów i osadzeń). Dokument wprost wymienia wstrzykiwanie szkodliwej treści przez korpus RAG i manipulację osadzeniami jako wektory ataku — czyli dokładnie to, co odtwarzasz w warunkach laboratoryjnych.
Czym różni się zatruwanie pamięci od zwykłego prompt injection?
Zacznijmy od rozróżnienia, bo bez niego cały test celuje w złą warstwę. Klasyczne, bezpośrednie prompt injection działa w obrębie jednej sesji: napastnik wpływa na zachowanie modelu tu i teraz, w bieżącej rozmowie. Gdy sesja się kończy, kończy się i efekt.
Zatruwanie pamięci jest trwałe. Napastnik nie rozmawia z modelem — zapisuje spreparowaną treść do zasobu, z którego agent będzie czerpać w przyszłości: do bazy wektorowej zasilającej RAG albo do trwałej pamięci agenta (notatek, podsumowań, „wspomnień“ między sesjami). Przy każdym kolejnym zapytaniu, które trafi w ten fragment, agent pobiera go jako rzekomo wiarygodny kontekst i działa zgodnie z nim — bez dalszego udziału napastnika. To różnica między pchnięciem a podłożeniem miny.
Dlatego test trzeba prowadzić ponad granicą jednej sesji. Zasiewasz w jednym przejściu, a skutek mierzysz w zupełnie innym — najlepiej w nowej, „czystej“ sesji, która nie wie nic o zasiewie. Jeśli Twoja uprząż testowa restartuje wszystko między próbami, łatwo przegapisz właśnie tę trwałość, która czyni atak groźnym.
Jak zbudować izolowane laboratorium zatruwania RAG?
Laboratorium musi być jednorazowe i odcięte od czegokolwiek produkcyjnego — to nie jest opcja, lecz warunek bezpiecznego eksperymentu. Minimalny zestaw wygląda tak:
- Korpus bazowy — kilkaset do kilku tysięcy „czystych“ dokumentów na zawężony temat (np. wewnętrzna baza wiedzy o jednym produkcie). Im węższa dziedzina, tym łatwiej zobaczysz, że skażony fragment odstaje.
- Potok wczytywania — ten sam, który masz na produkcji: dzielenie na fragmenty (chunking), ekstrakcja tekstu, model osadzeń, zapis do bazy wektorowej. Test ma wartość tylko wtedy, gdy odwzorowuje realny ciąg kroków, łącznie z jego słabymi punktami.
- Baza wektorowa — lokalna instancja tego, czego używasz (Qdrant, Weaviate, pgvector, Chroma). Trzymaj ją w kontenerze, który po teście kasujesz w całości.
- Agent / aplikacja RAG — cienka warstwa pobierająca top-k fragmentów i wklejająca je do promptu. Bez niej zmierzysz tylko wyszukiwanie, a nie wpływ na zachowanie modelu.
- Dziennik zdarzeń — log każdego pobrania: zapytanie, identyfikatory zwróconych fragmentów, ich odległości w przestrzeni wektorowej, finalny prompt i odpowiedź. To z tego dziennika powstaje całe wykrywanie.
Złota zasada: dane zasiewu trzymaj poza zbiorem prawdziwych dokumentów aż do momentu próby i oznaczaj je tak, byś po teście umiał co do jednego usunąć każdy skażony wpis. Laboratorium, którego nie potrafisz wyczyścić, samo staje się zagrożeniem.
Jak zasiać skażony korpus i bazę wektorową?
Atak na bazę wektorową ma kilka wariantów i każdy bada inną słabość potoku. Warto przejść je po kolei, bo bronią się różnymi mechanizmami.
Zasiew przez treść (najprostszy). Podkładasz dokument, który wygląda jak zwykły wpis, ale niesie ukrytą instrukcję — czyli pośrednie wstrzyknięcie polecenia — albo fałszywy „fakt“. Klasyczny trik z praktyki to tekst niewidoczny dla człowieka — biała czcionka na białym tle, znikomy rozmiar, treść w metadanych albo w warstwie tekstowej PDF pod obrazem. Ekstrakcja wciąga go jak każdy inny tekst, a recenzent przeglądający dokument oczami niczego nie zauważa. To podejście testuje przede wszystkim Twój potok wczytywania i higienę ekstrakcji.
Zasiew pod zapytanie (sterowany). Tu nie liczysz na przypadek — preparujesz fragment tak, by pobierał się dokładnie na zapytania, które Cię interesują. Nasycasz go słownictwem ofiary („polityka zwrotów“, „procedura eskalacji“, nazwa produktu), żeby jego osadzenie wylądowało blisko realnych pytań użytkowników. To bada selektywność wyszukiwania: czy jeden dobrze dobrany fragment potrafi wskoczyć do top-k na konkretne, wąskie zapytanie.
Manipulacja osadzeniem (najgłębszy). Jeśli potok pozwala podać gotowy wektor (a nie liczy go zawsze sam z tekstu), możesz zapisać wpis, którego osadzenie celowo leży blisko docelowego rejonu przestrzeni, choć jego widoczny tekst wygląda nieszkodliwie. To rozjeżdża treść i wektor — i jest jednym z trudniejszych wariantów do wykrycia samym przeglądem tekstu.
Zatruwanie progu objętości. Powtórz ten sam fałszywy „fakt“ w wielu nieco różnych fragmentach. Sprawdzasz, ile kopii trzeba, by zaczęły dominować top-k i przegłosowywać prawdziwą treść. To daje twardą liczbę, której potem bronisz po stronie obrony: „przy ilu skażonych fragmentach pękamy“.
Bezpieczeństwo zasiewu: każdy wstrzyknięty „fakt“ musi być oczywiście fałszywy i nieszkodliwy poza laboratorium (np. wymyślony kod rabatowy, fikcyjny adres). Nigdy nie zasiewaj treści, która po przypadkowym wycieku do prawdziwego systemu mogłaby zaszkodzić.
Jak wymusić pobranie i zmierzyć, że atak zadziałał?
Sam zasiew niczego nie dowodzi — fragment musi zostać pobrany i wpłynąć na odpowiedź. Dlatego po zasianiu odpalasz zestaw realistycznych zapytań w nowej sesji i mierzysz dwa progi.
Pierwszy próg to trafienie do wyszukiwania: czy skażony fragment w ogóle znalazł się w top-k zwróconych wyników. Drugi, ważniejszy, to wpływ na zachowanie: czy odpowiedź agenta zmieniła się zgodnie z intencją zasiewu — podała fałszywy fakt, wykonała podstawioną instrukcję, pominęła krok zatwierdzenia. Można pobrać skażony fragment, a mimo to model go zignoruje; i odwrotnie — jeden krótki fragment potrafi przeważyć dziesięć poprawnych.
Dobre metryki testu to: odsetek pobrań (na ilu zapytaniach skażony fragment wszedł do top-k), odsetek wpływu (na ilu pobraniach realnie zmienił odpowiedź) oraz próg objętości (minimalna liczba skażonych fragmentów potrzebna do przejęcia odpowiedzi na dane zapytanie). Te trzy liczby zamieniają mgliste „da się zatruć“ w konkretny budżet ryzyka, którym da się sterować po stronie obrony.
Jak wykrywać skażone wyszukiwanie?
Tu zaczyna się część, która ma realnie chronić produkcję: wykrywanie skażonego wyszukiwania. Najskuteczniej działa kilka niezależnych sygnałów naraz, bo każdy z osobna da się obejść.
Pochodzenie fragmentu (najmocniejszy sygnał). Każdy wpis w bazie wektorowej oznaczaj metadanymi: skąd pochodzi, kto i kiedy go dodał, jaką ścieżką wczytywania. W teście fragment dodany kanałem niezaufanym (np. dokument przesłany przez użytkownika zewnętrznego) jest podejrzany z definicji. Jeśli odpowiedź agenta wynikła z fragmentu o słabym pochodzeniu, masz punkt zaczepienia, by ją wstrzymać albo zaalarmować — zanim agent zacznie działać.
Anomalia osadzenia. Skażone wpisy, zwłaszcza te sterowane pod zapytanie albo z manipulowanym wektorem, często odstają geometrycznie: leżą nienaturalnie blisko siebie (powtórzenia) albo nienaturalnie blisko wielu niespokrewnionych zapytań naraz. Wykrywanie odstających (outlier detection) w przestrzeni wektorowej oraz wykres odległości w top-k wyłapują takie skupiska.
Niespójność z korpusem. Jeśli pobrany fragment twierdzi coś, czemu przeczy reszta zwróconych wyników (np. inny kod rabatowy niż dziesięć pozostałych fragmentów), to sygnał ostrzegawczy. Drugi, lekki model albo prosta reguła zgodności potrafi taką sprzeczność oznaczyć.
Regresja na znanym ataku. Gdy raz potwierdzisz udane zatruwanie, zamień je w stały test regresyjny w uprzęży. Każda zmiana modelu osadzeń, progu top-k czy potoku wczytywania ma od razu pokazać, czy luka znów się otworzyła.
| Wektor zasiewu | Co bada | Najskuteczniejsze wykrycie |
|---|---|---|
| Ukryta treść (biały tekst, PDF) | Higienę ekstrakcji i wczytywania | Skan wejścia, sanityzacja tekstu i metadanych |
| Fragment pod zapytanie | Selektywność wyszukiwania | Anomalia osadzenia + pochodzenie |
| Manipulacja wektora | Rozjazd treść–osadzenie | Przeliczanie osadzeń po stronie serwera, outlier detection |
| Próg objętości | Odporność na przegłosowanie | Deduplikacja, limit fragmentów z jednego źródła, kontrola niespójności |
Jakich narzędzi użyć do testu zatruwania RAG?
Nie wszystko trzeba pisać od zera, ale żadne narzędzie nie zrobi za Ciebie całości — bo zatruwanie pamięci atakuje warstwę pobierania, której skanery promptów często nie dotykają.
Garak (skaner podatności LLM od NVIDIA) ma gotowe sondy na jailbreaki, wstrzyknięcia i wyciek danych. Działa świetnie na sam model, ale jeśli kontekst pochodzi z bazy wektorowej, Garak domyślnie nie sprawdzi, czy da się ten kontekst zatruć — to nadal musisz zorganizować po stronie korpusu.
PyRIT (od Microsoftu) nadaje się tam, gdzie liczy się wielokrokowość: stopniowa eskalacja, scenariusze rozłożone na kilka tur. Przydaje się, gdy zatrucie pamięci ujawnia się dopiero po serii zapytań, a nie w pojedynczym strzale.
Promptfoo traktuje potoki RAG, agentów wielokrokowych i przepływy z narzędziami jako pełnoprawne cele i ma dedykowane wtyczki m.in. pod pośrednie wstrzyknięcie przez pobraną treść oraz zatruwanie pamięci między turami. Jego mocna strona to zamiana potwierdzonego ataku w test regresyjny, który wyłapie, że aktualizacja modelu lub promptu znów otworzyła dziurę.
Realny układ to warstwy: szybki szeroki skan (Garak/Promptfoo), potem preset zgodny z OWASP Agentic, a na końcu głębsza, wielokrokowa kampania (PyRIT) na potwierdzonych słabych punktach. Sam zasiew korpusu i bazy wektorowej zwykle dopisujesz własnym skryptem — to kilkanaście linijek wokół Twojego potoku wczytywania.
Jak czytać wyniki, żeby nie oszukać samego siebie?
Najczęstszy błąd to mylenie „pobrania“ z „wpływem“. Skażony fragment w top-k to dopiero połowa drogi — dopóki nie zmienił odpowiedzi, atak jest tylko potencjalny. Raportuj oba progi osobno, bo myli je nawet doświadczony zespół.
Drugi błąd to testowanie w tej samej sesji, w której zasiewałeś. Trwałość to istota zatruwania pamięci, więc skutek mierz w świeżej sesji, która nie zna zasiewu. Trzeci błąd to korpus zbyt mały albo zbyt jednorodny — w pięciu dokumentach wszystko wpada przy jednym wstrzyknięciu i wynik niczego nie mówi o produkcji. Skaluj korpus do rzędu wielkości, w jakim realnie pracujesz.
I na koniec higiena: po każdym przebiegu skasuj całą bazę wektorową i odtwórz ją z czystego korpusu. Skażone osadzenia mają tę właściwość, że zostają — a baza, która między testami gromadzi pozostałości po zasiewie, da Ci wyniki, których nie umiesz wyjaśnić.
Ten artykuł jest częścią obszaru badawczego „Red-teaming i ewaluacje“ portalu secagentlabs i rozwija mechanikę opisaną w analizie zatruwania pamięci i kontekstu agentów AI. Wszystkie opisane techniki przeznaczone są wyłącznie do testów na własnych, odizolowanych systemach.
Najczęstsze pytania
Czym jest test zatruwania pamięci agenta AI?
To kontrolowany eksperyment red-team, w którym sam wstrzykujesz spreparowane dokumenty do korpusu RAG i bazy wektorowej agenta, a potem sprawdzasz, czy trafiają do kontekstu modelu i czy zmieniają jego odpowiedzi. Cel to nie samo potwierdzenie, że da się zatruć bazę, lecz zmierzenie, ile skażonych fragmentów wystarczy do przejęcia wyników wyszukiwania i czy warstwa wykrywania to wychwyci, zanim agent zacznie działać na podstawie podstawionej treści.
Czym zatruwanie pamięci różni się od zwykłego prompt injection?
Prompt injection działa w obrębie jednej sesji i kończy się wraz z nią. Zatruwanie pamięci jest trwałe: napastnik nie rozmawia z modelem, lecz zapisuje fałszywą treść do bazy wektorowej lub trwałej pamięci agenta. Przy każdym kolejnym zapytaniu, które trafi w ten fragment, agent pobiera go jako wiarygodny kontekst i działa zgodnie z nim, bez dalszego udziału napastnika. Dlatego skutek trzeba mierzyć w nowej sesji, która nie zna zasiewu.
Jak zbudować bezpieczne laboratorium zatruwania RAG?
Użyj jednorazowego, odciętego od produkcji zestawu: wąski korpus bazowy, ten sam potok wczytywania co na produkcji, lokalna baza wektorowa w kontenerze (Qdrant, Weaviate, pgvector, Chroma), cienka aplikacja RAG i dziennik każdego pobrania. Dane zasiewu trzymaj poza prawdziwymi dokumentami aż do próby i oznaczaj je tak, by po teście usunąć co do jednego skażony wpis. Po każdym przebiegu kasuj całą bazę i odtwarzaj ją z czystego korpusu.
Ile skażonych dokumentów wystarczy, żeby zatruć wyszukiwanie RAG?
Nie ma jednej liczby — to właśnie zmierz w laboratorium jako próg objętości: minimalną liczbę skażonych fragmentów potrzebną do przejęcia odpowiedzi na konkretne zapytanie. Pojedynczy, dobrze dobrany fragment nasycony słownictwem ofiary potrafi wejść do top-k na wąskie zapytanie, ale przegłosowanie poprawnej treści zwykle wymaga kilku kopii. Wynik zależy od rozmiaru korpusu, progu top-k i modelu osadzeń, więc test trzeba prowadzić na realistycznej skali.
Jak wykryć skażone wyszukiwanie w bazie wektorowej?
Łącz kilka niezależnych sygnałów. Najmocniejszy to pochodzenie fragmentu: metadane o źródle i ścieżce wczytywania pozwalają oznaczyć jako podejrzaną każdą odpowiedź wynikłą z treści z niezaufanego kanału. Dalej: wykrywanie odstających osadzeń (skażone wpisy często leżą nienaturalnie blisko siebie lub wielu niespokrewnionych zapytań), kontrola niespójności z resztą pobranych fragmentów oraz stałe testy regresyjne na potwierdzonych atakach.
Czy Garak, PyRIT i Promptfoo testują zatruwanie RAG?
Częściowo i komplementarnie. Garak (NVIDIA) skanuje sam model pod jailbreaki, wstrzyknięcia i wyciek danych, ale domyślnie nie sprawdza, czy da się zatruć kontekst pobierany z bazy wektorowej. PyRIT (Microsoft) obsługuje scenariusze wielokrokowe, gdy zatrucie ujawnia się po serii zapytań. Promptfoo traktuje potoki RAG jako pełnoprawny cel, ma wtyczki pod pośrednie wstrzyknięcie i zatruwanie pamięci oraz zamienia potwierdzony atak w test regresyjny. Sam zasiew korpusu zwykle dopisujesz własnym skryptem.
Dlaczego skutek testu trzeba mierzyć w nowej sesji?
Bo istotą zatruwania pamięci jest trwałość: atak przeżywa koniec sesji, w której go zasiano. Jeśli mierzysz skutek w tej samej sesji co zasiew, sprawdzasz raczej zwykłe wstrzyknięcie w kontekście i możesz przegapić to, co czyni atak groźnym. Zasiej w jednym przejściu, a wpływ potwierdź w świeżej, czystej sesji, która nie ma żadnej wiedzy o zasiewie.
Jaka klasa OWASP odpowiada zatruwaniu RAG i baz wektorowych?
To LLM08:2025 Vector and Embedding Weaknesses (słabości wektorów i osadzeń) z OWASP Top 10 for LLM Applications 2025. Dokument opisuje wstrzykiwanie szkodliwej treści przez korpus RAG, manipulację osadzeniami, brak izolacji najemców i wprowadzanie niesanityzowanej pobranej treści do promptu — dokładnie te wektory, które odtwarzasz w laboratorium zatruwania RAG.