W jaki sposób publiczne pliki llms.txt umożliwiają badaczom uruchamianie kodu w dużych firmach
Badacze zarejestrowali nazwy nieodzyskanych pakietów, które oficjalne pliki llms.txt poleciały agentom sztucznej inteligencji zainstalować, a kod uruchomił się w dużych firmach w ciągu kilku minut. Dlaczego dane są teraz kodem.
Źródła: Data Became Code: We Ran Code Inside Fortune 500s Using Files They Published for AI Agents
Gdy opublikowany plik staje się zamówieniem
Zespół badający kwestie bezpieczeństwa poinformował, że maszyna w firmie z listy Fortune 500 uruchomiła kod, który zostali opublikowani, i że stało się to mniej więcej cztery minuty po udostępnieniu kodu. Kolejne dwa sygnały nadeszły w ciągu godziny. Według nich nikt nie wykorzystał luki CVE, nie przeprowadził ataku phishing na pracownika ani nie naruszył granic sieci. Badacze odnotowali kilka nazw oficjalnych plików dostępnych przez HTTPS, które same firmy udostępniały, a które już wskazywały agentom sztucznej inteligencji, jak je używać.
Pliki te były publiczne, a nazwy przypisane do nich nie zostały zgłoszone przez nikogo. Agenci robili dokładnie to, do czego zostały stworzone. Ten sam zespół twierdzi również, że podczas skanowania tych plików na dużą skalę natknął się na już aktywny atak: plik z instrukcjami dostarczony przez dostawcę, który kierował agenty na potwierdzony złośliwy kod. Ten przypadek zostanie omówiony poniżej.
Najpierw kilka informacji wstępnych.
Dlaczego llms.txt jest tu ważne
Przez większość historii internetu strona na stronie internetowej była po prostu stroną. Ktoś mógł ją przeczytać, a bot indeksujący mógł ją zaznaczyć w indeksie, ale nikt nie traktował jej jako polecenia. To już nie jest prawdą.
Firmy umieszczają teraz w korzeniu swoich stron nowy rodzaj pliku obok robots.txt: llms.txt, a czasami dłuższy plik llms-full.txt. Nie jest to mapa strony ani oświadczenie prawnicze. Funkcjonuje jako starannie opracowany zestaw wskazówek dla agentów sztucznej inteligencji, określający, co należy przeczytać, jakie API używać, jakie pakiety instalować i którym domenom ufać. Duże laboratoria zajmujące się modelami publikują własne takie pliki, a narzędzie Lighthouse w Chrome DevTools oferuje teraz audyt pod hasłem „agentic browsing”, który zachęca strony do ich dostarczenia. Liczba tych plików rośnie w jednym kierunku.
Zespół postanowił sprawdzić, jak szeroko rozprzestrzeniła się ta warstwa instrukcji. Ich statystyki wskazują na 8 565 plików llms.txt na 6 214 aktywnych domenach, wśród około 15 000 zarejestrowanych firm. Wśród tych, które te pliki publikują, znajdują się duże przedsiębiorstwa, giganci technologiczni, firmy z sektora fintech oraz podwykonawcy w branży obronnej.
Typowy plik kieruje agenta do dokumentacji, dziennika zmian oraz forum społecznościowego, a następnie do linii instalacyjnej – czegoś w rodzaju pip install dla SDK firmy. Treść pliku wydaje się pomocna i oficjalna, a pochodzi z domeny samej firmy przez protokół HTTPS. Agent do programowania oparty na AI, który ma zostać zintegrowany z tym produktem, odczyta tę linię i ją uruchomi.
Kolejne pytanie było niemal żenująco proste: kto tak naprawdę posiada to nazwisko pakietu na PyPI? W każdym przypadku odpowiedź brzmiała „nikt”. Nazwa znajdowała się w oficjalnym pliku pierwszej strony, a pakiet, na który wskazywała, nigdy nie został zgłoszony jako własny. Kto pierwszy, ten lepszy.
Naukowcy sprawdzili kilka kolejnych plików, potem setki, a następnie większość z nich i wszędzie widzieli to samo. Instrukcje instalacyjne wymieniały nazwy pakietów i domen, których nikt nie zarejestrował. Ich zdaniem nie były one „potencjalnie podatne na ataki”, a jedynie dostępne. To też nie jest typosquatting – nazwy w plikach są poprawnie zapisane, więc nie ma błędów pisowni, które można by wykryć, ponieważ rejestracje nigdy nie miały miejsca.
Jak kod trafił do pracy w dużych firmach
Zespół wybrał niewielką liczbę nazw pakietów, które pojawiły się w plikach llms.txt znanych firm, i zarejestrował je na PyPI oraz npm. Każdy pakiet zawierał nieszkodliwy mechanizm powrotu, minimalny sygnał informujący o zainstalowaniu się oprogramowania w infrastrukturze kontrolowanej przez badaczy. Następnie czekali.
Pierwszy sygnał powrotu nadszedł w ciągu niecałych czterech minut. Mianowicie, gdzieś w firmie o wartości kilkuset miliardów dolarów agent AI przeczytał plik llms.txt na stronie firmy, znalazł linijkę pip install i ją uruchomił. Pakiet pochodził z PyPI, jak wskazywał plik, chociaż był to pakiet badaczy. Drugi sygnał powrotu od firmy z listy Fortune 500 nadszedł w ciągu godziny, a kilkadziesiąt kolejnych pochodziło zarówno od startupów, jak i dużych przedsiębiorstw – niektóre z tych firm miały zespoły bezpieczeństwa większe od całej profesjonalnej sieci badaczy.
Ich streszczenie brzmi tak, że nie przełamali żadnych zabezpieczeń, lecz wykorzystali lukę w łańcuchu zaufania.
Jak agenci samodzielnie znajdują te pliki
Następnie w eksperymencie sprawdzano, jak mało wsparcia jest potrzebne. Badacze przetestowali pięć różnych konfiguracji na dwóch agentowych interfejsach CLI, podając każdemu tę samą zdanie 100 razy i nie umieszczając w nim nic poza nazwą dostawcy. Zdanie to prosiło agenta o wykorzystanie wszystkich dokumentów tego dostawcy do stworzenia i uruchomienia projektu Node.js z jego SDK.
To było całe polecenie. Nie zawierało żadnego URL, żadnego linku do dokumentacji ani wzmianki o llms.txt. Nie było żadnej iniekcji poleceń, żadnego atakującego w procesie ani żadnej sztuki inżynierii społecznej. Agent samodzielnie odnalazł kanał instrukcji, ponieważ właśnie do tego został stworzony – do wyszukiwania oficjalnej dokumentacji dostawcy. Zespół sprawdził, ile z 100 prób na każdą konfigurację trafiło do llms.txt, zobaczył tam odpowiednią komendę i zainstalował pakiet, którego nikt wcześniej nie zarejestrował.
Pakiety te były projektowane jako bezpieczne, pełniące jedynie funkcję sygnału. Wszystko do tego momentu stanowiło kontrolowane badania. To, co nastąpiło później, to odrębny incydent odkryty podczas analizy korpusu.
Przypadek już występujący w praktyce
Jedno odkrycie zatrzymało zespół w miejscu, ponieważ to już się działo.
Clerk, dostawca rozwiązań do autoryzacji, którego SDK-y są używane w dużej liczbie aplikacji Next.js w środowisku produkcyjnym, publikuje dokumentację napisaną dla agentów AI. Agent, który podąża tym tropem, trafia do dokumentacji Clerk’a llms.txt zawierającej rozwiązania dotyczące ochrony autoryzacji, w której znajduje się następujący polecenie:
npx clerk-next-fix-auth-protection
Agent czyta to i je wykonuje, co w przypadku instrukcji pochodzących bezpośrednio od dostawcy nie jest zaskakujące.
Problemem nie jest błędnie napisana nazwa pakietu. Samo polecenie clerk-next-fix-auth-protection to plik binarny dostarczany w ramach pakietu Clerk o nazwie @clerk/eslint-plugin. W dokumentacji zaleca się, aby agenci najpierw zainstalowali ten pakiet, a dopiero potem uruchomili dane polecenie. Jeśli jednak polecenie zostanie wywołane przed zainstalowaniem pakietu lokalnie, npx szuka jego nazwy w publicznym rejestrze npm, gdzie Clerk nigdy nie opublikował go jako odrębnego pakietu.
Ktoś inny go zarejestrował zamiast niego. Zgodnie z opisem badaczy pakiet nie zawiera kodu funkcyjnego, ale po zainstalowaniu uruchamia mechanizmy, które przy każdej instalacji wysyłają nazwę użytkownika instalatora, nazwę komputera, katalog roboczy oraz datę i godzinę na zewnętrzny serwer. Został sklasyfikowany jako MAL-2026-11069 w ramach CWE-506, czyli wbudowanego złośliwego kodu, i został zidentyfikowany przez narzędzia OSV.dev firmy Google oraz Amazon Inspector. Dokumentacja, otwarta ścieżka wykonywania oraz bezpośrednie uruchomienie byłyby identyczne, niezależnie od tego, czy „payload” pobrałby nazwę użytkownika, czy zainstalował pełny backdoor. Mechanizmem rozprzestrzeniania się jest sama luka bezpieczeństwa, a „payload” stanowi jedynie opcję wyboru.
Badanie zostało przekazane zespołowi ds. bezpieczeństwa Clerk, który szybko zareagował i naprawił problem. W tekście podkreśla się, że nie jest to krytyka wobec Clerk. Pakiet zarejestrowała strona trzecia, wykorzystując zamieszanie związane z nazwą npx, a Clerk nie miał nad tym kontroli. Zespół przedstawia to jako potwierdzone, rzeczywiste przykład problemu strukturalnego dotyczącego każdego dostawcy publikującego dokumentację czytelną dla agentów.
Dlaczego obecne mechanizmy kontroli mogą tego nie zauważyć
Każdy sygnał, od którego zależy konfiguracja bezpieczeństwa, w tym przypadku wskazuje w niewłażnym kierunku. Agent, który napotka plik llms.txt, widzi plik udostępniany przez HTTPS z oficjalnego domeny, w standardowym formacie przeznaczonym do wykorzystania przez sztuczną inteligencję, opublikowany przez firmę lub jej zaufanego partnera. Agent ma niewiele powodów, by w to wątpić, ponieważ plik ten jest z definicji autorytetem.
Gdy plik poleca zainstalowanie narzędzia o wyglądzie wewnętrznym, agent nie zatrzymuje się, by sprawdzić, czy nazwa należy do firmy. Nie bada przestrzeni nazw PyPI i nie zauważa, że link do dokumentacji prowadzi na domenę, której rejestracja wygasła trzy miesiące temu. Robi to, co mówi plik.
Zaufanie jest również transytywne. Plik llms.txt nie musi znajdować się na stronie docelowej firmy. Agenci czerpią kontekst od zaufanych stron trzecich, takich jak dokumentacja partnera, referencje SDK dostawcy lub strona konfiguracyjna projektu społecznościowego. Jeśli agent ufa tej stronie trzeciej, a plik tej strony wskazuje na nieodebrany pakiet, łańcuch działa w ten sam sposób.
Detekcja punktów końcowych również nie dała żadnego sygnału. Dla narzędzia EDR lub proxy wygląda to tak, jakby programista używał legalnego menedżera pakietów: pip install skierowany do pypi.org, domeny dozwolonej przez każdy korporacyjny proxy, przy czym procesem nadrzędnym jest agent programistyczny umieszczony tam celowo przez firmę. Nie ma żadnej anomalii ani ostrzeżenia. Problem leży wyżej, w przerwie między instrukcją a jej wykonaniem, a punkt końcowy nie może go wykryć, ponieważ nigdy nie zostało mu postawione właściwe pytanie.
Dane przekształcone w kod
Przez dziesięciolecia treści były konsumowane przez ludzi. Teraz to agenci AI najczęściej są pierwszymi, którzy je czytają, interpretują i na ich podstawie działają. To właśnie błąd kategorialny, w który wszyscy razem wpadliśmy: granica pomiędzy danymi a kodem zniknęła. Wszystko, co znajduje się na twojej stronie internetowej, to już nie tylko treść – to dane wejściowe do procesów operacyjnych, w zasadzie kod uruchamiany w środowisku kogoś innego z uprawnieniami przypisanymi temu agentowi.
To obala stare założenie. Strony i dokumenty były wcześniej uważane za o niskim ryzyku z definicji, ponieważ nikt nie traktował ich jako kodu wykonywalnego, więc nikt nie przewidywał kosztów związanych z ich integralnością. Gdy dane stają się kodem, integralność danych staje się elementem budżetu bezpieczeństwa.
llms.txt to nie cała powierzchnia ataku. To pierwsza szczelina wskazująca, że coś się zmieniło. Każda powierzchnia, do której podłączony jest agent, staje się miejscem, gdzie mogą przychodzić instrukcje, a żadne z tych miejsc nie zostało zaprojektowane z myślą o weryfikacji integralności.
Rozważmy, co tak naprawdę odbiera agent: oficjalne repozytoria na GitHubie, dokumentację, społeczności i fora, twoje zgłoszenia oraz e-maile. Przez dwadzieścia lat były to treści napisane dla ludzi, a nikt nie wdrożył wokół nich mechanizmów kontroli integralności, ponieważ treści same w sobie nic nie mogły zrobić. Ten świat zniknął. Cały zbiór danych, którymi obsługują się agenci, w ciszy stał się powierzchnią wykonywania poleceń.
Prawdziwym problemem nie jest ani jeden plik, ani jeden rejestr. Same dane zmieniły swój charakter, a branża bezpieczeństwa wciąż nadąża za tymi zmianami.
Liczby stojące za badaniami
- Rozmiar korpusu: 8 565 plików llms.txt pochodzących z 6 214 aktywnych domen, wybranych z listy około 15 000 firm.
- Ponad 237 nieodebranych zasobów oznaczonych jako instrukcje instalacji lub konfiguracji: nazwy pakietów, domeny i poddomeny. Każdy z nich to coś, co, według badaczy, można było odebrać, przy czym większość dostępna była bezpłatnie.
- Zachwiane zostały sześć ekosystemów: PyPI, npm, RubyGems, NuGet, crates.io i Packagist. W obszarze domen dotknęto wygasłych nazw .dev i .io oraz opuszczonych poddomen na platformach Render, Vercel, Fly i Netlify – wszystkie były dostępne do przejęcia.
Co mogą z tego wyciągnąć obrońcy
Badacze określają llms.txt jako zaledwie pierwszy element, który przeanalizowali, i spodziewają się odkrycia kolejnych sposobów awarii. Z ich raportu wynikają następujące praktyczne wnioski:
- Zbadaj własne pliki przeznaczone dla agentów. Każda nazwa pakietu, domena oraz poddomena, o których mowa, powinny być zarejestrowane, należeć do kogoś i być monitorowane.
- Wykonuj polecenia z dokumentacji, używając nazwy pakietu w określonym kontekście. Nazwa binarna bez dodatkowych informacji może zostać rozwiązana w publicznym rejestrze, jeśli nie doszło do lokalnej instalacji.
- Traktuj dokumentację stron trzecich, którą korzystają twoi agenci, jako część łańcucha dostaw, ponieważ zaufanie przenosi się przez nie.
- Pamiętaj, że standardowe narzędzia do obsługi punktów końcowych widzą tylko normalną instalację pakietu i nie zaznaczają jej jako problematycznej, dlatego kontrole muszą odbywać się wcześniej, na etapie wydawania instrukcji i wyszukiwania w rejestrze.
Zgodnie z oświadczeniem, w ramach eksperymentu nie doszło do żadnych szkód. Nie zainstalowano żadnych elementów utrzymujących dane, nie wybrano żadnych informacji, a wyniki są odpowiedzialnie przekazywane dotkniętym organizacjom, przy czym nazwy firm są utrzymywane w tajemnicy dopóki trwa naprawa.
Powiązane materiały
- Tworzenie agenta asystenta wiedzy w Databricks przy użyciu LangGraph — Krok po kroku budowanie agenta LangGraph w Databricks: minimalny agent, Vector Search RAG, mechanizm checkpointing w Lakebase do przechowywania krótkoterminowej pamięci oraz magazyn do przechowywania długoterminowej pamięci.
- Lokalna baza danych z rezerwum w formacie RAG przy użyciu Docling, PostgreSQL pgvector i Ollama — Przekształcenie folderu z rezerwum w formacie PDF i DOCX w bazę danych kandydatów nadającą się do wyszukiwania: funkcja dzielenia na fragmenty w Docling, PostgreSQL z modułem pgvector, lokalne modele Ollama oraz interfejs Streamlit.