Utwórz darmowe konto
Bezpieczeństwo kodu aplikacji LLM

Wyjście twojego modelu to niezaufane wejście. Znajdź miejsca, w których kod o tym zapomina.

Analiza statyczna kodu wokół twojego LLM — kodu, który buduje prompt, wywołuje model i coś robi z odpowiedzią. Nie modelu. Nie odporności promptu na jailbreak. Kodu.

Plan bezpłatny obejmuje 3 projekty i 30 analiz miesięcznie, bez limitu użytkowników i bez karty płatniczej. Ta analiza się w nim mieści.

Problem

Model nie jest biblioteką. Jest niezaufanym interpreterem: podajesz mu łańcuch znaków, a on oddaje inny. Wszystko, co wpłynęło na ten łańcuch — własny prompt użytkownika, strona, którą mu pokazano, dokument, który mu przekazano, wynik innego narzędzia — wpłynęło na odpowiedź.

Odpowiedź jest nieszkodliwa, dopóki kod nie nada jej możliwości działania. Niebezpieczeństwo nie polega na tym, że model coś powiedział, lecz na tym, że program w to uwierzył. Każde miejsce, w którym program traktuje wygenerowany tekst jak kod, polecenie, zapytanie, ścieżkę lub adres URL, jest wstrzyknięciem o jeden skok dalej — i w odróżnieniu od pytania, czy prompt da się obejść jailbreakiem, ten skok widać w kodzie źródłowym.

Czego szuka Cybseco

Tam, gdzie wyjście modelu trafia do czegoś, co działa. To są własne kategorie, poziomy istotności i identyfikatory CWE silnika.

Wykonanie kodu — CWE-94
krytyczna
eval, exec, compile, new Function, pickle.loads, yaml.load — odpowiedź staje się programem.
Powłoka — CWE-78
krytyczna
os.system, subprocess, child_process.exec, execSync — odpowiedź staje się poleceniem.
Zapytanie SQL — CWE-89
wysoka
execute, raw, createQuery — text-to-SQL to dokładnie ten wzorzec, a DROP TABLE jest prawdopodobnym dokończeniem.
Ścieżka w systemie plików — CWE-22
wysoka
open, readFile, shutil.rmtree, unlink — ../../etc/passwd jest równie prawdopodobnym dokończeniem.
Żądanie wychodzące — CWE-918
wysoka
requests, httpx, fetch, axios, urlopen — fałszowanie żądań po stronie serwera, wybrane przez model.

Konkretny przykład

Dziewięć linii i cały kształt ryzyka.

from openai import OpenAI
client = OpenAI()

def run_plan(task: str):
    answer = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": task}],
    )
    exec(answer.choices[0].message.content)
Źródło
client.chat.completions.create(…) — wywołanie zwracające wyjście modelu. Analizator wiąże zmienną, do której zostało przypisane, i właśnie to pozwala mu śledzić wartość w obrębie funkcji bez analizy międzyproceduralnej.
Przepływ
answer zawiera tekst, na który mógł wpłynąć atakujący. Między wywołaniem a ujściem nic go nie sprawdza, nie ogranicza ani nie sprowadza do stałego zbioru operacji.
Ujście
exec(…) — tekst staje się programem we własnym procesie aplikacji, z jej poświadczeniami, jej siecią i jej systemem plików.
Dlaczego to ma znaczenie
Wszystko, co może wpłynąć na task — bezpośrednio albo przez dokument pokazany modelowi — wybiera, co zostanie uruchomione. To zdalne wykonanie kodu o jeden skok dalej.

Uruchomiony na bieżącym silniku ten fragment daje jeden wynik: llm-output-to-code-execution, CWE-94, istotność krytyczna, pewność wysoka, w linii exec. Pewność jest wysoka, ponieważ zmienna jest związana z rzeczywistym wywołaniem completion. Nazwa, która jedynie wygląda jak odpowiedź modelu — llm_response, reply — jest zgłaszana ze średnią pewnością, bo to domysł, a twierdzenie inaczej byłoby kłamstwem o dowodach.

Czym to nie jest

