← Wszystkie wpisy

Twój agent ma dwa niezaufane wejścia

Z przewodnika: Claude Code Comprehensive Guide

Tradycyjny program ma jedną granicę zaufania: wejście, które przekazuje mu użytkownik. Walidujesz na tej krawędzi i w zasadzie masz z głowy. Agent po cichu dodał dwie kolejne, a większość narzędzi zbudowanych wokół agentów traktuje jako prawdziwą tylko jedną z nich.

Pierwsze nowe wejście to kod, który pisze model i który uruchamia Twój proces. Drugie to wyjście narzędzi, które model czyta, a potem na jego podstawie działa. Oba przekraczają granicę Twojego systemu z miejsca, którego nie kontrolujesz – z rozkładu próbkowania modelu językowego albo z serwera strony trzeciej – i oba są traktowane jako zaufane w chwili, gdy docierają. Bezpieczeństwo agentów wydaje się teraz nieustalone dlatego, że branża ma wiarygodną odpowiedź na pierwsze wejście i wciąż udaje, że drugie to ten sam problem. Nie jest.

Najważniejsze wnioski

  • Agenci mają dwa niezaufane wejścia, nie jedno. Wygenerowany przez model kod, który wykonuje Twoje środowisko uruchomieniowe, oraz wyjście narzędzi/serwerów, które Twój model przyjmuje i na którego podstawie działa. Zawodzą na różne sposoby i wymagają różnych zabezpieczeń – mieszanie ich to powód, dla którego ludzie czują się w piaskownicy, pozostając podatnymi.12
  • Wykonywanie niezaufanego kodu ma wreszcie wiarygodną odpowiedź w postaci izolacji. micropython-wasm Simona Willisona uruchamia napisany przez model Python w piaskownicy WebAssembly z limitami pamięci i CPU oraz kontrolowanym dostępem do plików i sieci – cechami, których potrzebuje prawdziwa piaskownica, na podłożu „testowanym w przeglądarkach od niemal dekady”.1
  • Zatruwanie narzędzi nie jest problemem wykonywania kodu, więc piaskownica kodu nic na nie nie daje. Złośliwe instrukcje ukryte w opisie narzędzia MCP są „niewidoczne dla użytkowników, ale widoczne dla modeli AI” i mogą przejąć agenta, nawet jeśli zatrute narzędzie nigdy nie zostanie uruchomione.23
  • Najgłębszy problem to luka zaufania między czasem połączenia a czasem działania. Opisy narzędzi są przeglądane raz, przy zatwierdzaniu; odpowiedzi narzędzi płyną prosto do kontekstu modelu bez równoważnej kontroli – a złośliwy serwer może zmienić opis po tym, jak go zatwierdzisz.2

Dwa wejścia, dwa tryby awarii

Zestaw te dwa wejścia obok siebie, bo asymetria jest całą puentą.

Kiedy model pisze kod, a Ty wykonujesz go przez exec(), tryb awarii to kod robi coś Twojej maszynie – czyta plik, którego nie powinien, otwiera gniazdo, kręci procesorem w nieskończoność, psuje stan. Promień rażenia to Twój proces i wszystko, do czego może sięgnąć. Obrona jest prastara i dobrze rozumiana: izolacja. Uruchom kod gdzieś, gdzie nie dotknie tego, co ważne.

Kiedy model czyta wyjście narzędzia i na jego podstawie działa, tryb awarii to słowa zmieniają to, co model postanawia zrobić. Nic nie wykonuje się na Twoim hoście w klasycznym sensie; zamiast tego tekst, który przyszedł jako „dane”, zostaje zinterpretowany jako „instrukcja”, a agent – trzymający Twoje poświadczenia – ją wykonuje. Promień rażenia to wszystko, do czego Twój agent jest upoważniony. Żadna izolacja procesów nie pomoże, bo agent miał przecież móc czytać to narzędzie i działać na jego podstawie. Exploit jedzie legalną ścieżką.

