Dziesięć błędów, które AI wpisuje w Twój kod
Hardcoded secrets, SQL injection, path traversal, słaba kryptografia. Wzorce, które powtarzają się w kodzie z LLM, i sposób na każdy.
Kod generowany przez LLM ma rozpoznawalny odcisk palca. Po zaudytowaniu około pięćdziesięciu codebasów wdrożonych między 2024 a 2026, które zawierały funkcje generowane przez AI w historii commitów, te same dziesięć słabości pojawia się mniej więcej w tej samej kolejności. Ten post wymienia je w przybliżonej częstości, wyjaśnia co sprawia, że kod generowany przez model jest podatny w każdym przypadku, i daje jeden konkretny wzorzec prewencji.
Lista to nie OWASP Top 10. To wyspecjalizowany podzbiór dla kodu, który regulowane MŚP wdraża na produkcję: web API, wewnętrzne serwisy, pipeline danych, integracje. Zachowanie modelu, bias danych treningowych i wzorce indukowane promptem wyjaśniają, dlaczego te konkretne CWE się powtarzają.
1. CWE-798 - Hardcoded credentials w kodzie źródłowym
Najczęstszy z dużym marginesem. Modele trenowane na publicznym GitHubie widziały tysiące repozytoriów, gdzie klucze API, URI baz danych i sekrety JWT są commitowane raz i usuwane w panice. Odtwarzają wzorzec w generowanym kodzie z tą samą ludzką plausibility. Typowe symptomy: literały API_KEY = "sk-...", bloki w stylu .env wbudowane w Python lub JavaScript, connection stringi dla Postgres i MongoDB z poświadczeniami inline.
Prewencja: traktuj każde poświadczenie jako wartość wstrzykiwaną w runtime. Konfiguracja ze zmiennych środowiskowych lub secret managera (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault). Hook pre-commit ze skanerem sekretów (gitleaks, trufflehog) blokuje przypadkowe commity. Dodaj krok CI, który wysypuje build przy sekretach w diffie, nawet jeśli poprzedni PR nie miał tego problemu.
2. CWE-89 - SQL injection przez konkatenację stringów
Modele domyślnie tworzą query stringowe, gdy prompt to "funkcja filtrująca użytkowników po emailu." Wzorzec f"SELECT * FROM users WHERE email = '{email}'" pojawia się w generowanym kodzie z częstością sugerującą, że dane treningowe mają go w zdrowej podaży. Model jest też podatny na budowanie dynamicznych klauzul ORDER BY lub whitelist kolumn z wejścia użytkownika bez parametryzacji, nawet gdy WHERE clause jest poprawne.
Prewencja: używaj wyłącznie parametryzowanych zapytań. W Python to cursor.execute("SELECT ... WHERE email = %s", (email,)) z psycopg lub równoważnym. W JavaScript prepared statements przez pg, mysql2 lub ORM. Reguła lintera (python-bandit, eslint-plugin-security) łapie wzorce konkatenacji. Dodaj zestaw testów SQL injection, który CI uruchamia na każdym endpoincie, w tym tych, których nikt nie ruszał od roku.
3. CWE-79 - Cross-site scripting przez niezescapowany rendering
Dla React i Vue to często dyrektywy dangerouslySetInnerHTML i v-html stosowane do wejścia użytkownika lub do stringów generowanych przez model, które zawierają dane użytkownika. Dla server-renderowanych szablonów Jinja2 lub Django brak dyscypliny |safe i HTML w wyjściu modelu. Wzorzec jest trudniejszy do wykrycia w code review niż SQL injection, bo podatność żyje w ścieżce danych, nie w przepływie sterowania.
Prewencja: domyślnie bezpieczny rendering. Traktuj każdy string przechodzący granicę zaufania jako tekst, nie HTML. Sanityzuj na granicy permisywno-bezpieczną whitelistą (DOMPurify dla przeglądarki, bleach dla Pythona). Jeśli produkt faktycznie renderuje HTML z kontrolowanego źródła, izoluj tę ścieżkę za jawną allow-listą i audytuj ją przy kolejnym security review.
4. CWE-22 - Path traversal przez niesanityzowane ścieżki plików
Modele czytające lub zapisujące pliki pod nazwami podanymi przez użytkownika bez sprawdzania sekwencji ../ lub ścieżek bezwzględnych to powtarzający się wzorzec, szczególnie w pipeline uploadu dokumentów, procesorach obrazów i importerach CSV. Model często łapie oczywiste przypadki (.. w środku stringa), ale przepuszcza sztuczki Unicode normalisation lub ścieżki celujące w symlinki.
Prewencja: rozwiąż ścieżkę podaną przez użytkownika z kanonizacją docelowego systemu operacyjnego, potem zweryfikuj, że rozwiązana ścieżka jest wewnątrz dozwolonego roota. W Python os.path.realpath plus sprawdzenie prefixu rozwiązanej ścieżki. W Go filepath.Clean i to samo sprawdzenie prefixu. Nigdy nie konkatenuj wejścia użytkownika w ścieżkę podawaną do open() bez przechodzenia przez resolver.
5. CWE-327 - Użycie złamanego lub ryzykownego algorytmu kryptograficznego
Modele często domyślnie sięgają po md5 dla "szybkiego hasha" lub DES, RC4 albo tryb ECB AES dla "funkcji szyfrującej." Oba to złe domyślne wybory, które model traktuje jako kanoniczne. Subtelniejszy wariant to użycie crypto.createCipher (Node) lub Random (Java) bez silnego seeda, albo random zamiast secrets w kontekście kryptograficznym Pythona.
Prewencja: ogranicz powierzchnię kryptograficzną w twoich wrapperach biblioteki standardowej. Wymuś użycie zatwierdzonych prymitywów (AES-GCM, ChaCha20-Poly1305, SHA-256 lub SHA-3 do haszowania). Przypnij algorytm na granicy importu, żeby deweloper (lub model) nie mógł przypadkiem użyć słabego prymitywu. Dodaj regułę lintera flagującą MD5, SHA-1, DES, RC4 poza testami legacy.
6. CWE-94 - Code injection przez dynamic evaluation
eval(), exec(), konstruktory Function() i silniki szablonów, które re-kompilują wejście użytkownika. Modele piszące funkcje pomocnicze w notebookach regularnie zawierają eval(input_data), bo prompt mówił "ewaluuj wyrażenie." Powierzchnia ryzyka jest mała, ale wysoko uderzeniowa: pojedynczy eval w handlerze requestu wystawionym na wejście użytkownika to remote code execution.
Prewencja: brak eval w kodzie produkcyjnym. Dla dynamicznych szablonów użyj silnika bez logiki (Handlebars, Liquid w trybie ścisłym) i dozwolonego zestawu helperów. Dodaj hook pre-commit, który grepem łapie eval(, exec(, Function(\" i wysypuje build.
7. CWE-502 - Deserializacja niezaufanych danych
pickle.loads, yaml.load (bez Loader=SafeLoader), Java ObjectInputStream, PHP unserialize na wejściu użytkownika. Modele trenowane na notebookach data science są ciężkimi emitterami pickle.loads; wzorzec jest powszechny w generowanych pipeline.
Prewencja: YAML przez yaml.safe_load. Pickle zastąpiony round-tripem JSON lub Parquet. Java używa udokumentowanej allow-listy klas z filtrowaniem ObjectInputStream. Serializacja PHP zastąpiona przez json_encode/json_decode. Dla komunikacji między serwisami użyj typowanego schemy (Protocol Buffers, FlatBuffers, Avro) zamiast natywnej serializacji.
8. CWE-918 - Server-side request forgery
Modele budujące "image proxy" lub "walidator webhooka" często implementują forward requestu bez ograniczania docelowego URL. Request do https://your-service/image?url=https://attacker.internal staje się punktem oparcia dla endpointu metadanych chmury.
Prewencja: allow-list hostnamów, nie sztuczki parsowania URL. Rozwiąż hostname, sprawdź IP przeciwko prywatnym zakresom (10.0.0.0/8, 169.254.0.0/16 itd.) i odmów, jeśli rozwiązany adres nie jest na allow-liście. Uruchom proxy jako osobną tożsamość sieciową bez dostępu do wewnętrznych serwisów.
9. CWE-287 - Niepoprawna autentykacja
Najszersze CWE w tej liście, pojawiające się w wielu formach w kodzie generowanym przez AI: brak weryfikacji tokenu na chronionych endpointach, walidacja JWT bez sprawdzania podpisu, ciasteczka sesji ustawione bez Secure i HttpOnly, flow OAuth pomijające parametr state. Typowy wariant to model piszący if user.get("role") == "admin": bezpośrednio na danych requestu, z rolą pobraną z payloadu JWT, ale nigdy niezweryfikowaną.
Prewencja: scentralizuj autentykację. Jeden middleware, jedna biblioteka, jedno miejsce do audytu. Modele nie generują kodu autentykacji - wywołują funkcję w twojej warstwie auth. Funkcja jest testowana, recenzowana i jest na śladzie audytowym. Zdecentralizowany auth to pierwotna przyczyna większości CWE-287 na tej liście.
Dlaczego to się powtarza w kodzie generowanym przez AI
Trzy czynniki się nakładają. Kompozycja danych treningowych. Korpus nadreprezentuje kod tutorialowy, który z definicji jest permisywny (działa na laptopie dewelopera, nie w produkcyjnym threat modelu). Reprezentuje też kod produkcyjny z historycznymi podatnościami. Model uczy się wzorca powierzchni, nie threat modelu. Skróty indukowane promptem. Gdy prompt to "napisz endpoint Flask zwracający profil użytkownika", model przeskakuje od razu do happy path. Autentykacja, rate limiting i logowanie błędów są nieobecne, chyba że prompt je wymieni. Deweloper, który traktuje wyjście jako draft startowy, złapie to; ten, który traktuje jako gotowy kod, nie złapie. Brak kontekstu. Model nie wie, które pola są PII w twojej domenie, które endpointy są admin-only, które integracje są osiągalne z publicznego internetu. Zadawanie właściwych pytań to zadanie inżynierskie; model nie może ich za ciebie zadać.
Wzorce prewencji, które przecinają wszystkie dziesięć
Trzy kontrolki inżynierskie redukują powierzchnię ataku dla każdego CWE z tej listy. Harness testowy dla OWASP Top 10 i CWE Top 25 z fixtures z OWASP Benchmark i NIST SARD. Stos linting i pre-commit (Bandit, ESLint z eslint-plugin-security, Gosec, Semgrep), który łapie oczywiste wzorce. Granica architektoniczna, gdzie generowany kod woła do cienkiej, audytowanej warstwy wrapperów dla poświadczeń, systemu plików, sieci i dostępu do bazy danych.
Jak to się łączy ze zgodnością z AI Act
Art. 15 AI Actu (dokładność, odporność, cyberbezpieczeństwo) uderza najmocniej właśnie w tę listę. Jeśli twój asystent AI generuje kod w regulowanym pipeline, output jest częścią systemu AI. Właściwości bezpieczeństwa outputu są właściwościami bezpieczeństwa systemu. Udokumentowany program prewencji dla powyższych CWE jest częścią oceny zgodności z art. 43.
ArtCode Software wdrożył ten harness prewencyjny obok generatorów kodu AI w trzech regulowanych polskich SaaS w 2025-2026. Harness żyje w repo, działa w CI i jest referencją w model card. Jeśli potrzebujesz przeglądu tego, gdzie kod generowany przez AI jest obecnie w twoim pipeline i który z tych dziesięciu wzorców jest najbardziej eksponowany, AI Readiness Audit obejmuje przegląd próbek kodu pod kątem tej listy. Jeśli chcesz bieżącej ochrony w miarę ewolucji modelu i codebase, Fractional AI Architect Retainer osadza wzorce prewencji w twoim procesie deweloperskim.