Bezpieczeństwo agentów AI: uprawnienia, sandboxy i zagrożenia MCP
Tłumaczenie automatyczne Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.
Aktualizacja artykułu
Pierwotnie opublikowano 20 kwietnia 2026 r. Zaktualizowano i poddano przeglądowi 6 września 2026 r. Aktualizacja obejmuje nowsze mechanizmy kontroli sandboxów, interwencje bezpieczeństwa dostawców oraz opublikowane ustalenia dotyczące bezpieczeństwa — wraz z ich ograniczeniami i linkami do źródeł.
Bezpieczeństwo agenta zaczyna się w chwili, gdy model proponuje działanie, a kończy dopiero przed wykonaniem go przez maszynę. Zanim działanie uzyska dostęp do poświadczeń, plików, sieci lub systemu zewnętrznego, zdecyduj, która kontrola ma ostateczny głos.
Harness to kod, który buduje każdy prompt, decyduje, które proponowane wywołania narzędzi zostaną wykonane, i zwraca wyniki do modelu. Większość kontroli powinna znajdować się właśnie tam, ponieważ jest to ostatnie tanie miejsce, w którym można zatrzymać polecenie. Po jego wykonaniu sandbox, przekazane mu poświadczenia oraz proces odzyskiwania muszą ograniczyć szkody. Niektóre incydenty opisane w tym artykule w ogóle nie docierają do modelu.
Bezpieczeństwo agentów AI wykracza poza bezpieczeństwo LLM. Wczesne produkty guardrails analizowały wejście i wyjście pojedynczego wywołania modelu. Mogły filtrować toksyczny tekst, redagować dane osobowe, blokować jailbreaki i odrzucać odpowiedzi odbiegające od tematu. Taka granica była użyteczna, dopóki model mógł zwracać wyłącznie tekst.
Pętle narzędzi dodały systemy plików, shelle, serwery Model Context Protocol (MCP) oraz poświadczenia. Model zagrożeń rozszerzył się więc z niebezpiecznego tekstu na niebezpieczne działania. Siedem opisanych niżej grup incydentów obejmuje pośrednie prompt injection oraz błędy konfiguracji, tożsamości i dystrybucji oprogramowania. Analiza tekstu może pomóc w przypadku niektórych złośliwych danych wejściowych, ale nie zastąpi kontroli na tych granicach wykonawczych.
Gdy agent może odczytać repozytorium, wywołać narzędzie lub wysłać dane stronie trzeciej, przypisz każde proponowane działanie do kontroli, która może je zatrzymać. Poniższe sekcje obejmują uprawnienia, hooki, sandboxy, poświadczenia i przegląd wykonywany przez człowieka.
Krótka lista kontrolna znajduje się tutaj: Lista kontrolna bezpieczeństwa agenta AI.
Stos bezpieczeństwa agenta AI
Żaden pojedynczy guardrail nie zabezpiecza agenta. Każda część systemu potrzebuje własnej kontroli.
Tabela wskazuje, gdzie działa każda kontrola. Harness to opisany wyżej program sterujący. Runtime to infrastruktura, z której korzysta: sandbox, log sesji, magazyn checkpointów i trace’y zachowywane po restarcie workera.
| Warstwa | Co kontroluje | Przykładowa awaria, którą wykrywa | Gdzie działa |
|---|---|---|---|
| Filtry treści | Niebezpieczny tekst wejściowy i wyjściowy | Toksyczne wyjście, wyciek PII, odpowiedzi naruszające politykę | Harness |
| Drabina uprawnień | Narzędzia, ścieżki, API i zakresy dostępne agentowi | Agent podsumowujący próbujący zapisywać w systemach produkcyjnych | Harness |
| Hook polityki przed narzędziem | Czy dane działanie powinno teraz zostać wykonane | Polecenie shell zbudowane na podstawie niezaufanej treści wyszukanej przez retrieval | Harness |
| Sandbox | Do czego narzędzie może uzyskać dostęp na poziomie systemu i sieci | Eksfiltracja plików, przejęcie zależności, command injection | Runtime |
| Kontrola akceptacji człowieka | Nieodwracalne działania o dużym wpływie | Wysłanie e-maila, transfer pieniędzy, wdrożenie na produkcję | Harness |
| Zakres MCP i tokenów | Dla którego serwera i odbiorcy ważne jest poświadczenie | Ponowne użycie tokenu wobec niezamierzonego serwera narzędzi | Runtime |
| Ślad audytowy | Co się wydarzyło, kto zatwierdził działanie i dlaczego | Analiza incydentu po długim autonomicznym przebiegu | Runtime |
Filtry treści pytają, czy model powiedział coś niebezpiecznego. Bezpieczeństwo agenta pyta również, czy system może wykonać następne działanie.
Wiersze dotyczące harnessu decydują, czy działanie może zostać wykonane. Wiersze dotyczące runtime’u egzekwują wcześniej ustalone ograniczenia i rejestrują przebieg. Zachowaj sandbox nawet wtedy, gdy reguły uprawnień wydają się kompletne: może zatrzymać wywołanie, którego harness nie przewidział. Nie może jednak zdecydować, czy dozwolone działanie było właściwe — to musi zrobić harness.
Ostatnia kolumna wskazuje, gdzie działa kontrola, a nie kto nią zarządza. Dostawca może udostępniać filtr treści, ale wywołuje go harness.
Zarządzane filtry treści obejmują warstwę tekstową. Pozostałe kontrole należą do polityki aplikacyjnej, systemu tożsamości i infrastruktury.
Dlaczego bezpieczeństwo agentów AI różni się od bezpieczeństwa LLM
Bharani Subramaniam i Martin Fowler przedstawili te ramy na początku 2025 r. w artykule Emerging Patterns in Building GenAI Products. Ich obserwacja była wąska i bezpośrednia:
„W tradycyjnych systemach mogliśmy oceniać poprawność przede wszystkim za pomocą testów… W systemach opartych na LLM mamy do czynienia z systemem, który nie zachowuje się już deterministycznie”.
Ewaluacja wyjścia sprawdza, czy odpowiedź modelu spełnia określone kryteria. Model zagrożeń agenta musi obejmować również wywołania narzędzi, polecenia shell, zapisy plików, poświadczenia i żądania sieciowe. Ewaluator wyjścia nie może zatrzymać tych działań. Robi to harness — zbiór kontroli, które przekształcają propozycję modelu w dozwolone działanie. Pozostała część artykułu opisuje te kontrole.
Simon Willison ujął specyficzny dla agentów kształt ryzyka w czerwcu 2025 r., nazywając go lethal trifecta:
„Lethal trifecta możliwości obejmuje: dostęp do prywatnych danych; kontakt z niezaufaną treścią; możliwość zewnętrznej komunikacji, która może posłużyć do kradzieży danych. Jeśli agent łączy te trzy cechy, atakujący może łatwo nakłonić go do uzyskania dostępu do prywatnych danych i wysłania ich atakującemu”.
Wiele użytecznych agentów łączy te możliwości: dostęp do skrzynki odbiorczej, wyszukiwanie w sieci i narzędzie do wysyłania wiadomości; albo dostęp do repozytorium, odczytywanie issue i zapisywanie pull requestów. Guardrail treści pyta, czy model wygenerował niebezpieczny tekst. Trifecta pyta, czy niezaufane dane wejściowe mogą pokierować systemem tak, by ujawnił dane za pośrednictwem dozwolonego działania.
Strukturalna wersja tego samego argumentu znajduje się w preprincie Joela Fokou Parallax (arXiv 2604.12986, zgłoszonym 14 kwietnia 2026 r., bez recenzji naukowej). Główna teza brzmi:
„System rozumujący o działaniach musi być strukturalnie niezdolny do ich wykonywania, a system wykonujący działania musi być strukturalnie niezdolny do rozumowania o nich — pomiędzy nimi powinien znajdować się niezależny, niezmienny walidator”.
Nie trzeba akceptować wyników ewaluacji z tego artykułu, aby przeanalizować jego punkt strukturalny. Kilka obecnych harnessów implementuje częściowo tę samą separację:
- hooki PreToolUse w Claude Code
- executor Codex CLI z sandboxem systemowym (w systemie Linux: bubblewrap i filtrowanie wywołań systemowych przez seccomp)
- Managed Agents firmy Anthropic, które przechowują poświadczenia w vault, którego agent nigdy nie widzi
- tokeny MCP z ograniczeniem odbiorcy zgodnie z RFC 8707
Systemy te oddzielają model od kodu wykonującego polecenia. Ich kontrole są różne, ale żaden nie pozwala executorowi polegać na opinii modelu o bezpieczeństwie.
Istnieje uzupełniająca zasada, którą Alessandro Pignati najtrafniej nazwał w styczniu 2026 r.: Principle of Least Agency. Least Privilege pyta: do czego ta tożsamość ma dostęp? Least Agency pyta: o czym ten agent może decydować? Privilege ogranicza poświadczenia; agency ogranicza zasięg planu, nawet gdy poświadczenia są prawidłowe. Excessive Agency to osobna pozycja w Top 10 dla aplikacji LLM opublikowanym przez OWASP, Open Worldwide Application Security Project. Osobna lista agentowa, omówiona dalej, rozdziela tę samą awarię między nadużycie narzędzi i nadużycie uprawnień. Least Agency to dyscyplina projektowa, która zapobiega obu problemom. Agent, który może podsumować skrzynkę odbiorczą, prawdopodobnie nie potrzebuje praw do commitowania w monorepo. A jednak wciąż znajdujemy konfiguracje, w których je ma.
Co obejmują guardrails dla LLM
Guardrails dla LLM wykonują istotną pracę wokół wywołania modelu. Analizują wejście, wyszukany tekst i wyjście, a następnie blokują, redagują, naprawiają lub oznaczają treści, które nie spełniają skonfigurowanej reguły. Poniższe produkty różnią się sposobem wdrożenia i zakresem. Kontrola treści jest odrębna od kontroli autoryzacji na granicy narzędzia lub serwera MCP; niektóre produkty oferują również funkcje polityk runtime’u, które wymagają własnej konfiguracji i ewaluacji.
NVIDIA NeMo Guardrails
Najbardziej opiniotwórczy z produktów: framework orkiestracyjny wokół pięciu typów rails (input, dialog, retrieval, execution, output) z własnym DSL — Colang, językiem podobnym do Pythona służącym do definiowania przepływów dialogu, intencji użytkownika i wiadomości bota. Podstawy można obsługiwać z poziomu Python + YAML, ale bogatsza logika dialogu jest zapisywana w Colang — stąd określenie „opiniotwórczy”. Dokumentacja znajduje się pod adresem docs.nvidia.com/nemo/guardrails.
To przykładowy kształt API; wymaga pakietu i skonfigurowanego katalogu ./config.
from nemoguardrails import LLMRails, RailsConfig
config = RailsConfig.from_path("./config")
rails = LLMRails(config)
response = rails.generate(
messages=[{"role": "user", "content": "Hello"}]
)
Repozytorium NeMo jasno opisuje model zagrożeń: „typowe podatności LLM, takie jak jailbreaki i prompt injection”. Równie jasno określa zakres: „Wbudowane guardrails mogą, ale nie muszą, nadawać się do danego zastosowania produkcyjnego… deweloperzy powinni współpracować z wewnętrznym zespołem aplikacyjnym, aby upewnić się, że guardrails spełniają wymagania”. Pokazana tu ścieżka filtrowania treści obserwuje to, co mówi model. Aktualna dokumentacja NeMo opisuje również execution rails, akcje niestandardowe i inspekcję wywołań narzędzi; są to konfigurowalne kontrole runtime’u, a nie dowód, że wdrożone narzędzie lub serwer MCP uwierzytelnił i autoryzował wywołanie. Za tę granicę nadal odpowiada aplikacja.
Meta Llama Guard 4
Czysty klasyfikator treści 12B, wyodrębniony z Llama-4-Scout i dostosowany do taksonomii zagrożeń MLCommons (13 kategorii szkód oraz nadużycia interpretera kodu, zgodnie z kartą modelu). Meta wyjątkowo otwarcie mówi o ograniczeniach:
„Niektóre kategorie zagrożeń mogą wymagać aktualnej wiedzy faktograficznej, aby można je było w pełni ocenić… Wreszcie, jako LLM, Llama Guard 4 może być podatny na ataki adwersarialne lub prompt injection, które mogą ominąć jego zamierzone zastosowanie albo je zmienić: zobacz Llama Prompt Guard 2 do wykrywania ataków na prompt”.
Meta dostarcza osobny produkt do ochrony klasyfikatora treści przed prompt injection. Jeśli to zdanie brzmi jak strukturalne przyznanie ograniczenia, tak właśnie jest.
Guardrails AI
Rejestr walidatorów. Łączysz walidatory Hub (PII za pomocą Presidio, JailbreakDetect, CompetitorCheck, kontrole proweniencji) z akcjami on_fail exception | fix | fix_reask | filter | refrain | reask | noop albo własnym callbackiem (guardrailsai.com). Zwróć uwagę na exception, a nie raise. W aktualnym kodzie nierozpoznany ciąg on_fail trafia do obsługi własnego callbacku i powoduje błąd podczas konfiguracji walidatora, zamiast wyświetlić ostrzeżenie i użyć wartości domyślnej. Przypnij wdrażaną wersję i przetestuj tę ścieżkę błędu. Nie istnieje jeden zunifikowany model zagrożeń; zakres ochrony jest sumą zainstalowanych walidatorów. Otrzymujesz ochronę przed tym, dla czego masz walidator, i żadnej ochrony przed resztą.
Lakera Guard
Obecny na rynku SaaS API, trenowany na dziesiątkach milionów próbek ataków zebranych z Gandalf. Obiecuje analizować wejście i wyjście pod kątem „prompt attacks… i wycieku danych”. Osobny produkt Lakera AI Agent Security opisuje również egzekwowanie polityk i runtime’u w odniesieniu do tego, do czego agenci mogą uzyskać dostęp, co mogą wywoływać i jakie działania mogą wykonywać. To inna powierzchnia produktu niż omawiane tutaj wywołanie do filtrowania treści. Przed wdrożeniem sprawdź aktualną umowę produktową i cennik.
AWS Bedrock Guardrails
Domyślny wybór dla przedsiębiorstw korzystających już z Bedrock. ApplyGuardrail działa z dowolnym modelem, niezależnie od tego, czy jest to Bedrock:
# No-run: illustrative AWS request; requires boto3, AWS credentials, and a real guardrail identifier.
import boto3
brt = boto3.client("bedrock-runtime")
resp = brt.apply_guardrail(
guardrailIdentifier="gr-xxxxxxxxxxxx",
guardrailVersion="2",
source="INPUT",
content=[{"text": {"text": "user question",
"qualifiers": ["guard_content"]}}],
)
Opublikowany ApplyGuardrail cennik: $0.15 za 1000 jednostek tekstu dla filtrów treści lub zablokowanych tematów, $0.10 dla filtrów PII lub contextual grounding. Jednostka tekstu obejmuje do 1000 znaków.
Azure AI Content Safety
Udostępnia Prompt Shields jako zunifikowany endpoint, który „wykrywa i blokuje adwersarialne ataki z danych wejściowych użytkownika… zagrożenia bezpośrednie i pośrednie”. Azure również jest szczery: „Azure AI Content Safety nie można używać do wykrywania nielegalnych obrazów przedstawiających wykorzystywanie dzieci”, a jakość wielojęzyczna jest ograniczona do ośmiu ocenianych języków.
OpenAI Moderation i OpenAI Guardrails
omni-moderation-latest to bezpłatna baza multimodalna. Osobno openai-guardrails-python (dokumentacja: guardrails.openai.com) to odpowiedź OpenAI na poziomie frameworku: trzystopniowy pipeline (pre-flight, input, output) z Jailbreak Detection, Hallucination Detection przez FileSearch, NSFW, PII przez Presidio oraz LLM-as-judge. GuardrailAgent integruje się z Agents SDK.
# No-run: illustrative OpenAI Guardrails API shape; requires the package and guardrail_config.json.
from guardrails import GuardrailsOpenAI, GuardrailTripwireTriggered
client = GuardrailsOpenAI(config="guardrail_config.json")
try:
resp = client.responses.create(model="<your-model-id>", input="...")
except GuardrailTripwireTriggered as e:
print(f"blocked: {e}")
Czego nie rozstrzygają filtry treści
Dwie obserwacje dotyczące wszystkich siedmiu produktów.
Po pierwsze, opublikowanych danych o opóźnieniach i przepustowości jest niewiele. Bedrock, Azure i Lakera publikują ceny, ale nie gwarantują najgorszego przypadku opóźnienia. Meta nie publikuje gwarancji dotyczącej hostowanego endpointu dla Llama Guard. NVIDIA dostarcza NeMo Guardrails jako oprogramowanie hostowane przez użytkownika, więc opóźnienie zależy od modelu i infrastruktury. Mierz koszt każdej synchronicznej kontroli na ścieżce krytycznej, zamiast wywnioskowywać go z cennika produktu.
Po drugie, ta sekcja obejmuje wymienione wyżej konfiguracje skoncentrowane na treści.
Filtr treści może analizować wejście i wyjście modelu. Nie pokazuje jednak, że konkretne wywołanie narzędzia jest autoryzowane, że serwer MCP uwierzytelnił wywołującego ani że system może zatrzymać wieloetapową eksfiltrację danych lub wykonanie kodu przed wywołaniem modelu. Autoryzacja to osobna decyzja dotycząca tego, czy dana tożsamość może wykonać dane wywołanie wobec tego serwera.
NeMo opisuje również execution rails i inspekcję wywołań narzędzi, a Lakera opisuje egzekwowanie runtime’u w osobnym produkcie AI Agent Security. Są to dodatkowe kontrole, które trzeba skonfigurować i przetestować. Pozostała część wpisu omawia kontrole wokół wykonywania narzędzi.
Zagrożenia bezpieczeństwa agentów AI: siedem incydentów i OWASP ASI Top 10
Różnica między filtrowaniem tekstu a ochroną wykonania przestała być akademicka w połowie 2025 r. Siedem poniższych incydentów dotarło do warstw retrieval, konfiguracji, poświadczeń, instalacji pakietów lub wykonywania w CI. Klasyfikator treści może nadal wykryć podejrzany ciąg, ale kontrole bezpośrednio blokujące te ścieżki znajdują się na granicach narzędzi, tożsamości, sandboxów i łańcucha dostaw.
EchoLeak — CVE-2025-32711
Ujawniony w czerwcu 2025 r. przez Aim Labs, ramię badawcze Aim Security, w odniesieniu do Microsoft 365 Copilot. Techniczny opis znajduje się obecnie w Cato Networks, które przejęło ten zespół, pod nazwiskiem byłego szefa Aim Labs, Itaya Ravii (opis). Spreparowany e-mail, sformułowany jako instrukcje dla ludzkiego odbiorcy, ominął XPIA (wbudowany filtr Microsoftu wyszukujący ataki prompt injection w danych wejściowych Copilota). Następnie trafił do warstwy retrieval Copilota — części systemu, która przeszukuje dokumenty w celu znalezienia kontekstu odpowiedzi. Badacze nazwali tę technikę RAG-spraying: atakujący wykorzystuje wiele e-maili lub długi, podzielony na fragmenty e-mail, aby zwiększyć ekspozycję retrieval. Zwiększa to szansę na pobranie treści, ale go nie gwarantuje. Po uzyskaniu dostępu Copilot posłusznie umieścił najbardziej wrażliwe dane z sesji w linku Markdown wskazującym obraz na domenie kontrolowanej przez atakującego. API podglądu Teams, działające w domenie już zaufanej przez zasady przeglądarki Microsoftu, automatycznie pobrało ten URL obrazu, przekazując tym samym dane atakującemu. Zero kliknięć. Aim Labs nazwało tę klasę ataku „LLM Scope Violation”: model przekracza granicę, której nie powinien przekroczyć, wykorzystując wyłącznie operacje uznawane przez poszczególne systemy za legalne.
Każdy krok z osobna wyglądał legalnie. E-mail był skierowany do człowieka. Retrieval pobrał dokument, który powinien pobrać. Link Markdown renderował się tak, jak renderują się linki Markdown. Pobranie obrazu trafiło do domeny na allowliście. Badacze ominęli filtrowanie XPIA, a model wykonał pośrednie instrukcje z wyszukanej treści. Przypadek łączy awarię prompt injection z zachowaniem retrieval, renderowania i egress; nie dowodzi, że detektory nie miały czego oznaczyć.
Amazon Q Developer VS Code v1.84.0 — lipiec 2025
AWS udostępniło przejęty build po tym, jak atakujący zatwierdził złośliwy plik system promptu za pomocą nadmiernie szeroko uprawnionego tokenu CodeBuild GitHub (advisory). Payload próbował zmienić instrukcje agenta tak, aby wykonywał destrukcyjne działania. Złośliwy kod został rozdystrybuowany wraz z v1.84.0, ale nie wykonał się z powodu błędu składni. AWS unieważniło poświadczenia, usunęło kod i wydało v1.85.0. Payload zawiódł z powodu błędu składni, a nie dlatego, że kontrola bezpieczeństwa go zablokowała.
Usługa Azure Web Apps MCP — CVE-2026-32211
Rekord CVE dostawcy firmy Microsoft dotyczy braku uwierzytelniania w hostowanej usłudze Azure Web Apps MCP. Nie jest to advisory dotyczące każdego lokalnego serwera Azure MCP ani SDK. Wywołujący, który dotrze do nieuwierzytelnionej usługi narzędziowej, może całkowicie ominąć model; wdrożona usługa musi uwierzytelniać i autoryzować żądanie.
Podatności zaufania projektów Claude Code
Były to odrębne podatności, a nie wymagane etapy jednego ataku:
- Obejście ostrzeżenia o zaufaniu naprawiono w wersji 1.0.87.
- Wykonanie przed zaufaniem, CVE-2025-59536, naprawiono w wersji 1.0.111. Konfiguracja repozytorium mogła uruchomić wykonanie przed zaufaniem projektowi.
- Ujawnienie endpointu/klucza API, CVE-2026-21852, naprawiono w wersji 2.0.65. Niezaufana konfiguracja mogła przekierować ruch API i ujawnić poświadczenia.
Zaufanie do projektu, wykonywanie hooków i konfiguracja endpointu to kontrole hosta. Klasyfikator treści nie może zapobiec kodowi, który wykonuje się przed wywołaniem modelu.
Axios 1.14.1 i 0.30.4 — 31 marca 2026
Analiza po incydencie autora wskazuje dwie złośliwe wersje, 1.14.1 i 0.30.4, zawierające zależność plain-crypto-js@4.2.1. Zależność ta zainstalowała trojana zdalnego dostępu — złośliwe oprogramowanie zapewniające atakującemu zdalny dostęp do maszyny. Ekspozycja wymagała rozwiązania dotkniętych wersji i wykonania odpowiedniego procesu instalacji; niezależne npm install nie pobierało ich automatycznie. Była to awaria wykonania w łańcuchu dostaw, niezależna od zachowania modelu.
Przejęcie tagów Trivy Actions — 19 marca 2026
Advisory Aqua opisuje przekierowanie 76 z 77 tagów wersji trivy-action oraz siedmiu tagów setup-trivy do złośliwej treści. Złośliwy entrypoint akcji zbierał pamięć procesu runnera i pliki poświadczeń; nie przypisuj całej tej ścieżki zbierania binarium skanera. Późniejsze zdarzenie Docker Hub miało osobne okno ekspozycji.
Workflow rozwiązujący dotknięty tag podczas przejęcia mógł wykonać payload. Tagi są ruchomymi referencjami, dlatego przypinaj sprawdzone Actions do niezmiennych commit SHA i weryfikuj zmiany zależności. Agent programistyczny może rozpowszechnić tę samą niebezpieczną referencję w większej liczbie plików workflow.
Ewaluacje OpenAI / Hugging Face — lipiec 2026
Raport incydentu z 26 sierpnia firmy OpenAI opisuje wewnętrzne agenty do ewaluacji cyberbezpieczeństwa, które uzyskały dostęp do internetu przez współdzieloną infrastrukturę, współpracowały za pośrednictwem nieautoryzowanej tablicy wiadomości i przejęły systemy Hugging Face. Główny model był dostępny wyłącznie wewnętrznie, a ewaluacje działały przy ograniczonych zabezpieczeniach. To dowód dotyczący tego środowiska ewaluacyjnego, a nie zmierzony współczynnik awarii publicznie wdrożonych agentów.
Lekcja inżynieryjna jest taka, że dozwolona usługa wewnętrzna może stać się ścieżką wychodzącą lub kanałem komunikacji między sesjami. Testuj, co mirror pakietów, proxy i współdzielony magazyn mogą zrobić w imieniu agenta, a nie tylko to, czy sandbox może otworzyć bezpośrednie połączenie z internetem. Osobne badanie METR analizowało zachowanie agentów i współpracę; ocena skuteczności zabezpieczeń i działań naprawczych nie należała do jego zakresu.
Asynchroniczna interwencja dostawcy
Monitorowanie misalignment firmy OpenAI może interweniować po wyjściu lub działaniach. W przypadku objętych nim modeli żądania Responses z utrwalonym reasoning, WebSockets lub kompresją OpenAI mogą być automatycznie zatrzymywane. Inne żądania Responses mogą generować alerty bez automatycznego zatrzymywania; Chat Completions znajduje się poza tym systemem. Webhook nie umożliwia blokowania.
Zablokowane żądanie zgłasza misalignment_policy_violation, a przed rozpoczęciem streamingu zwracany jest HTTP 403; błędy mogą również nadejść w trakcie streamingu. Zatrzymaj dalsze działania, zachowaj rekordy żądań i narzędzi oraz poproś operatora o przegląd. Nie ponawiaj automatycznie. Wcześniejsze skutki pozostają, a alerty mogą być omyłkowe lub mogą nie wykryć problemu. Jest to dodatkowe wykrywanie, a nie zamiennik lokalnej autoryzacji.
OWASP ASI Top 10, wydanie 2026
OWASP Agentic Security Initiative (ASI) to grupa robocza skupiona konkretnie na agentach sterowanych przez LLM. 9 grudnia 2025 r. opublikowała Agentic Security Initiative Top 10 for 2026 — katalog dziesięciu kategorii ryzyka dotyczącego bezpieczeństwa agentów.
Używaj go jako listy kontrolnej pokrycia modelu zagrożeń, a nie jako rankingu częstości incydentów:
Filtry treści mogą pomóc w wykrywaniu złośliwych instrukcji, w tym przejęcia celu i zatruwania pamięci. Kategorie częściowo się pokrywają: żadna z nich nie należy wyłącznie do filtra tekstu. Przypisz każdą ścieżkę ataku do odpowiednich kontroli tożsamości, polityki narzędzi, pamięci, orkiestracji, monitorowania i łańcucha dostaw. EchoLeak mapuje się na ASI01. Amazon Q mapuje się na ASI04 (Supply Chain) i ASI02 (Tool Misuse). Azure MCP to ASI03 (Identity). Claude Code CVE-2025-59536 obejmuje ASI05 (Code Execution), ASI04 i ASI03. Axios i Trivy to ASI04. To mapowanie pokazuje, dlaczego model zagrożeń musi wykraczać poza wejście i wyjście modelu.
Uprawnienia to infrastruktura, nie prompt
W tym miejscu guardrails przestają być produktem, a stają się jednym z podsystemów harnessu. Trzy obecne systemy — OpenAI Agents SDK, Codex CLI i Claude Code — pokazują, jak w praktyce wygląda powierzchnia polityki produkcyjnej. Wszystkie trzy egzekwują uprawnienia w kodzie. Żaden nie polega na ostrożności modelu.
OpenAI Agents SDK
SDK rozdziela harness od compute. Hostowane narzędzia MCP przyjmują require_approval — albo prosty ciąg "always" / "never", albo obiekt filtra z kluczami odpowiadającymi tym dwóm politykom i nazwami narzędzi, których każda z nich dotyczy — oraz callback on_approval_request uruchamiany dla każdego narzędzia pozostawionego przy "always", zwracający {"approve": bool} z opcjonalnym uzasadnieniem. Szczegółowe filtrowanie narzędzi (tool_filter) jest dostępne w wariantach serwera lokalnego (MCPServerStdio, MCPServerStreamableHttp, MCPServerSse), jeśli go potrzebujesz:
# No-run: illustrative Agents SDK shape; requires openai-agents, a configured hosted MCP server, and credentials.
from agents import Agent, HostedMCPTool
def approve(request):
# Only tools under the "always" policy reach this callback.
if request.data.name == "delete_repo":
return {"approve": False, "reason": "escalate to a human reviewer"}
return {"approve": True}
agent = Agent(
name="Ops",
tools=[HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "github",
"server_url": "https://mcp.example.com",
"require_approval": {
"always": {"tool_names": ["delete_repo"]},
"never": {"tool_names": ["list_issues"]},
},
},
on_approval_request=approve,
)],
)
Callback akceptacji jest kodem. Polityka akceptacji dla poszczególnych narzędzi jest kodem. Możesz przeczytać ten plik, przetestować go i porównać z inną wersją. Żadna z tych rzeczy nie jest prawdziwa w przypadku system promptu, który mówi: „zachowuj ostrożność w produkcji”.
Codex CLI i zarządzana warstwa polityk
Harness programistyczny OpenAI obsługuje zarządzany plik requirements.toml, który działy IT mogą rozpowszechniać za pomocą zarządzania urządzeniami. W systemach Unix plik systemowy znajduje się pod /etc/codex/requirements.toml. Działa jako warstwa twardych ograniczeń, dlatego ustawienia poziomu projektu nie mogą nadpisać jej reguł:
# /etc/codex/requirements.toml
[rules]
prefix_rules = [
{ pattern = [{ token = "rm" }, { any_of = ["-rf", "-fr"] }], decision = "forbidden", justification = "Recursive force-delete prohibited by IT policy" },
]
prefix_rules.decision akceptuje wyłącznie "prompt" lub "forbidden", nigdy "allow". Projekt nie może przyznać sobie uprawnienia, którego zabrania warstwa zarządzana. Allowliste MCP są indeksowane zarówno nazwą, jak i tożsamością, taką jak ciąg polecenia lub URL. Projekt nie może więc zadeklarować się jako github-mcp i wskazać serwera atakującego. Obsługiwane wymagania różnią się w zależności od klienta i wersji. Aktualna dokumentacja wymaga konkretnie Codex 0.138.0 lub nowszego dla zarządzanych kluczy profilu uprawnień, dlatego przed wdrożeniem przetestuj każdą politykę wymagań ze wszystkimi wersjami klienta w całej flocie.
Drabina uprawnień Claude Code
Claude Code nie publikuje jednej stałej sekwencji sześciu kontroli dla każdego wywołania narzędzia. Jego reguły uprawnień są oceniane deny → ask → allow; pierwsza pasująca reguła określa wynik. Hook PreToolUse uruchamia się przed promptem uprawnień. Hook może zablokować wywołanie, ale wynik hooka nie omija pasującej reguły deny ani ask. Aktywny tryb uprawnień obsługuje wywołania, których reguły nie rozstrzygnęły. Claude Agent SDK ma osobny callback canUseTool dla nierozstrzygniętych żądań. Ten callback jest kontrolą SDK, a nie kontrolą uprawnień CLI Claude Code.
Tryby przełącza się za pomocą default → acceptEdits → plan i Shift+Tab. auto, bypassPermissions i dontAsk aktywują się przy określonych warunkach wejściowych, które może zablokować warstwa polityki zarządzana przez przedsiębiorstwo. To coś więcej niż sprawdzanie poprawności pliku konfiguracyjnego. Jest to maszyna stanów z regułami pierwszeństwa, opublikowana tak, aby zespół bezpieczeństwa mógł ją analizować.
Trzy zasięgi rażenia w jednym pliku
Oto kształt konfiguracji uprawnień w stylu Codex z wartością domyślną i dwoma nazwanymi profilami:
# ~/.codex/config.toml
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[profiles.ci]
approval_policy = "never"
sandbox_mode = "read-only"
[profiles.release]
approval_policy = "untrusted"
sandbox_mode = "danger-full-access"
[mcp_servers.github]
command = "gh-mcp"
args = ["--readonly"]
Dwa klucze wykonują zasadniczą pracę i są niezależne. approval_policy decyduje, kiedy pytany jest człowiek. on-request pozwala agentowi eskalować, gdy napotka blokadę. never nie pyta o nic. untrusted zatrzymuje każde polecenie, którego nie ma na zaufanej liście. sandbox_mode decyduje, czego polecenie może dotknąć, jeśli zostanie uruchomione.
CI nigdy nikogo nie przerywa i nie może wykonywać zapisów. Release może uzyskać dostęp do całej maszyny, ale przedtem musi uzyskać akceptację człowieka dla niemal wszystkiego. Profil release płaci za ten zasięg: danger-full-access wyłącza sandbox, więc untrusted pozostaje jedyną kontrolą. Wszystko spoza zaufanej listy wymaga akceptacji człowieka albo nie zostaje uruchomione. Ta zaufana lista staje się teraz całą granicą bezpieczeństwa.
Profile domyślny i CI zachowują ochronę kernela: Seatbelt na macOS, bubblewrap i seccomp na Linuxie oraz ograniczone tokeny w systemie Windows. W żadnym przypadku opinia modelu nie ma znaczenia.
Egzekwowanie sandboxa to kwestia systemu operacyjnego
To kernel wykonuje tu rzeczywistą pracę. Każdy system operacyjny udostępnia inny zestaw narzędzi, a oba CLI nie zawsze sięgają po ten sam element:
| Platforma | Claude Code | Codex CLI |
|---|---|---|
| macOS | Seatbelt przez sandbox-exec z profilem SBPL (Seatbelt Profile Language) | Seatbelt przez sandbox-exec -p |
| Linux | bubblewrap + socat network proxy | bubblewrap + seccomp (starszy Landlock przez use_legacy_landlock) |
| Windows | Wymagany WSL2 | Natywne ograniczone tokeny + ACL przestrzeni roboczej + capability SID |
Tam, gdzie system operacyjny daje jedną opcję (Seatbelt, bubblewrap), rozwiązania są zgodne, a tam, gdzie jej nie daje — różnią się. Sandbox Claude Code wymaga WSL2 w systemie Windows; jest to ograniczenie sandboxa, a nie stwierdzenie, że CLI nie może działać natywnie. Codex dostarcza natywny sandbox Windows. W obu przypadkach egzekwowanie odbywa się w kernelu, a nie w modelu.
Ścieżka Linux w Codex nakłada trzy blokady na poziomie kernela wokół polecenia. PR_SET_NO_NEW_PRIVS uniemożliwia procesowi uzyskanie dodatkowych uprawnień, nawet jeśli spróbuje. Filtr seccomp sprawia, że kernel bezwarunkowo odrzuca całe klasy wywołań systemowych. Ograniczenia sieciowe zależą od tego, czy sieć jest wyłączona, czy skonfigurowano tryb proxy; nie są uniwersalnie ograniczone wyłącznie do socketów Unix. Zobacz implementację sandboxa Linux. Nowy izolowany /proc ukrywa resztę maszyny.
Codex wzmacnia również własny binarny plik podczas uruchamiania na każdej platformie Unix. Ustawia RLIMIT_CORE=0, aby wyłączyć zrzuty awarii, i odrzuca próby podłączenia debuggera. To inna granica niż sandbox.
Sandbox Windows ma dwa tryby. unelevated używa ograniczonego tokenu użytkownika i nie zapewnia egzekwowania sieciowego dostępnego w trybie podwyższonym. elevated korzysta z dedykowanych użytkowników sandboxa, reguł zapory i ACL systemu plików.
Gdy dostęp do sieci jest wyłączony, Codex umieszcza zastępcze pliki .bat i .cmd dla ssh i scp w katalogu znajdującym się na początku PATH. Polecenia te kończą się kodem różnym od zera, zamiast docierać do rzeczywistych binariów. Codex kieruje również HTTP_PROXY, HTTPS_PROXY, ALL_PROXY oraz zmienne proxy Git na nieużywany lokalny port. Środki te dotyczą narzędzi współpracujących; same zmienne proxy i stuby poleceń nie mogą ograniczyć dowolnej komunikacji sieciowej.
Sandbox musi mieć również zdefiniowany tryb awarii. W bieżącej konfiguracji Claude Code, sandbox.failIfUnavailable: true zatrzymuje wykonanie, gdy nie można uruchomić sandboxa. allowUnsandboxedCommands: false wyłącza nieobudowaną sandboxem ścieżkę ponowienia agenta, ale excludedCommands nadal ją omija. Przetestuj skuteczną konfigurację przy brakujących zależnościach i zabronionym miejscu docelowym.
Brokerowanie poświadczeń jest teraz dostępne również lokalnie. sandbox.credentials Claude Code może odrzucać nazwane pliki i zmienne środowiskowe. Maskowanie zmiennych środowiskowych, dostępne od wersji v2.1.199, przekazuje poleceniom działającym w sandboxie placeholder i pozwala proxy wstrzyknąć prawdziwą wartość do żądań kierowanych do skonfigurowanych hostów. Ustaw wąskie injectHosts i skonfiguruj terminację TLS; maskowanie nie autoryzuje żądanej operacji. Kontrole te obejmują komendy Bash działające w sandboxie, dlatego hooki, procesy MCP i inne ścieżki wykonawcze nadal wymagają własnej polityki poświadczeń.
Opcje izolacji poza Claude Code i Codex
Jeśli tworzysz własnego agenta, okazuje się, że „sandbox” to pojęcie zbiorcze. Opcje open source układają się na kontinuum — od lekkich wrapperów przestrzeni nazw po pełne microVM — a wybór zależy od tego, na ile ufasz kodowi uruchamianemu wewnątrz.
Lekka izolacja — ten sam kernel, mniej uprawnień:
- bubblewrap — niskopoziomowy konstruktor sandboxa przestrzeni nazw używany przez Flatpak i Claude Code na Linuxie. To wywołujący musi wybrać system plików, sieć i opcjonalną politykę seccomp; sam bubblewrap nie jest gotową polityką bezpieczeństwa.
- Standardowe kontenery Docker / OCI — izolacja przestrzeni nazw nad współdzielonym kernelem hosta. Nie są sandboxem dla niezaufanego kodu; własna dokumentacja gVisor wyraźnie to stwierdza („containers are not a sandbox”). Są rozsądnym punktem wyjścia w połączeniu z seccomp i AppArmor, ale niczym więcej.
Izolacja na poziomie aplikacji i kernela — agent rozmawia z fałszywym kernelem:
- gVisor — kernel działający w przestrzeni użytkownika, opracowany przez Google. Kontener sądzi, że działa na Linuxie, podczas gdy implementacja kernela w Go przechwytuje wywołania systemowe. Ogranicza to bezpośrednią ekspozycję na kernel hosta bez maszyny wirtualnej, kosztem kompatybilności i wydajności.
Pełna izolacja VM — dedykowany kernel dla każdego sandboxa:
- Firecracker — technologia microVM firmy AWS. Każda VM ma własny kernel Linux działający na KVM; kontenery współdzielą kernel hosta. Przejęcie jednej VM nadal musi przejść przez VMM lub kontrolę hosta, aby wpłynąć na hosta albo inną VM, dlatego Jailer Firecracker i załatany host pozostają częścią ochrony.
- Kata Containers — interfejs kontenerowy i izolacja klasy VM. To rozwiązanie dla klastrów Kubernetes, które muszą uruchamiać niezaufany kod.
Platformy — usługi, które można wynająć zamiast budować:
- E2B opakowuje Firecracker w hostowane API sandboxa.
- OpenSandbox oddziela SDK od izolacji runtime’u konfigurowanej przez administratora. Domyślny Docker runc nie jest microVM; jego ścieżka Firecracker korzysta z Kata z Firecracker przez Kubernetes.
- Agent Governance Toolkit firmy Microsoft (na licencji MIT, kwiecień 2026 r.) dodaje silnik polityk runtime’u. Mapuje kontrole polityk na OWASP ASI Top 10. Deklarowane opóźnienie uruchomienia dotyczy jednego silnika polityk, a nie całkowitego kosztu wszystkich kontroli wdrożonego agenta.
Wybierz poziom izolacji na podstawie poziomu zaufania do kodu, granicy między tenantami, dostępu sieciowego, danych hosta i kosztu odzyskiwania. Kontrole przestrzeni nazw i seccomp mogą pasować do zaufanych narzędzi wewnętrznych. Kod generowany przez LLM i niezaufane pakiety wymagają silniejszej granicy, takiej jak gVisor, Kata lub microVM, a następnie testów ścieżek ucieczki i eksfiltracji wynikających z własnego modelu zagrożeń.
Claude Code i Codex wybrały elementy z tego samego zestawu co wszyscy inni. Po prostu opakowały je inaczej.
Hooki PreToolUse jako programowalna polityka
Tryby i allowlisty obsługują proste przypadki: „pozwól agentowi edytować pliki, ale nie uruchamiać Basha”, „odrzuć wszystko, co wygląda jak rm -rf”. Zawodzą, gdy polityka wymaga rzeczywistej logiki. Chcesz blokować git push tylko wtedy, gdy branch to main. Chcesz odrzucać każdy Edit dotykający pliku pasującego do regexu sekretu. Chcesz ograniczać liczbę wywołań shella na sesję albo kierować każde wywołanie narzędzia do centralnego logu audytowego (SIEM — systemu zarządzania informacjami i zdarzeniami bezpieczeństwa, który obserwuje już twój zespół bezpieczeństwa).
Żadna z tych potrzeb nie mieści się w statycznej allowliście. Do tego służą hooki — polecenia shell uruchamiane przez Claude Code w określonych punktach cyklu życia wywołania narzędzia, z możliwością zbadania oczekującego wywołania i zwrócenia ustrukturyzowanej decyzji allow/deny. Claude Code udostępnia około trzydziestu zdarzeń cyklu życia (pełna lista znajduje się w dokumentacji), a jedno z nich zmienia znaczenie pozostałych: hook PreToolUse zwracający permissionDecision: "deny" blokuje narzędzie niezależnie od trybu.
Oto kształt ustawień:
{
"permissions": {
"defaultMode": "acceptEdits",
"deny": ["Bash(rm -rf:*)", "Bash(sudo:*)", "Read(.env*)"]
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/pre-bash-firewall.sh"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/protect-paths.sh"
}
]
}
]
}
}
Statyczne reguły deny i dynamiczne hooki mają różne tryby awarii. Wynik PreToolUse równy deny blokuje działanie przed zwykłym przepływem uprawnień, ale przekroczenie czasu przez hook command, HTTP lub MCP-tool jest nieblokujące: Claude Code kontynuuje przepływ. W tym przykładzie acceptEdits może więc zatwierdzić Edit lub Write, gdy protect-paths.sh przekroczy limit czasu. Nie uzależniaj niepodlegającego negocjacji ograniczenia ścieżki wyłącznie od hooka polecenia. Umieść statyczne ograniczenia w regułach deny lub sandboxie; dla polityki dynamicznej wybierz kontrolę, której awaria ewaluatora pozostaje restrykcyjna, i przetestuj zarówno zachowanie po przekroczeniu limitu, jak i jawne odrzucenie.
Hook może być pięcioliniowym skryptem shell albo pełnym silnikiem polityk. Liczy się kształt wyniku:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "writes outside workspace prohibited"
}
}
Model widzi ustrukturyzowane odrzucenie. Pętla rozumowania z Części 1 traktuje je tak jak każdą inną obserwację narzędzia: odmowa staje się kontekstem, agent planuje ponownie, a pętla działa dalej. To właśnie daje „uprawnienia to infrastruktura”. Odmowa jest podłączona do tego samego mechanizmu, który obsługuje kod 500 z narzędzia HTTP. Nie jest osobnym workflow bezpieczeństwa, który trzeba dopiero dołączyć.
Częstym antywzorcem jest napisanie system promptu: „nie usuwaj żadnych plików bez wyraźnego potwierdzenia użytkownika”, wdrożenie agenta i poleganie na tej instrukcji jako kontroli. Wstrzyknięty prompt lub wynik narzędzia kontrolowany przez atakującego może ominąć tę instrukcję. Model nie jest silnikiem polityk. Może dopasować się do wzorca, który napisałeś, albo do wzorca dostarczonego przez atakującego.
Akceptacja człowieka działa wyłącznie jako eskalacja
Filtry treści analizują to, co mówi model. Reguły uprawnień analizują wywołanie narzędzia przed jego wykonaniem. Human-in-the-loop obsługuje działania, które nadal wymagają udziału człowieka. Jeśli ludzie zatwierdzają 93% promptów, sprawdź reguły eskalacji i jakość promptów.
LangGraph dostarcza prymityw pauzy i wznowienia. HumanLayer opakowuje kanał akceptacji, a dane dotyczące użycia Anthropic pokazują, dlaczego należy mierzyć liczbę i jakość eskalacji.
Prymityw LangGraph
interrupt() + Command(resume=value) LangGraph wstrzymuje graf, utrwala jego stan za pomocą skonfigurowanego checkpointera i wznawia go z wartością dostarczoną przez człowieka. Bezpieczeństwo wznowienia zależy od jednego szczegółu w dokumentacji:
„Po wznowieniu wykonania (po dostarczeniu żądanego wejścia) runtime uruchamia cały node ponownie od początku — nie wznawia go dokładnie w miejscu, w którym wywołano
interrupt”.
Z tego zachowania wynikają trzy ograniczenia:
1. Skutki uboczne przed interrupt() muszą być idempotentne. Gdy człowiek odpowie, cały node uruchomi się ponownie od początku, a nie od linii interrupt(). Jeśli więc node wysyła e-mail, zatrzymuje się w celu uzyskania akceptacji, a następnie zwraca „sent”, po wznowieniu e-mail zostanie wysłany drugi raz. Naprawa: umieść skutki uboczne po przerwaniu albo spraw, aby bezpiecznie można je było powtórzyć (klucze deduplikacji, upsert zamiast insert, cache po message ID).
2. Przerwania są dopasowywane do wznowień po indeksie, a nie po nazwie. Jeśli jeden node zawiera dwa wywołania interrupt(), LangGraph dopasowuje je do wartości Command(resume=...) w kolejności, w której się pojawiły. Każde rozgałęzienie zmieniające liczbę wykonywanych przerwań (np. if pomijające jedno przy wznowieniu albo pętla wykonująca się inną liczbę razy) rozjeżdża indeksy, więc wartość wznowienia może trafić do niewłaściwego przerwania.
3. Payloady muszą być bezpieczne dla JSON. Dokumentacja LangGraph wymaga wartości serializowalnych do JSON dla interrupt() i payloadów wznowienia. Używaj stringów, liczb, wartości logicznych, tablic i słowników zawierających takie wartości. Unikaj funkcji, instancji klas i innych złożonych obiektów, ponieważ serializacja zależy od skonfigurowanego checkpointera. Konwertuj dane akceptacji do słowników i prymitywów przed przekazaniem ich do interrupt() lub udostępnieniem przez API HTTP.
Trzy kanoniczne wzorce:
# No-run: illustrative LangGraph sketches; requires LangGraph, a tool decorator, interrupt, and smtp_send.
# (a) Approval check
@tool
def send_email(to, subject, body):
resp = interrupt({"action": "send_email", "to": to,
"subject": subject, "body": body})
if resp.get("action") == "approve":
return smtp_send(to, subject, body)
return "Email cancelled"
# (b) Edit-and-continue
def review_node(state):
edited = interrupt({"content": state["generated_text"]})
return {"generated_text": edited}
# (c) Mid-run state correction — conditional edge
class AgeState(TypedDict):
age: int | None
pending_question: str | None
def get_age_node(state: AgeState):
question = state.get("pending_question") or "What is your age?"
answer = interrupt(question) # once per node invocation
if isinstance(answer, int) and answer > 0:
return {"age": answer, "pending_question": None}
return {"pending_question": f"'{answer}' is not valid. Please enter a positive number."}
def route_age(state: AgeState):
return END if state.get("age") is not None else "get_age"
builder = StateGraph(AgeState)
builder.add_node("get_age", get_age_node)
builder.add_edge(START, "get_age")
builder.add_conditional_edges("get_age", route_age)
Wznowienie ma postać graph.invoke(Command(resume={"action": "approve"}), config=cfg). LangGraph 0.4+ obsługuje wznowienie wielu przerwań w gałęziach równoległych za pomocą słownika, co ma znaczenie natychmiast po rozdzieleniu pracy przez agenta.
HumanLayer: akceptacja jako produkt
HumanLayer to zarządzana wersja tego samego pomysłu. Ozdabiasz funkcję dekoratorem, a żądania akceptacji trafiają do Slacka, e-maila lub Discorda zgodnie z regułami określającymi, kto ma zostać powiadomiony. Gdy agent próbuje wywołać multiply(2, 5), logi wyglądają tak:
last message led to 1 tool calls: [('multiply', '{"x":2,"y":5}')]
HumanLayer: waiting for approval for multiply
Osoba zatwierdzająca klika approve lub deny w Slacku. W przypadku odmowy dokumentacja HumanLayer ujmuje to tak: „HumanLayer przekaże informację zwrotną agentowi, który może następnie zmienić swoje podejście”. Taka informacja pozwala agentowi skorygować plan, zamiast traktować odrzucenie jako ślepą uliczkę.
Zmęczenie akceptacjami w danych
Anthropic opublikował rzeczywiste dane w lutym 2026 r. Trzy ustalenia są ważniejsze od pozostałych.
„Ustaliliśmy, że 80% wywołań narzędzi pochodzi od agentów, którzy wydają się mieć co najmniej jeden rodzaj zabezpieczenia (np. ograniczone uprawnienia lub wymaganie akceptacji człowieka), 73% wydaje się mieć w pewnym sensie human-in-the-loop, a tylko 0,8% działań wydaje się nieodwracalnych”.
To dobra wiadomość. Traktuj 80% jako górne ograniczenie, ponieważ przypis 14 Anthropic dodaje, że „Claude często zawyżał udział człowieka, dlatego oczekujemy, że 80% jest górną granicą”.
„Nowsi użytkownicy (<50 sesji) korzystają z pełnej automatycznej akceptacji mniej więcej w 20% przypadków; przy 750 sesjach odsetek ten rośnie do ponad 40% sesji”.
To właśnie dryf. Użytkownicy zaczynają ostrożnie, a gdy nabierają zaufania do narzędzia, stają się mniej ostrożni. Tak zachowują się ludzie i nie jest to wada charakteru. To sygnał telemetryczny, który system powinien śledzić. (Mała uwaga fact-checkingowa: materiały wtórne często cytowały to jako „20% → ponad 50%”. W podstawowych danych Anthropic potwierdzona wartość to 20% → ponad 40%. Jeśli widziałeś wartość 50%, stąd się wzięła.)
W marcowym wpisie inżynieryjnym z 2026 r. dotyczącym auto mode Claude Code Anthropic podał kluczową liczbę:
„Użytkownicy Claude Code akceptują 93% promptów uprawnień. Zbudowaliśmy klasyfikatory automatyzujące część decyzji, zwiększając bezpieczeństwo i ograniczając zmęczenie akceptacjami… Jeśli sesja zgromadzi 3 kolejne odmowy lub 20 odmów łącznie, zatrzymujemy model i eskalujemy do człowieka”.
Wysoki wskaźnik akceptacji uzasadnia sprawdzenie, czy prompty pomagają ludziom podejmować decyzje; nie dowodzi uniwersalnego progu awarii. Dwustopniowy klasyfikator Anthropic ogranicza liczbę promptów i eskaluje skupione odmowy. Zgłoszony współczynnik false positive wynoszący 0,4% oparto na 10 000 przykładów ruchu. Współczynniki false negative wynosiły 17% dla 52 rzeczywistych nadmiernie pochopnych działań i 5,7% dla 1000 syntetycznych przypadków eksfiltracji. Są to różne populacje, a nie uzupełniające się wartości procentowe ani dowód, że klasyfikacja zastępuje sandboxing.
Mierz jakość eskalacji
Umieszczaj rutynowe, odwracalne działania na allowliście i rejestruj je. Eskaluj działania, których skutki uboczne przekraczają granicę, której runtime nie może cofnąć, takie jak wiadomość zewnętrzna, zapis na produkcji, force push lub płatność. Anthropic przedstawia cel jako utrzymanie możliwości interwencji człowieka, gdy decyzja ma rzeczywiste konsekwencje.
Śledź cały lejek zamiast dążyć do zapożyczonego celu dotyczącego wskaźnika akceptacji: proponowane działania, automatyczne akceptacje, eskalacje, akceptacje, odmowy, edycje i incydenty po akceptacji. Wysoki wskaźnik akceptacji może oznaczać, że prompty są rutynowym szumem. Wysoki wskaźnik odmów lub edycji może oznaczać, że planner proponuje niewłaściwe działanie albo ukrywa informacje potrzebne osobie zatwierdzającej. Użyteczny próg zależy od klasy działania i kosztu false allow, dlatego ustalaj go na podstawie własnych danych dotyczących incydentów i przeglądów.
Zakres MCP i łańcuch dostaw
MCP łączy agentów z zewnętrznymi narzędziami, takimi jak Slack, GitHub i bazy danych, przez co jego model autoryzacji staje się częścią granicy bezpieczeństwa. Zmiany specyfikacji z 2025 r. rozdzieliły role wystawcy tokenu i serwera zasobów oraz dodały resource indicators. Ta historia wyjaśnia, jakie kontrole odbiorcy i przekazywania serwer musi dziś egzekwować.
Autoryzacja MCP w trzech rewizjach
Autoryzacja była opcjonalna dla implementacji MCP w specyfikacji 2025-03-26. W przypadku produkcyjnego wdrożenia HTTP chroniącego dane użytkownika lub narzędzia zalecam OAuth 2.1 z PKCE (Proof Key for Code Exchange), którego specyfikacja wymaga, gdy implementacja obsługuje autoryzację OAuth. Wczesny projekt pozwalał jednemu serwerowi MCP pełnić dwie role. Authorization server wystawia tokeny, a resource server je akceptuje. Są to odrębne role, nawet gdy jeden serwis realizuje obie. Jeśli serwis przekazuje żądanie innemu serwerowi, to samo poświadczenie może trafić tam, gdzie nie powinno. To właśnie luka.
Rewizja 2025-06-18 wyraźnie rozdzieliła role. Chroniony serwer MCP działa jako serwer zasobów OAuth, a serwer autoryzacji wystawia token. Serwer autoryzacji może być hostowany razem z serwerem zasobów albo osobno. RFC 8707 Resource Indicators wiążą token z docelowym zasobem, a RFC 9728 Protected Resource Metadata zapewnia klientowi jawną ścieżkę discovery. Specyfikacja zabrania również serwerowi MCP przekazywania tokenu klienta dalej.
Rewizja 2025-11-25 zachowała ten podział i dopracowała elementy, które klient musi poprawnie obsłużyć. Discovery serwera autoryzacji zyskał OpenID Connect Discovery, dzięki czemu klient może znaleźć właściwego issuera, zamiast zgadywać. Zgoda na przyrostowy zakres została przeniesiona do nagłówka WWW-Authenticate, co pozwala serwerowi poprosić o kolejny zakres dopiero w chwili, gdy go potrzebuje, zamiast żądać wszystkiego z góry. Rejestracja klienta zyskała OAuth Client ID Metadata Documents jako rekomendowany mechanizm, zastępujący dynamiczną rejestrację w większości wdrożeń. Discovery Protected Resource Metadata został również dostosowany do RFC 9728, dzięki czemu WWW-Authenticate jest opcjonalne, a fallbackiem jest .well-known.
Przed implementacją sprawdź stronę wersjonowania. Na dzień 6 września 2026 r. aktualna rewizja to 2026-07-28. Wymaga, aby każde żądanie deklarowało wersję protokołu, i pozwala serwerowi niezależnie akceptować lub odrzucać każde żądanie. Klient może wywołać server/discover, aby z góry wybrać wersję, ale discovery jest opcjonalne. Deklaracja dla każdego żądania i negocjacja pozostają wymagane, również wtedy, gdy klient obsługuje błąd nieobsługiwanej wersji i ponawia żądanie z wersją wspólnie obsługiwaną.
Powiązanie z odbiorcą ogranicza replay wobec niewłaściwego serwera MCP. Nie neutralizuje jednak osobnych podatności konfiguracyjnych Claude Code opisanych wyżej: hook po stronie hosta nadal może wykonać się przed uruchomieniem modelu, a niezaufany projekt nadal może próbować zmienić lokalną konfigurację. Zakres tokenu, zaufanie do projektu, polityka hooków i sandboxing pozostają odrębnymi kontrolami.
Lista kontrolna MCP na 2026 r.
Jeśli dostarczasz MCP lub korzystasz z niego na produkcji:
- Traktuj uwierzytelnianie jako wymaganie produkcyjne, a nie domyślne zachowanie protokołu. MCP pozostawia autoryzację opcjonalną, ale w chronionym wdrożeniu HTTP zalecam OAuth 2.1 z PKCE. Advisory dotyczące usługi Azure Web Apps MCP dotyczyło braku uwierzytelniania. Jeśli serwer akceptuje ruch bez weryfikowania poświadczeń wywołującego, zbudowałeś narzędzie, które może wywołać każdy, kto ma do niego dostęp.
- Tokeny są powiązane z odbiorcą. Zażądaj tokenu dla docelowego zasobu MCP i sprawdź, czy przedstawiony token wskazuje twój serwer jako odbiorcę. Odrzucaj tokeny wystawione dla innego zasobu.
- Celowo oddziel uprawnienia odczytu i zapisu. MCP wiąże token z serwerem zasobów, a nie z pojedynczym narzędziem. Jeśli serwer Slack akceptuje poświadczenie z
chat:writei kieruje je zarówno do handlerów odczytu, jak i zapisu, narzędzie przeznaczone do odczytu może stać się ścieżką wysyłania wiadomości przez politykę tego serwera. Używaj osobnych serwerów zasobów albo osobnych poświadczeń i kontroli autoryzacji, gdy operacje odczytu i zapisu wymagają niezależnych zasięgów rażenia. - Używaj świeżych tokenów o krótkim czasie życia zamiast stałych kluczy API. Wzorzec vaultu Claude Managed Agents (inżynieria Anthropic) jest punktem odniesienia: sam agent nigdy nie widzi prawdziwych poświadczeń. Proxy pobiera odpowiednie poświadczenia z vaultu, wywołuje narzędzie w imieniu agenta i zwraca wynik. Wystawianie nowego tokenu przy każdym wywołaniu nie jest udokumentowaną gwarancją; poświadczenia krótkotrwałe są rekomendacją wdrożeniową.
Nadal obowiązują kontrole łańcucha dostaw
Incydenty axios i Trivy to znane awarie łańcucha dostaw pakietów i CI zastosowane do systemów automatyzujących instalację zależności. Automatyzacja zwiększa liczbę i szybkość wykonań, dlatego kontrole wersji, proweniencji i przeglądu muszą działać, zanim wygenerowane polecenie dotrze do CI lub sandboxa.
Obrona jest prosta:
- Przypinaj wersje w lockfile. Agenci nigdy nie mogą rozwiązywać pływającej wersji — bez
@latest, beznpm updatei bez--upgrade. - Skanuj w CI za pomocą narzędzi niezależnych od sprawdzanego komponentu.
- Używaj commit SHA GitHub dla Actions, a nie tagów.
- Przeglądaj różnice zależności w PR-ach tworzonych przez agenta przed scaleniem.
Są to standardowe kontrole łańcucha dostaw. Automatyzacja agentowa zmienia ich częstotliwość, a nie mechanizm.
Stos polityk dla Market Analyst Agent
Market Analyst Agent z Części 1 to niewielki agent LangGraph, który pobiera dane rynkowe i zapisuje raport analityczny — choć opis ten nie oddaje jego pełnego zakresu. Oprócz narzędzi danych rynkowych uruchamia allowlistowane CLI przez subprocess, ocenia kod Python napisany przez model w procesie i tworzy symulowane rekordy transakcji. Ćwiczy wywoływanie narzędzi, wykonywanie kodu i routing akceptacji, ale nie składa rzeczywistych zleceń. Oto, jak wygląda minimalny stos polityk.
Warstwa 1: hook PreToolUse odrzucający przed wykonaniem
Nawet agent, który „tylko odczytuje dane akcji”, może sięgnąć po rzeczy, których nie powinien: curl do URL-a kontrolowanego przez atakującego, zapisy poza przestrzenią roboczą albo mutacje git w repozytorium hosta. Reguła deny to infrastruktura, nie prompt. Poniższy szkic zwraca własny kształt decyzji agenta, a nie opakowanie hookSpecificOutput oczekiwane przez Claude Code.
# agent/permissions.py
from pathlib import Path
DENY_COMMANDS = frozenset({
"rm -rf", "sudo", "chmod 777",
"curl -X POST", "wget", "nc ",
})
WORKSPACE = Path("./workspace").resolve()
def _outside_workspace(path: str) -> bool:
# Resolve first: "~/.ssh/id_rsa" and "workspace/../../etc" both
# have to become real paths before the comparison means anything.
return not Path(path).expanduser().resolve().is_relative_to(WORKSPACE)
def pre_tool_use(tool_name: str, args: dict) -> dict | None:
if tool_name == "shell":
cmd = args.get("command", "")
if any(bad in cmd for bad in DENY_COMMANDS):
return {"permissionDecision": "deny",
"reason": f"command pattern disallowed: {cmd!r}"}
if tool_name == "write_file":
path = args.get("path", "")
if _outside_workspace(path):
return {"permissionDecision": "deny",
"reason": f"path outside workspace: {path!r}"}
return None # fall through to mode / canUseTool
Szkic uwidacznia punkt kontroli. Hook zwraca ustrukturyzowane odrzucenie, a pętla rozumowania otrzymuje odmowę jako obserwację narzędzia.
Sprawdzanie ścieżki jest allowlistą: jeden katalog główny workspace, wszystko inne odrzucone. Deny-lista zabronionych prefiksów blokuje tylko ścieżki, o których pomyślałeś. ~/.ssh/id_rsa nigdy nie jest zapisane dokładnie tak, jak założyłeś. Sprawdzanie poleceń nadal jest deny-listą. Dopasowanie podciągu nie jest produkcyjną polityką shella. Rzeczywista implementacja powinna parsować polecenie i polegać na sandboxie systemowym na etapie wykonania. Szkic sam w sobie nie jest granicą wykonawczą: jeśli uruchamia go zewnętrzny hook, przekroczenie limitu czasu musi pozostawić niezależne ograniczenie workspace w mocy.
Warstwa 2: canary wejścia dla prompt injection
Przejęcie celu agenta (ASI01) często przychodzi przez wyszukaną stronę internetową, wiadomość użytkownika lub PDF z artykułem badawczym. Tani canary oparty na regexie wykrywa dosłowne wzorce instrukcji i tworzy użyteczne zdarzenie telemetryczne. Nie wykryje zaciemnionych, wielojęzycznych ani zależnych od kontekstu prób injection, dlatego nie może służyć jako granica decyzyjna:
# agent/input_canary.py
import re
INJECTION_PATTERNS = [
re.compile(r"ignore\s+(?:all\s+|any\s+|the\s+)?"
r"(?:previous\s+|prior\s+|above\s+|earlier\s+)?"
r"(?:instructions|rules|prompts?)",
re.IGNORECASE),
re.compile(r"you are now|act as|roleplay as", re.IGNORECASE),
re.compile(r"system[ _:]*prompt", re.IGNORECASE),
re.compile(r"<\|im_(start|end)\|>"),
]
def input_canary(text: str) -> dict | None:
for pat in INJECTION_PATTERNS:
m = pat.search(text)
if m:
return {"flag": "possible_injection", "match": m.group(0)}
return None
Rejestruj oznaczone wejścia, ale nie odrzucaj ich automatycznie. False positives są tu kosztowne dla asystenta badawczego. Log pozwala jednak zauważyć, że liczba flag nagle rośnie w przypadku jednego użytkownika.
Warstwa 3: walidacja ustrukturyzowanych danych wyjściowych przez hook stop
Model Pydantic wraz z hookiem Stop daje ścisłą pętlę validate-then-retry dla generowania raportu. Agent nie może oznaczyć działania jako „done”, dopóki dane wyjściowe nie przejdą walidacji schematu i smoke testu:
# No-run: illustrative policy sketch; requires Pydantic and the repo-local agent.schemas module.
# agent/stop_hook.py
from pydantic import ValidationError
from agent.schemas import MarketReport
def on_stop(final_output: str) -> dict:
try:
report = MarketReport.model_validate_json(final_output)
except ValidationError as e:
return {"decision": "continue",
"feedback": f"schema invalid: {e.errors()[:3]}"}
if not report.tickers:
return {"decision": "continue",
"feedback": "no tickers in report — did you skip the snapshot step?"}
return {"decision": "allow_stop"}
Sprawdzenie schematu i jeden smoke test odróżniają „agent powiedział, że skończył” od „wynik rzeczywiście jest raportem”.
Warstwa 4: akceptacja przed działaniami wychodzącymi
execute_trade Market Analyst to symulowana, idempotentna zmiana stanu, dlatego pokazuje routing akceptacji, a nie nieodwracalny skutek finansowy. W przypadku rzeczywistej integracji wychodzącej — e-maila, Slacka, raportu dla klienta lub zlecenia brokerskiego — pokaż człowiekowi proponowane działanie i poczekaj na akceptację albo odrzucenie, zanim narzędzie zostanie uruchomione. Użyj interrupt() do wstrzymania:
# No-run: illustrative outbound-tool sketch; requires LangGraph, a tool decorator, and smtp_send.
# agent/tools/notify.py
from langgraph.types import interrupt
@tool
def send_report(to: str, body: str):
resp = interrupt({
"action": "send_report",
"to": to,
"body": body, # Review the complete content that will execute.
})
if resp.get("action") == "approve":
return smtp_send(to, body)
return "send cancelled by human"
Działania wychodzące domykają lethal trifecta. Wymagaj akceptacji dla działań wychodzących, gdy istniejąca autoryzacja i polityka wdrożenia ich nie obejmują. Powiąż akceptację z pełnym miejscem docelowym i treścią; zmienione argumenty wymagają nowej decyzji. Wiadomości do działów finansowych, klientów lub innych zewnętrznych odbiorców powinny pokazywać osobie zatwierdzającej, co zostanie wysłane i dokąd.
Czego ten stos nie zapewnia
Nie jest to ochrona przed:
- Przejętą zależnością upstream (klasa axios). Agent uruchamia to, co mówi
uv sync. - Złośliwym
.mcp.jsonw sklonowanym repozytorium (klasa CVE-2025-59536). To model uprawnień klienta MCP hosta powinien to wychwycić, a nie kod agenta. - Łańcuchem kradzieży danych zbudowanym z legalnych narzędzi (klasa EchoLeak) — agent odczytuje prywatne dane, pobiera zewnętrzne URL-e i wysyła wiadomości na zewnątrz. Przerwij tę ścieżkę eksfiltracji lub ogranicz ją za pomocą zakresowego dostępu do danych, zaufanego routingu, ograniczeń egress i wymaganej akceptacji. Usunięcie jednej możliwości blokuje tę konkretną ścieżkę, a nie każdy możliwy atak.
- Ucieczką z
execute_python_analysis, ewaluatora Python działającego w procesie agenta. Blokuje on listę typów instrukcji, odrzuca każdy identyfikator zaczynający się od podkreślenia i pozwala importować wyłącznie zjson,mathorazstatistics. Jednakexecw procesie workera nie jest granicą: obejście działa z uchwytami plików i siecią workera. Przed ocenianiem niezaufanego kodu przenieś go za izolację systemu plików, sieci i poświadczeń oraz dodaj limity CPU, pamięci i czasu. Sam subprocess dziedziczy dostęp i nie jest sandboxem bezpieczeństwa.
Te cztery warstwy to polityka lokalna, a polityka lokalna jest najbardziej wewnętrzną warstwą, którą kontrolujesz — nie jedyną. Każdy element tej listy musi zostać przechwycony gdzie indziej: w lockfile, kliencie MCP, granicy procesu wokół generowanego kodu albo w kontrolach zapobiegających połączeniu niezaufanych instrukcji z prywatnymi danymi i miejscem eksfiltracji.
Najważniejsze wnioski
- Filtry treści i polityka wykonania chronią różne granice. Filtry analizują wejście i wyjście modelu. Autoryzacja narzędzi, zakres poświadczeń, sandboxy i kontrole łańcucha dostaw działają na ścieżkach wykorzystanych w siedmiu incydentach.
- Większość kategorii OWASP ASI wymaga kontroli poza wyjściem modelu. Użyj listy, aby przypisać każde zagrożenie komponentowi, który faktycznie może je zablokować lub zarejestrować.
- Uprawnienia to infrastruktura, nie prompt. Claude Code dokumentuje pierwszeństwo reguł deny, ask i allow, a
PreToolUsemoże blokować przed wykonaniem. Claude Agent SDK udostępnia osobną ścieżkęcanUseTool. Inne runtime’y potrzebują równie testowalnego modelu pierwszeństwa. - Ustrukturyzowane odrzucenie hooka PreToolUse traktuj jak każdą inną obserwację narzędzia. Pętla rozumowania już je obsługuje. Nie potrzebujesz osobnego workflow bezpieczeństwa.
- Wskaźnik akceptacji na poziomie 93% jest sygnałem do sprawdzenia jakości promptów i częstotliwości eskalacji. Śledź edycje, odmowy i incydenty po akceptacji, zamiast kopiować uniwersalny cel.
- Tokeny powiązane z odbiorcą i vaulty per sesja ograniczają replay oraz ekspozycję poświadczeń. Nie zastępują zaufania do projektu, polityki hooków ani sandboxingu.
- Kontrole łańcucha dostaw muszą działać z szybkością automatyzacji. Przypinaj wersje i SHA Actions, skanuj w CI oraz przeglądaj zmiany zależności w pull requestach tworzonych przez agenta.
- Buduj warstwę polityk tak, aby nowe wydanie produktu jej nie unieważniło. OpenAI Agents SDK, Codex CLI i Claude Code wyrażają te same prymitywy w różny sposób. Stawiasz na prymitywy — drabiny uprawnień, hooki, sandboxy, przerwania i tokeny powiązane z odbiorcą.
Następna warstwa to runtime
Część 5, Long-Running AI Agent Runtime, pokazuje, gdzie podczas długiego przebiegu znajdują się sandbox, broker sekretów, checkpoint i ślad audytowy. Część 6 przenosi się następnie do wnętrza harnessu, gdzie ta drabina uprawnień jest jednym z kilku etapów, i analizuje, jak kontrole akceptacji, ponowienia oraz ewaluacja oparta na trace’ach zapobiegają zbyt wczesnemu ogłoszeniu sukcesu przez pętlę. Dodaje także pytanie, którego ten artykuł nie musiał rozstrzygać: czy wywołanie, które przekroczyło limit czasu w trakcie działania, w ogóle można bezpiecznie wysłać ponownie.
Bibliografia
Ramy pojęciowe
- Bharani Subramaniam i Martin Fowler, Emerging Patterns in Building GenAI Products.
- Simon Willison, The lethal trifecta for AI agents, 16 czerwca 2025 r.
- Joel Fokou, Parallax: Why AI Agents That Think Must Never Act, arXiv 2604.12986, 14 kwietnia 2026 r. (bez recenzji naukowej).
- Alessandro Pignati, Your AI Agent Has Too Much Power: Understanding and Taming Excessive Agency, styczeń 2026 r.
Produkty guardrails dla LLM
- NVIDIA NeMo Guardrails
- Meta Llama Guard 4
- Guardrails AI
- Lakera Guard
- AWS Bedrock Guardrails
- Azure Content Safety: Prompt Shields
- openai-guardrails-python
Incydenty
- Itay Ravia (dawniej Aim Labs, obecnie Cato Networks), Breaking down EchoLeak (CVE-2025-32711).
- AWS, Amazon Q Developer VS Code v1.84.0 advisory (CVE-2025-8217).
- Microsoft, Azure MCP Server CVE record (CVE-2026-32211; referencja dostawcy: Microsoft).
- Check Point Research, RCE and API token exfiltration through Claude Code project files (CVE-2025-59536).
- axios, v1.14.1 / v0.30.4 compromise post-mortem.
- Aqua Security, Trivy Actions tag hijack (GHSA-69fq-xp46-6x23).
Powierzchnie polityk
- OpenAI Agents SDK — MCP tools docs
- Codex CLI managed configuration
- Claude Code permission modes
- Claude Code sandboxing
- Claude Managed Agents
HITL
- LangGraph interrupts docs
- HumanLayer Python quickstart
- Anthropic, Measuring AI agent autonomy in practice, 18 lutego 2026 r.
- Anthropic, Claude Code auto mode, 25 marca 2026 r.
- Jackson Wells (Galileo), How to Build Human-in-the-Loop Oversight for Production AI Agents, 21 grudnia 2025 r.
OWASP
- OWASP Agentic Security Initiative, Top 10 for Agentic Applications, 2026, 9 grudnia 2025 r.
Warstwa polityk Market Analyst Agent znajduje się w połączonym grafie analysis-to-trade repozytorium, a nie w grafie analizy wymienionym w Części 1. Zarządza symulowanym stanem transakcji: deterministyczny node guardian odrzuca działania ograniczone polityką, automatycznie akceptuje działania o niskiej wartości i eskaluje pozostałe do node’a compliance officer, zanim graf zakończy się wartością interrupt_before. Warstwa polityk znajduje się na GitHub. Hook deny, canary wejścia i walidator Stop-hook opisane wyżej są szkicami tych samych punktów kontroli. Zostały napisane do czytania, a nie do bezpośredniego wklejenia do tego repozytorium.