Piaskownica kodu to mur wokół pierwszego wejścia. Jest niezbędna i wreszcie robi się dobra. Na temat drugiego wejścia milczy całkowicie.

Wejście, które wreszcie ma piaskownicę

6 czerwca 2026 roku Simon Willison wydał micropython-wasm, pakiet w wersji alfa do uruchamiania Pythona w piaskownicy WebAssembly, po latach prób z podejściami, które nigdy do końca nie pasowały.1 Motywacja to dokładnie pierwsze niezaufane wejście: chce uruchamiać kod generowany przez LLM wewnątrz swojego Datasette Agenta bez narażania hosta, a jak sam to ujmuje, „wadliwa lub złośliwa wtyczka mogłaby wszystko zepsuć albo wyciec prywatne dane”.1

Uwagę zasługuje lista kontrolna, którą faktycznie spełnia, bo ta lista jest definicją użytecznej piaskownicy:

  • Limity pamięci i CPU, żeby napisane przez model while True: s += "x" nie mogło wyczerpać hosta. CPU jest ograniczony mechanizmem „fuel” z wasmtime – co do którego Willison jest szczery, zauważając, że jednostki są „trudne do ogarnięcia”.1
  • Kontrolowany dostęp do plików i sieci, domyślnie odmawiany, a nie domyślnie otwarty.
  • Czysty model izolacji: kod działa na osobnym wątku za kolejką żądanie/odpowiedź, a interpreter WASM blokuje się na funkcji hosta, dopóki nie dostanie pracy – niezaufany kod nigdy więc nie dzieli przestrzeni adresowej hosta.1
  • Podłoże z historią. Wybrał WebAssembly, bo zostało „od początku zaprojektowane tak, by wspierać wszystkie cechy, na których mi zależy, i było testowane w przeglądarkach od niemal dekady”, a MicroPythona, bo zorientowany na przeglądarkę Pyodide nie jest wspierany po stronie serwera.1

Ta szczerość to znak rozpoznawczy dobrej pracy nad bezpieczeństwem. Willison wydaje to jako alfę i pisze, że „nie jest gotów polecać tego nikomu, kto nie chce podjąć znaczącego ryzyka”.1 To postawa bramki dowodów – twierdzić dokładnie to, co się zweryfikowało, i nic więcej. Nie chodzi o to, że ten jeden pakiet jest odpowiedzią; chodzi o to, że kształt odpowiedzi na niezaufany kod jest teraz jasny i odtwarzalny: prawdziwa granica izolacji z limitami zasobów i domyślnie odmawianym I/O. Pierwsze wejście staje się rozwiązanym problemem inżynierskim.

Pułapka polega na wierze, że jego rozwiązanie czyni Cię bezpiecznym.

Wejście, które jej nie ma

Drugie wejście nie uruchamia kodu, więc mur nic nie daje. 1 kwietnia 2025 roku Invariant Labs ujawniło atak zatruwania narzędzi: „złośliwe instrukcje są osadzane w opisach narzędzi MCP, niewidoczne dla użytkowników, ale widoczne dla modeli AI”.2 Asymetria jest exploitem – „modele AI widzą pełne opisy narzędzi, łącznie z ukrytymi instrukcjami, podczas gdy użytkownicy zwykle widzą w swoim interfejsie tylko uproszczone wersje”.2 Narzędzie, które w interfejsie brzmi „dodaje dwie liczby”, może w opisie, który model faktycznie konsumuje, nieść instrukcję odczytania ~/.ssh/id_rsa i wyprowadzenia go przez ukryty parametr.2 OWASP kataloguje to już jako nazwaną klasę ataku.3

Dwie właściwości czynią go paskudnym w sposób, do którego izolacja nie sięga:

Odpala się bez wywołania narzędzia. Zatrute instrukcje żyją w opisie, który model przyjmuje, gdy rozważa zestaw narzędzi – atak może więc się udać, nawet jeśli funkcja nigdy się nie wykona.3 Nie ma żadnego zdarzenia kodu, które dałoby się zamknąć w piaskownicy.