To nie jest test modelu
Nie sondujemy modelu, nie prowadzimy wobec niego red teamingu i nie oceniamy, jak zachowuje się pod presją. Nic tutaj nie mówi, czy prompt da się obejść jailbreakiem: tego nie da się rozstrzygnąć na podstawie kodu źródłowego, a twierdzenie tak byłoby dokładnie takim stwierdzeniem, którego ten silnik ma unikać.
To nie jest pełne wykrywanie wstrzykiwania promptów
Wstrzyknięcie pośrednie zgłaszamy tam, gdzie niezaufana treść w dowodliwy sposób trafia do promptu. Kanału, którego nie widzimy w kodzie, nie zgłaszamy.
To nie jest gwarancja dotycząca agenta
Zgłaszamy, że agentowi przyznano narzędzie wykonujące kod lub polecenia. To, co agent zrobi później w czasie działania, wykracza poza to, co analiza statyczna może rozstrzygnąć.
Uzupełnienie bezpieczeństwa AI w czasie działania
Guardraile, stanowiska ewaluacyjne i red teaming odpowiadają na pytania, na które to nie odpowie, a to odpowiada na pytania, na które one nie odpowiedzą. Żadne nie zastępuje drugiego.

Inne ryzyka charakterystyczne dla LLM w kodzie

Każde z nich zostało wyzwolone na próbce wobec bieżącego silnika, zanim je tutaj zapisano.

Sekrety i dane osobowe wstawione do promptu — CWE-200
api_key, hasło, IBAN albo dokumentacja medyczna umieszczone w wysyłanym przez ciebie tekście. Zgłaszane tam, gdzie faktycznie budowany jest kontekst promptu, a nie przy każdym f-stringu, który przypadkiem zawiera klucz.
Agent z narzędziem wykonującym kod lub polecenia — CWE-250
PythonREPLTool, ShellTool, interpreter kodu, terminal. Przyznanie jednego z nich zamienia każde pytanie o wstrzyknięcie promptu w pytanie o zdalne wykonanie kodu.
Zabezpieczenie frameworka ponownie wyłączone — CWE-502
allow_dangerous_deserialization=True, trust_remote_code=True, dangerouslyAllow… — framework je wyłączył, bo było niebezpieczne.
Wyłączone mechanizmy bezpieczeństwa dostawcy — CWE-693
BLOCK_NONE, safety_settings=None, moderation=false.
Prompt lub definicja agenta pobierane w czasie działania — CWE-829
hub.pull(…), szablon promptu ładowany przez HTTP. Kto kontroluje ten punkt końcowy, kontroluje instrukcje.
Niezaufana treść wczytana wprost do promptu — CWE-77
Zescrapowana strona, PDF, repozytorium, wiki. To kanał wstrzyknięcia pośredniego, rozpoznawany po tym, skąd pochodzi tekst, a nie po tym, co mówi.
Klucz API modelu zapisany w kodzie źródłowym — CWE-798
sk-…, sk-ant-…, AIza…, hf_… zacommitowane do repozytorium.
Wycofany lub zastąpiony model zapisany na stałe w kodzie — CWE-1104
text-davinci-*, gpt-4-0314, claude-instant — słabsza hierarchia instrukcji, brak oddzielenia promptu systemowego.

Dlaczego w cokolwiek z tego wierzyć

Opublikowany benchmark
Precyzja, czułość i F1 w podziale na CWE, język i warstwę analizy, na wersjonowanym korpusie oznaczonym ręcznie. Zobacz liczby.
Opublikowany zakres
Każda warstwa, której nie mierzymy, jest wymieniona wraz z powodem. Przeczytaj metodykę.
Walidacja na kodzie publicznym
Przeanalizowane repozytoria i commity, napotkane języki, odsetek ukończeń i determinizm — wolumeny i odsetki, a nie twierdzenia o dokładności. Zobacz przebiegi.
Każdy wynik niesie swój dowód
Plik, linia, dopasowana konstrukcja i CWE. Wynik, którego nie możesz sprawdzić, to wynik, na podstawie którego nie powinieneś działać.

Niezależny od dostawcy z założenia. Analizator rozpoznaje kształt — coś wytwarza tekst, coś go konsumuje — a nie zapis jednego konkretnego SDK. Nazywa framework, który zobaczył, kiedy może (OpenAI, Anthropic, Google, Azure OpenAI, Mistral, Bedrock, Ollama, LiteLLM, LangChain, LangGraph, LlamaIndex, Semantic Kernel, AutoGen, CrewAI, Hugging Face), żeby wynik mógł powiedzieć, skąd pochodzi. To etykieta na wyniku, a nie integracja z każdym SDK, i framework nieobecny na tej liście jest analizowany dokładnie tak samo.

Zobacz, jak Cybseco wnioskuje o rzeczywistym systemie

Obejrzyj interaktywne demo, a następnie poproś o prowadzony okres próbny dla swojego zespołu.