W miarę jak duże modele językowe (LLM) generują coraz więcej działającego kodu i są integrowane z procesami rozwoju i stosami agentów, rośnie ryzyko, że ukrytego or złośliwy instrukcje — niezależnie od tego, czy są osadzone w wynikach modelu, wstrzykiwane za pośrednictwem stron internetowych lub wtyczek stron trzecich, czy wprowadzane podczas trenowania modelu — mogą powodować niebezpieczne zachowanie podczas wykonywania tego kodu.
Według raportów użytkowników krążących w społecznościach programistów, pewien programista oprogramowania doświadczył katastrofalnej utraty danych — około Usunięto 800 GB plików, W tym cała aplikacja CursorAI — po wykonaniu kodu wygenerowanego przy pomocy Gemini 3 podczas pracy wewnątrz CursorAI IDEPonieważ programiści coraz częściej polegają na modelach LLM przy generowaniu kodu, konsekwencje nieprzejrzanych lub niebezpiecznych skryptów stają się coraz poważniejsze.
Dlatego też niezwykle istotna jest wiedza na temat wykrywania i usuwania niebezpiecznych kodów generowanych przez LLM.
Czym jest „ukryty kod” w kontekście ChatGPT i LLM?
Co ludzie mają na myśli mówiąc o „ukrytym kodzie”?
„Ukryty kod” to ogólny termin używany przez programistów do opisania wszelkich osadzonych instrukcji lub wykonywalnej zawartości w tekście (lub plikach), które LLM pobiera lub emituje, w tym:
- Instrukcje w formie komunikatów osadzone w treści użytkownika (np. „Zignoruj wcześniejsze instrukcje…” ukryte w pliku PDF).
- Niewidzialne postacie lub spacje o zerowej szerokości, służące do ukrywania tokenów lub łamania założeń tokenizacji.
- Zakodowane ładunki (base64, kodowanie URL, osadzenia steganograficzne wewnątrz obrazów lub dokumentów).
- Ukryty HTML/JS lub bloków skryptów zawartych w sformatowanej zawartości, które mogą zostać zinterpretowane przez renderery niższego rzędu.
- Metadane lub adnotacje (komentarze do plików, ukryte warstwy w plikach PDF), które instruują systemy wyszukiwania lub model.
- Zachowania ukryte wynikające z wygenerowanego kodu, który wykorzystuje niebezpieczne interfejsy API (np.
eval,exec,subprocesslub wywołania sieciowe/systemowe) — nawet jeśli intencja nie jest jawnie złośliwa. - Instrukcje wstrzykiwane podpowiedziami powodujące, że model generuje kod zawierający ukryte polecenia lub logikę przypominającą tylne drzwi, ponieważ atakujący zmodyfikował monit lub kontekst.
Te wektory ataku są często nazywane szybki wtrysk or pośrednia natychmiastowa iniekcja gdy celem jest zmiana zachowania modelu. Społeczność zajmująca się bezpieczeństwem traktuje obecnie szybkie wstrzykiwanie jako podstawową lukę w zabezpieczeniach LLM, a OWASP sformalizowało ją jako kategorię ryzyka LLM.
Czym to się różni od zwykłego złośliwego oprogramowania lub XSS?
Różnica polega na semantyczny Warstwa: atak typu instant injection atakuje zachowanie modelu w zakresie wykonywania instrukcji, a nie system operacyjny hosta lub silnik renderujący przeglądarki. Niemniej jednak, ukryty kod HTML lub skrypt, który ostatecznie uruchamia się w rendererze internetowym, nadal stanowi atak wykonywalny (podobny do XSS); zarówno warstwa semantyczna, jak i warstwa wykonania wymagają obrony. Liderzy branży i badacze określili atak instant injection mianem „pionierskiego wyzwania bezpieczeństwa” i nadal publikują strategie minimalizowania ryzyka.
Dlaczego LLM może generować ukryty lub niebezpieczny kod?
Zachowanie modelu, dane szkoleniowe i kontekst instrukcji
Modele LLM są trenowane w celu generowania wiarygodnych kontynuacji w kontekście i z uwzględnieniem instrukcji. Jeśli kontekst zawiera wskazówki antagonistyczne lub jeśli użytkownik poprosi model o kod wykonujący konkretne działania, model może wygenerować kod zawierający subtelne lub aktywne zachowanie.
LLM-y generują wiarygodny, ale niebezpieczny kod
LLM-y są zoptymalizowane pod kątem płynności i użyteczności, a nie bezpieczeństwa w przypadku wystąpienia szkodliwych skutków ubocznych. Chętnie wygenerują zwięzły rm -rf /path/to/dir or shutil.rmtree() dzwonią, gdy proszą o „posprzątanie” – a ponieważ ich odpowiedzi są często formułowane pewnie, użytkownicy mogą kopiować i publikować bez wystarczającej kontroli. Ten problem „pewnej halucynacji” sprawia, że pozornie niegroźne prośby stają się niebezpieczne.
Automatyzacja przepływów pracy zaciemniania
Aktorzy zagrożeń automatyzują obecnie zaciemnianie kodu poprzez łączenie wywołań LLM: jeden model generuje ładunek, inny go przerabia, aby uniknąć wykrycia sygnatur, i tak dalej. Raporty dotyczące zagrożeń branżowych i analizy dostawców z 2025 roku dokumentują tę „zaciemnianie wspomagane sztuczną inteligencją” jako nową technikę.
Jak można wykryć ukryty kod w wynikach modelu?
Szybka lista kontrolna triażu
- Skanuj w poszukiwaniu niewidocznego/nietypowego kodu Unicode (łączniki zerowej szerokości, spacje zerowej szerokości, znaczniki kolejności bajtów, homoglify spoza zestawu ASCII).
- Uruchom analizę statyczną/analizę AST aby zidentyfikować użycie potężnych interfejsów API (
eval,exec,subprocess,os.system, rozmowy refleksyjne). - Szukaj zakodowanych ładunków (base64, bloby heksadecymalne, powtarzające się długie ciągi znaków lub skompresowana zawartość).
- Sprawdź wzorce zaciemniania (łączenie ciągów znaków tworzące nazwy API, arytmetyka znaków,
chr()więzy). - Użyj analizy semantycznej aby potwierdzić, czy kod faktycznie wykonuje operacje wejścia/wyjścia, sieciowe lub mutację systemu plików.
Wykrywanie wzorców statycznych (szybkie, pierwsza linia)
- Analiza składniowa i linting uwzględniający język. Natychmiast analizuj wygenerowane dane wyjściowe na bloki kodu, a nie na prozę. Uruchom formatery i lintery (Black/Prettier, pylint, eslint). Reguły lintera powinny sygnalizować użycie
eval,exec,rm -rf, surowe wywołania podprocesów lub potoki powłoki, które konstruują polecenia dynamicznie. - Skanery wzorców tokenów i ciągów znaków. Wyszukaj tokeny i wzorce wysokiego ryzyka:
sudo, ścieżki absolutne takie jak/home/,C:\,rm -rf,shutil.rmtree,subprocess.Popen, wbudowane bloby base64, długie, niemożliwe do zinterpretowania ciągi znaków oraz manipulacje zmieniające kontekst interpretatora. - Tajne skanowanie i sprawdzanie pochodzenia. Wykrywaj zakodowane na stałe dane uwierzytelniające, adresy URL wskazujące na niezaufane rejestry lub kod, który dynamicznie pobiera pakiety z dowolnych źródeł.
Analiza statyczna pozwala szybko wykryć wiele oczywistych problemów, a jej wykorzystanie jako elementu bramki CI jest tanie.
Wykrywanie semantyczne i kontekstowe (głębsze)
- Analiza intencji. Użyj modelu wtórnego lub silnika reguł, aby sklasyfikować intencję wygenerowanego kodu: czy jest to „odczyt”, „zapis”, „usuwanie”, „sieć”, „instalacja”? Każda czynność sklasyfikowana jako „usuwanie/zapis” powinna wywołać eskalację.
- Analiza przepływu danych. Przeanalizuj kod, aby sprawdzić, czy niezweryfikowane lub podane przez użytkownika ścieżki mogą prowadzić do destrukcyjnych interfejsów API. Na przykład, jeśli zmienna pochodząca z danych wyjściowych LLM lub pliku zdalnego zostanie później scalona z poleceniem powłoki, zgłoś to.
- Korelacja pochodzenia. Zachowaj pełny zapis konwersacji, komunikatów systemowych i stron kontekstowych. Jeśli podejrzane wyniki korelują z konkretnym dokumentem zewnętrznym lub wywołaniem wtyczki, może to wskazywać na wstrzyknięcie komunikatu lub skażony kontekst.
Wykrywanie dynamiczne i behawioralne (najbardziej niezawodne)
- Wykonanie w trybie sandbox z monitorowaniem. Wykonuj wygenerowany kod w ściśle ograniczonym, efemerycznym środowisku bez sieci, montowania hostów i filtrowania wywołań systemowych (seccomp). Monitoruj aktywność systemu plików, próby wywołań sieciowych, tworzenie procesów i nietypowe operacje wejścia/wyjścia.
- Testowanie kanarka. Przed uruchomieniem kodu na rzeczywistych danych należy uruchomić go w syntetycznych katalogach, które zawierają pliki strażnicze; należy monitorować go pod kątem usunięć lub nadpisań.
- Heurystyka behawioralna. Szukaj pętli przechodzących przez katalogi nadrzędne, operacji rekurencyjnych bez kontroli głębokości lub wzorców zmiany nazw, które mogą uszkodzić wiele plików (np. wielokrotne zapisywanie tej samej nazwy pliku).
Analiza dynamiczna jest jedyną metodą wykrywania ładunków, które są zaciemnione, opóźnione lub wyzwalane dopiero w czasie wykonywania.
Jak należy usuwać lub neutralizować ukryty kod przed wykonaniem wyników LLM?
Defensywne usuwanie kontra zmiana semantyki
Usuwanie ukrytego kodu ma dwa cele:
- Odkażanie — usuń treści, które ewidentnie nie są kodem lub są podejrzane (niewidoczny Unicode, znaki o zerowej szerokości, dodane ładunki base64). Nie powinno to zmienić zamierzonej, nieszkodliwej logiki.
- Neutralizacja — w przypadku wszelkich czynności, które wykonują lub wywołują usługi zewnętrzne, należy wyłączyć te wywołania lub ustawić je jako no-op do czasu weryfikacji.
Zawsze preferuj neutralizacja + przegląd Nadmierne usuwanie bez powodu: arbitralne usuwanie fragmentów kodu może prowadzić do wadliwego lub nieoczekiwanego działania. Zamiast tego należy zastąpić podejrzane konstrukcje jawnymi, zarejestrowanymi szczątkami, które bezpiecznie zawiodą (zgłoszą wyjątki lub zwrócą bezpieczne wartości domyślne).
Krok 1 — Traktuj wygenerowany kod jako dane niegodne zaufania
Nigdy nie uruchamiaj kodu bezpośrednio z ChatGPT (ani żadnego LLM) bez przepuszczenia go przez proces usuwania i wzmacniania. Proces ten powinien być egzekwowany przez politykę i zautomatyzowany w ramach CI/CD.
Krok 2 — Wyodrębnij i zkanalizuj kod
- Normalizuj tekst i usuń znaki o zerowej szerokości: Usuń znaki takie jak U+200B, U+200C, U+200D, U+FEFF i inne punkty kodowe o zerowej szerokości/formatujące. Rejestruj usunięte znaki do audytu. Ten krok eliminuje wiele „ukrytych” kodowań używanych do ukrywania się pod względem wizualnym.
- Usuń cały kontekst niebędący kodem: usuń narrację, ukryte komentarze i wszelkie wrappery HTML/Markdown. Konwertuj kod do postaci kanonicznej za pomocą formaterów języka (Black, Prettier), aby zaciemnione spacje lub znaki kontrolne zostały znormalizowane.
- Odrzuć lub poddaj kwarantannie kod za pomocą tych konstrukcji:dynamiczny
eval, surowe wywołania podprocesów (os.system,subprocess.Popen), wbudowane bloby base64 dekodowane do wykonania lub osadzone#!dyrektywy próbujące zmienić kontekst interpretatora. Normalizuj tekst i usuń znaki o zerowej szerokości
Usuń znaki takie jak U+200B, U+200C, U+200D, U+FEFF i inne punkty kodowe o zerowej szerokości/formatujące. Rejestruj usunięte znaki do audytu. Ten krok eliminuje wiele „ukrytych” kodowań używanych do ukrywania się pod względem wizualnym.
Krok 3 — Przeprowadź analizę w AST i zastąp ryzykowne węzły
Po przeanalizowaniu kodu do AST znajdź węzły wywołujące dynamiczne wykonywanie (np. exec) lub programowo budujących nazwy funkcji. Zastąp je bezpiecznymi stubami, które generują kontrolowany wyjątek wskazujący na „zablokowanie niebezpiecznego dynamicznego zachowania”. Wygeneruj oczyszczoną kopię źródła opartego na AST do przeglądu. Uruchom sprawdzanie wzorców bezpieczeństwa (niestandardowe reguły semgrep dla Twojego środowiska). W przypadku znalezienia pasujących elementów zaznacz je i zneutralizuj.
Krok 4 — Utwardzanie statyczne i ponowne zapisywanie
- Automatyczne przepisywanie:przekaż kod przez automatyczny program czyszczący, który zastępuje niebezpieczne połączenia bezpiecznymi opakowaniami — np. zastąp
os.system()/subprocessz zatwierdzonym wykonawcą w trybie sandbox, który wymusza przekroczenia limitów czasu i blokady sieciowe. - Bramkowanie możliwości: modyfikuj lub usuwaj klucze API, tokeny lub wywołania uprzywilejowanych punktów końcowych; zastąp je adapterami pozornymi do testów lokalnych. Zapobiegaj przypadkowemu dodawaniu sekretów lub adresów URL.
- Przepisywanie zależności:blok dynamiczny
pip/npmInstalacje utworzone przez kod. Wymagaj zadeklarowania i zatwierdzenia zależności za pośrednictwem rejestru.
Krok 5 — Uruchom w agresywnym środowisku sandbox
- Kontenery efemeryczne / mikromaszyny wirtualne: wykonaj kod w kontenerze/maszynie wirtualnej, która nie ma dostępu do sieci, nie ma dostępu do danych uwierzytelniających hosta i ma ograniczony dostęp do systemu plików. Odpowiednie są technologie takie jak gVisor, Firecracker lub dedykowane usługi efemerycznego wykonywania. Jeśli kod musi uzyskać dostęp do wejścia/wyjścia, użyj serwera proxy, który wymusza przestrzeganie zasad.
- Filtry wywołań systemowych i seccomp: limit dozwolonych wywołań systemowych. Zapisy do plików poza katalogiem tymczasowym powinny być blokowane.
- Limity zasobów/czasu:ustaw limity procesora/pamięci/czasu, tak aby nawet bomby logiczne nie mogły działać w nieskończoność.
Wykonywanie zadań w środowisku testowym i monitorowanie często ujawniają ładunki, których nie wykrywają testy statyczne. Wytyczne branżowe i najnowsze dokumenty zalecają stosowanie środowiska testowego jako podstawowego środka zaradczego.
Jakie narzędzia i reguły automatyczne powinny znaleźć się w Twoim procesie?
Zalecane komponenty łańcucha narzędzi
- Moduł sanitarny Unicode (biblioteki niestandardowe lub istniejące). Należy rejestrować znormalizowane znaki.
- Parser + analizator AST dla każdego języka docelowego (Python
ast,typed-ast, parsery JavaScript, parsery Java). - Analizatory statyczne / SAST:Bandit (Python), Semgrep (wielojęzyczny, konfigurowalny), ESLint z wtyczkami bezpieczeństwa.
- Entropia i heurystyka dekodera: wykryj base64/hex/gzip i skieruj do inspekcji.
- Środowisko wykonawcze piaskownicy:minimalny kontener ze ścisłym profilem seccomp/AppArmor lub interpreter na poziomie języka z wyłączonymi wywołaniami systemowymi.
- Egzekutor polityki:komponent decydujący o dozwolonych modułach, dozwolonych punktach końcowych i bezpiecznych opakowaniach API.
- Ścieżka audytu:niezmienne dzienniki rejestrujące oryginalne dane wyjściowe, oczyszczone dane wyjściowe, różnice i decyzje.
Przykładowe wzorce semgrep (koncepcyjne)
Stosuj krótkie, konserwatywne reguły, które sygnalizują użycie niebezpiecznych funkcji. Na przykład:
- Flaga
eval,exec,Functionkonstruktor (JS), dynamiczne importy lub nazwy API utworzone w oparciu o ciągi znaków. - Oznacz połączenia sieciowe spoza listy dozwolonych (np.
requests.getdo nieznanych hostów). - Flaga zapisuje do wrażliwych ścieżek (
/etc, foldery systemowe) lub tworzenie procesów.
(Zachowaj je jako elementy konfiguracji dla każdej organizacji i z czasem udoskonalaj je.)
Czym są praktyczne fragmenty kodu dezynfekcyjnego (bezpieczne przykłady)?
Poniżej znajdziesz niegroźne, defensywne przykłady, które możesz zastosować. Są to: dezynfekcja i wykrywanie fragmenty kodu — nie instrukcje eksploatacji.
Przykład: usuwanie znaków o zerowej szerokości (Python, defensywne)
import re
ZERO_WIDTH_RE = re.compile(r'')
def strip_zero_width(s: str) -> str:
cleaned = ZERO_WIDTH_RE.sub('', s)
return cleaned
Usuwa znaki, których atakujący często używają do ukrywania kodu w tekście, który w przeciwnym razie byłby widoczny. Zawsze rejestruj usunięte elementy i traktuj usuwanie jako część ścieżki audytu.
Przykład: parsowanie i inspekcja AST (Python, koncepcyjny)
import ast
def has_dynamic_exec(source: str) -> bool:
tree = ast.parse(source)
for node in ast.walk(tree):
if isinstance(node, ast.Call):
if getattr(node.func, 'id', '') in ('eval', 'exec',):
return True
if isinstance(node, ast.Attribute):
if getattr(node, 'attr', '') in ('popen', 'system'):
return True
return False
If has_dynamic_exec zwraca True, nie uruchamiaj kodu; zamiast tego zastąp węzeł dynamiczny bezpiecznym szczątkiem i wymagaj przeglądu.
Uwaga: te przykłady mają charakter obronny. Nie usuwaj rejestrowania, audytu ani weryfikacji ludzkiej z procesu.
Podsumowanie: zawsze traktuj wyniki LLM jak niepewny kod
LM to potężne narzędzia zwiększające produktywność — potrafią tworzyć elegancki kod, przyspieszać tworzenie wersji roboczych i automatyzować rutynowe zadania. Jednak tam, gdzie spotykają się z wykonaniem, zasady bezpieczeństwa ulegają zmianie: wyniki modelu należy traktować jako artefakty niegodne zaufaniaPołączenie szybkich ataków, badań nad lukami w zabezpieczeniach i ujawniania rzeczywistych luk w zabezpieczeniach w ciągu ostatnich 18–30 miesięcy jasno pokazuje: powierzchnia ryzyka wzrosła i będzie nadal ewoluować.
Praktyczne mechanizmy obronne łączące analizę składniową, analizę statyczną, dynamiczne testowanie w piaskownicy, zarządzanie i ciągłe redteaming powstrzymają większość ataków. Zespoły muszą jednak również inwestować w mechanizmy kontroli organizacyjnej: minimalizację uprawnień, pochodzenie i kulturę, która zakłada, że wyniki LLM wymagają weryfikacji. Branża tworzy narzędzia i struktury, które ułatwiają te wzorce; tymczasem wdrożenie powyższej listy kontrolnej zmniejsza ryzyko, że ukryty ładunek zostanie pominięty.
Programiści mogą uzyskać dostęp do najnowszego interfejsu API LLM, takiego jak Claude Sonnet 4.5 API oraz Podgląd Gemini 3 Pro itp. poprzez CometAPI, najnowsza wersja modelu jest zawsze aktualizowany na oficjalnej stronie internetowej. Na początek zapoznaj się z możliwościami modelu w Plac zabaw i zapoznaj się z Przewodnik po API aby uzyskać szczegółowe instrukcje. Przed uzyskaniem dostępu upewnij się, że zalogowałeś się do CometAPI i uzyskałeś klucz API. Interfejs API Comet zaoferuj cenę znacznie niższą niż oficjalna, aby ułatwić Ci integrację.
Gotowy do drogi?→ Zarejestruj się w CometAPI już dziś !
Jeśli chcesz poznać więcej wskazówek, poradników i nowości na temat sztucznej inteligencji, obserwuj nas na VK, X oraz Discord!