Zaufanie jest udzielane raz, a nadużywane później. Opisy narzędzi są przeglądane w czasie połączenia, gdy zatwierdzasz serwer. Odpowiedzi płyną potem prosto do kontekstu modelu w czasie działania bez równoważnej kontroli – a według ustalenia Invariant o „rug pullu” „złośliwy serwer może zmienić opis narzędzia po tym, jak klient już go zatwierdził”.2 Twoje jednorazowe zatwierdzenie nie zabezpiecza niczego trwałego.

Kanoniczna demonstracja nie jest hipotetyczna. Badacze zatruli zgłoszenie na GitHubie wstrzykniętym tekstem; kiedy deweloper poprosił asystenta o przejrzenie otwartych zgłoszeń, agent przyjął zgłoszenie, wykonał ukryte instrukcje, użył tokena dewelopera do odczytania prywatnych repozytoriów i wyciekł ich zawartość do publicznego pull requesta.3 Każde pojedyncze działanie było autoryzowane. Agent zrobił dokładnie to, do czego agent służy. Dlatego piaskownica kodu jest tu bez znaczenia – nic niezaufanego nie zostało wykonane; niezaufany tekst został po prostu awansowany do rangi instrukcji wewnątrz procesu trzymającego prawdziwe poświadczenia. To ta sama lekcja, którą Ken Thompson zostawił w Reflections on Trusting Trust: niebezpieczeństwem nie jest kod, który sprawdzasz, tylko zaufanie, którego udzielasz bez sprawdzania.

Obrona drugiego wejścia

Jeśli izolacja jest obroną dla kodu, to obroną dla wyjścia narzędzi jest traktowanie granicy między danymi a instrukcją jako prawdziwej, w czasie działania, za każdym razem – czyli to, co model zatwierdzania w czasie połączenia pomija. Własne wytyczne Microsoftu dotyczące MCP lądują w tym samym miejscu, zalecając „prompt shields”, które wykrywają i filtrują wstrzyknięte instrukcje, oraz spotlighting, w którym „umieszczenie ograniczników w komunikacie systemowym jawnie wyznacza położenie tekstu wejściowego”, żeby model odróżniał treść od polecenia.4 Konkretnie:

  • Sprawdzaj opisy ponownie w czasie działania, nie tylko przy zatwierdzaniu. Przypnij definicję narzędzia, którą zatwierdziłeś, i wykrywaj, kiedy opis serwera zmienia się pod Tobą. Rug pull działa tylko dlatego, że nikt nie patrzy dwa razy.2
  • Oznaczaj granicę dane/instrukcja jawnie. Odpowiedzi narzędzi to dane, nie dyrektywy – a praktyczna wersja to spotlighting: ogranicz wyjście narzędzia w kontekście tak, by model dostał strukturalnie informację, że to treść do rozważenia, a nie polecenia do wykonania.4 Łączy się to z autoryzacją na poziomie działań w narzędziach MCP, tak by nawet przejęty agent nie mógł sięgnąć po wywołania o wysokich konsekwencjach.
  • Stosuj zasadę najmniejszych uprawnień do autoryzowanej ścieżki. Exploit na GitHubie zadziałał, bo jeden agent trzymał zarówno „czytaj prywatne repozytoria”, jak i „otwieraj publiczne PR” – a najmniejsze uprawnienia to dokładnie to, co Microsoft wskazuje jako podstawową higienę przeciw tym atakom.4 Bezpieczeństwo przez kompartmentalizację Joanny Rutkowskiej to ten sam instynkt na poziomie architektury: załóż, że domena jest skompromitowana, i upewnij się, że nie sięgnie do pozostałych. Agent, który czyta zgłoszenia, nie powinien być agentem, który trzyma ścieżkę wyprowadzania danych.
  • Obserwuj ruch wychodzący, bo eksfiltracja to nagroda. Większość tych ataków kończy się na tym samym kroku – dane wychodzą. Spojrzenie w stylu cichego wyjścia wyłapuje skutek, nawet gdy wstrzyknięcie prześlizgnęło się przez drzwi frontowe.

Żadne z nich nie jest murem. To bramki na ścieżce, którą agent ma przejść – trudniejszy, mniej satysfakcjonujący rodzaj bezpieczeństwa i taki, jakiego drugie wejście naprawdę wymaga.

Co z tego biorę dla siebie

Model mentalny, który zatrzymuję, jest taki, że „czy mój agent jest w piaskownicy?” to złe pytanie, bo po cichu zakłada, że jest jedna granica do obrony. Są dwie. Kod, który pisze mój model, potrzebuje muru – i dzięki pracom takim jak Willisona zbudowanie tego muru staje się normalnym zadaniem inżynierskim z jasną specyfikacją. Wyjście narzędzi, które czyta mój model, potrzebuje czegoś zupełnie innego: środowiska, które nigdy nie pozwoli danym po cichu stać się instrukcją, oraz modelu autoryzacji tak ciasnego, że przejęty agent i tak niewiele zdziała. Mieszanie ich to sposób, w jaki człowiek czuje się chroniony – „patrz, kod działa w WASM” – pozostając szeroko otwartym przez wejście, na którym nikt nie postawił bramki.

Głębsza ciągłość polega na tym, że agenci nie tyle wymyślili nową kategorię podatności, ile dodali nowe miejsca, w których może mieszkać stara. Niezaufane wejście zawsze było korzeniem bezpieczeństwa; era agentów dała mu tylko dwoje nowych drzwi – jedne, które możesz zamknąć izolacją, i drugie, które możesz jedynie pilnować dyscypliną. Zbuduj mur i bramkę. Sam mur, w systemie z dwoma wejściami, to połowa obrony, która wydaje się całością.

Często zadawane pytania

Jakie są dwa niezaufane wejścia w agencie AI?

Wygenerowany przez model kod, który wykonuje Twoje środowisko uruchomieniowe, oraz wyjście narzędzi lub serwerów, które Twój model czyta, a potem na jego podstawie działa. Pierwsze może bezpośrednio uszkodzić hosta; drugie może przejąć decyzje agenta, korzystając z poświadczeń i uprawnień, które agent już posiada. Wymagają różnych zabezpieczeń – izolacji dla kodu, rozdzielenia danych i instrukcji w czasie działania oraz ścisłej autoryzacji dla wyjścia narzędzi.12

Czy piaskownica kodu chroni przed zatruwaniem narzędzi MCP?

Nie. Zatruwanie narzędzi nie wykonuje kodu na Twoim hoście – osadza w opisie narzędzia instrukcje, które model traktuje jako zaufane, i może się odpalić, nawet jeśli narzędzie nigdy nie zostanie wywołane.23 Piaskownica izoluje wykonanie, więc nic nie daje przeciw atakowi, który jedzie legalnymi, autoryzowanymi działaniami agenta.

Czym jest atak zatruwania narzędzi?

Ujawniony przez Invariant Labs w kwietniu 2025 roku, to atak, w którym „złośliwe instrukcje są osadzane w opisach narzędzi MCP, niewidoczne dla użytkowników, ale widoczne dla modeli AI”.2 Ponieważ model widzi pełny opis, a użytkownik uproszczoną etykietę w interfejsie, ukryte instrukcje – na przykład odczytania kluczy SSH i ich wyprowadzenia – mogą przejąć agenta. OWASP śledzi to już jako nazwaną klasę ataku.23

Czym jest luka zaufania między czasem połączenia a czasem działania?

Opisy narzędzi są przeglądane raz, gdy zatwierdzasz serwer (czas połączenia). Odpowiedzi narzędzi płyną potem do kontekstu modelu w czasie działania bez równoważnej kontroli, a złośliwy serwer może zmienić opis po zatwierdzeniu („rug pull”).2 Rozwiązaniem jest weryfikacja w czasie działania, nie tylko przy zatwierdzaniu.


Źródła


  1. Simon Willison, „Running Python code in a sandbox with MicroPython and WASM,” simonwillison.net, 6 czerwca 2026. Przedstawia pakiet alfa micropython-wasm i wtyczkę datasette-agent-micropython; motywację, że „wadliwa lub złośliwa wtyczka mogłaby wszystko zepsuć albo wyciec prywatne dane”; listę kontrolną piaskownicy (limity pamięci/CPU przez „fuel” z wasmtime, kontrolowany dostęp do plików/sieci, izolację żądanie/odpowiedź na osobnym wątku); uzasadnienie, że WebAssembly zostało „od początku zaprojektowane tak, by wspierać wszystkie cechy, na których mi zależy, i było testowane w przeglądarkach od niemal dekady”; oraz zastrzeżenie, że „nie jest gotów polecać tego nikomu, kto nie chce podjąć znaczącego ryzyka”. ↩↩↩↩↩↩↩↩↩

  2. Luca Beurer-Kellner i Marc Fischer, „MCP Security Notification: Tool Poisoning Attacks,” Invariant Labs, 1 kwietnia 2025. Pierwotne ujawnienie: „Atak zatruwania narzędzi ma miejsce, gdy złośliwe instrukcje są osadzane w opisach narzędzi MCP, niewidoczne dla użytkowników, ale widoczne dla modeli AI”; luka widoczności („modele AI widzą pełne opisy narzędzi, łącznie z ukrytymi instrukcjami, podczas gdy użytkownicy zwykle widzą w swoim interfejsie tylko uproszczone wersje”); ustalenie o „rug pullu”, że „złośliwy serwer może zmienić opis narzędzia po tym, jak klient już go zatwierdził”; oraz przykład zatrutego add czytającego ~/.cursor/mcp.json i ~/.ssh/id_rsa. ↩↩↩↩↩↩↩↩↩↩↩↩↩

  3. „MCP Tool Poisoning,” OWASP Foundation. Kataloguje zatruwanie narzędzi jako nazwaną klasę ataku: instrukcje ukryte w metadanych narzędzi, które wpływają na agenta, „nawet jeśli zatrute narzędzie nigdy nie zostanie wywołane”, oraz przykład GitHub MCP, w którym zatrute zgłoszenie prowadzi agenta do odczytania prywatnych repozytoriów przez token dewelopera i wycieku ich do publicznego pull requesta. ↩↩↩↩↩↩

  4. Sarah Young i Den Delimarsky, „Protecting against indirect prompt injection attacks in MCP,” Microsoft Developer Blog, 28 kwietnia 2025. Zaleca „prompt shields”, które „wykorzystują zaawansowane algorytmy uczenia maszynowego i przetwarzanie języka naturalnego do wykrywania i odfiltrowywania złośliwych instrukcji”, spotlighting, w którym „umieszczenie ograniczników w komunikacie systemowym jawnie wyznacza położenie tekstu wejściowego”, weryfikację łańcucha dostaw komponentów MCP oraz podstawową higienę, taką jak najmniejsze uprawnienia. ↩↩↩

Powiązane artykuły

Piaskownica Twojego agenta to tylko sugestia

Atakujący otworzył zgłoszenie na GitHub i dostarczył złośliwe oprogramowanie w kolejnym wydaniu Cline. Piaskownice agent…

14 min czytania

Serwery MCP to nowa powierzchnia ataku

50 podatności MCP, 30 CVE w 60 dni, 13 krytycznych. Protokoły użycia narzędzi to powierzchnia ataku, której nikt nie aud…

6 min czytania

Pętla Ralph: jak uruchamiam autonomiczne agenty AI na noc

Zbudowałem system autonomicznych agentów z hookami zatrzymania, budżetami spawnowania i pamięcią opartą na plikach. Co z…

9 min czytania