Czy kod wygenerowany przez AI jest bezpieczny? Dane i audyt krok po kroku

background
Audyt kodu wygenerowanego przez AI - 45% nie przechodzi testów bezpieczeństwa

Asystent AI napisze działający endpoint w kilkanaście sekund. Problem w tym, że „działający” i „bezpieczny” to dwa różne stany, a testy akceptacyjne sprawdzają zwykle tylko ten pierwszy. Kod przechodzi code review, bo robi dokładnie to, co miał robić. Luka wychodzi pół roku później.

Ten artykuł pokazuje, co dokładnie mówią badania o bezpieczeństwie kodu generowanego przez modele językowe, jakie klasy błędów powtarzają się najczęściej i jak wygląda audyt takiego kodu u nas.


Co pokazują dane

Najszerzej zakrojone publiczne badanie na ten temat to GenAI Code Security Report opublikowany przez Veracode 30 lipca 2025 roku. Przetestowano w nim ponad 100 modeli językowych na zadaniach programistycznych w czterech językach: Javie, Pythonie, C# i JavaScripcie.

Wynik: 45% wygenerowanych próbek kodu nie przeszło testów bezpieczeństwa i wprowadzało podatności z listy OWASP Top 10.

W rozbiciu na języki różnice są duże:

JęzykOdsetek próbek z podatnością
Java72%
C#45%
JavaScript43%
Python38%

Najgorzej wypadła ochrona przed cross-site scriptingiem — w zadaniach, gdzie XSS (CWE-80) był realnym zagrożeniem, modele nie zabezpieczyły kodu w 86% przypadków.

Najważniejszy wniosek raportu nie dotyczy jednak samych liczb. Veracode zwraca uwagę, że wyniki bezpieczeństwa pozostawały płaskie niezależnie od wielkości modelu i zaawansowania treningu. Nowsze i większe modele piszą kod, który częściej działa poprawnie, ale nie piszą kodu, który jest bezpieczniejszy. To znaczy, że problem nie rozwiąże się sam przez czekanie na kolejną wersję narzędzia.


Dlaczego AI pisze niebezpieczny kod

Nie dlatego, że „nie umie”. Powody są konkretne i każdy z nich jest przewidywalny.

Model uczył się na publicznym kodzie. Większość przykładów w internecie to tutoriale, odpowiedzi ze Stack Overflow i kod demonstracyjny — pisany po to, żeby pokazać mechanizm, a nie żeby wytrzymać produkcję. Kod pokazujący „jak zrobić zapytanie do bazy” rzadko zawiera warstwę autoryzacji.

Model nie zna Twojego modelu zagrożeń. Nie wie, które pole jest publiczne, a które tylko dla zalogowanego kontrahenta, czy ten endpoint stoi za VPN-em i kto realnie może wysłać do niego request. Pisze kod spełniający prompt, nie kod spełniający politykę dostępu, której mu nie opisano.

Model widzi fragment, nie system. Generuje funkcję w oderwaniu od tego, że walidacja miała być w Form Requeście, że to konkretne zapytanie wykona się w pętli po 3000 rekordów, albo że identyczna logika istnieje już w innym serwisie i teraz będą się rozjeżdżać.

Kod wygląda na pewny siebie. Nie ma komentarza „tu nie sprawdziłem uprawnień”. Jest schludny, sformatowany i nazwany zgodnie z konwencją. Przy przeglądzie czyta się go szybciej niż kod kolegi — i właśnie dlatego łatwiej przepuścić w nim błąd.


Co znajdujemy najczęściej

Przy przeglądach kodu pisanego z pomocą asystentów AI powtarza się ten sam zestaw problemów:

  • Brak autoryzacji na poziomie zasobu. Endpoint sprawdza, czy użytkownik jest zalogowany, ale nie sprawdza, czy to jego zamówienie. Klasyczne Broken Access Control, numer jeden w OWASP Top 10.
  • Walidacja tylko po stronie frontu. Formularz w Reakcie waliduje poprawnie, backend przyjmuje wszystko. Walidacja frontowa jest wygodą dla użytkownika, nigdy zabezpieczeniem.
  • Walidacja oderwana od znaczenia pola. string|max:255 na numerze telefonu, polu NIP i imieniu. Technicznie waliduje, biznesowo nie waliduje niczego.
  • Dane wrażliwe w logach. Wrzucony w ramach debugowania zrzut całego requestu, w którym leci token albo hasło.
  • Sekrety w repozytorium. Klucz API wklejony w kod, bo tak było w przykładzie z promptu.
  • Zapytania N+1 i brak indeksów. Działa na danych testowych, kładzie się na produkcyjnych.
  • Nieobsłużone wyjątki i wycieki szczegółów błędów. Stack trace trafia do odpowiedzi API.
  • Biblioteki dobrane „z pamięci” modelu. Paczki porzucone, zarchiwizowane albo z aktywnym CVE — model zna je z czasu treningu, nie z dzisiejszego stanu rejestru.

Ostatni punkt jest wyjątkowo podstępny, bo tu AI potrafi wymyślić nazwę pakietu, który nie istnieje. Jeżeli ktoś zarejestruje taką nazwę w npm czy Packagiście, bezrefleksyjna instalacja z podpowiedzi staje się realnym wektorem ataku na łańcuch dostaw.


Jak audytujemy kod z AI w Nice Code

Audyt prowadzimy w pięciu krokach. Kolejność ma znaczenie — automat idzie pierwszy, bo odsiewa oczywiste rzeczy i zostawia czas człowiekowi na to, czego automat nie zobaczy.

1. Inwentaryzacja i zależności

Zaczynamy od tego, z czego aplikacja jest zbudowana. composer audit i npm audit pod kątem znanych podatności, plus przegląd ręczny: czy paczka nie jest oznaczona jako deprecated, czy repozytorium na GitHubie nie jest zarchiwizowane, kiedy było ostatnie wydanie. Sprawdzamy też, czy wszystkie zależności w ogóle istnieją w oficjalnych rejestrach i czy pliki lock są w repozytorium.

2. Skan statyczny i przegląd historii

Analiza statyczna pod kątem OWASP Top 10, skan repozytorium pod kątem sekretów — również w historii commitów, nie tylko w bieżącym stanie, bo usunięcie klucza nowym commitem nie usuwa go z repo. Na tym etapie odpadają też rzeczy czysto formalne: niespójny styl, martwy kod, pozostałe po generowaniu fragmenty „do uzupełnienia”.

3. Przegląd ręczny warstwy dostępu

To jest część, której nie da się zautomatyzować, i to tutaj znajdujemy najpoważniejsze błędy. Przechodzimy endpoint po endpoincie i odpowiadamy na jedno pytanie: kto może to wywołać i na czyich danych. W Laravelu oznacza to sprawdzenie, czy każdy zasób ma Policy albo Gate i czy autoryzacja faktycznie jest wywoływana, a nie tylko zdefiniowana. Równolegle sprawdzamy, czy walidacja siedzi w Form Requestach i czy reguły odpowiadają rzeczywistym danym — że w imieniu nie przejdą cyfry, a w kwocie wartość ujemna.

4. Testy i przypadki brzegowe

Patrzymy, co jest pokryte testami i czego w testach nie ma. Kod generowany przez AI zwykle ma testy ścieżki szczęśliwej, bo taki był prompt. Brakuje testów na odrzucenie niepoprawnych danych (422), na żądanie nieuwierzytelnione (401) i na żądanie uwierzytelnione, ale bez uprawnień (403). Te trzy przypadki dopisujemy zawsze — są najtańszym sposobem, żeby ta sama luka nie wróciła przy następnej zmianie.

5. Raport z priorytetami

Na koniec dostajesz listę znalezisk uszeregowaną według realnego ryzyka, a nie według liczby ostrzeżeń ze skanera. Każdy punkt ma lokalizację w kodzie, opis konsekwencji i propozycję poprawki. Rozdzielamy to, co trzeba naprawić przed wdrożeniem, od tego, co może poczekać na kolejną iterację. Poprawki możemy wprowadzić sami albo zostawić je Twojemu zespołowi — to Twoja decyzja.


Czego nie znajdzie sam skaner

Warto mieć realistyczne oczekiwania wobec narzędzi automatycznych. Skaner świetnie wyłapuje wzorce: konkatenację SQL-a, wywołanie eval, znaną podatność w zależności. Nie wyłapuje natomiast błędów, które są poprawnym kodem realizującym złą regułę biznesową.

Skaner nie wie, że rabat kontrahenta nie powinien być widoczny dla innego kontrahenta. Nie wie, że status zamówienia można zmieniać tylko w jedną stronę. Nie wie, że to pole miało być tylko do odczytu po akceptacji dokumentu. Z punktu widzenia analizy statycznej wszystkie te przypadki to zwyczajny, czysty kod.

Dlatego audyt, który sprowadza się do wklejenia raportu ze skanera, jest wart tyle, co sam skaner. Wartość pojawia się dopiero wtedy, gdy ktoś zestawi kod z tym, jak biznes ma faktycznie działać.


Kiedy warto zrobić audyt

Nie każdy projekt go potrzebuje w tym samym momencie. Sygnały, przy których warto się zatrzymać:

  • Aplikacja powstała w dużej części z pomocą asystenta AI i nikt z doświadczeniem w bezpieczeństwie nie przeszedł przez nią całościowo.
  • Przetwarzacie dane osobowe, dane kontrahentów albo płatności.
  • Projekt pisał zewnętrzny wykonawca i przejmujecie go do utrzymania.
  • Zbliża się wdrożenie produkcyjne albo integracja z ERP.
  • Coś już się wydarzyło — nietypowy ruch, podejrzane zamówienia, wyciek.

Jeżeli budujesz dopiero pierwszą wersję, taniej jest ustawić zasady na starcie, niż audytować po fakcie. Opisaliśmy to podejście w przewodniku jak stworzyć moduł PrestaShop z pomocą AI — znajdziesz tam gotowy zestaw reguł, który można podłączyć modelowi jeszcze przed napisaniem pierwszej linijki.


FAQ

Czy to znaczy, że nie powinienem używać AI do pisania kodu? Nie. AI realnie przyspiesza pracę i sami z niej korzystamy codziennie. Zmienia się natomiast rozkład czasu: mniej go idzie na pisanie, więcej na weryfikację. Kto oszczędza na tym drugim, oddaje całą uzyskaną przewagę z nawiązką.

Ile trwa audyt? Zależy od wielkości projektu i od tego, czy jest to przegląd całej aplikacji, czy pojedynczego modułu. Zakres i termin ustalamy po wstępnym spojrzeniu na repozytorium — bez tego każda liczba byłaby zgadywaniem.

Czy musicie dostać dostęp do produkcji? Nie. Do audytu kodu wystarczy repozytorium. Dostęp do środowiska testowego pomaga, ale produkcja nie jest potrzebna.

Audytujecie tylko Laravel i PrestaShop? Najmocniejsi jesteśmy w PHP (Laravel, PrestaShop, Magento) i w React. Przy innych stosach mówimy wprost, czy jesteśmy właściwym adresem.

Co jeśli audyt wykaże dużo problemów? To normalny wynik i nie jest to powód do paniki — raport jest po to, żeby uszeregować je według ryzyka. Zwykle kilka pozycji trzeba naprawić od razu, a reszta to dług techniczny do rozłożenia w czasie.


Podsumowanie

Dane Veracode są jednoznaczne w jednym punkcie: skoro bezpieczeństwo kodu generowanego przez modele nie poprawia się wraz z ich rozwojem, to warstwa weryfikacji nie jest etapem przejściowym, tylko stałym elementem procesu. Asystent AI przyspiesza wytwarzanie i jednocześnie przyspiesza wprowadzanie podatności — audyt jest tym, co rozdziela te dwa efekty.

U nas sprowadza się to do prostej zasady: automat odsiewa znane wzorce, człowiek sprawdza, kto ma dostęp do czego, a testy pilnują, żeby raz naprawiony błąd nie wrócił.

Masz aplikację napisaną z pomocą AI i chcesz wiedzieć, co w niej siedzi? Napisz do nas — spojrzymy na repozytorium i powiemy, czy audyt ma sens i w jakim zakresie.

Zobacz też naszą ofertę dedykowanego oprogramowania i modułów PrestaShop. Jeśli potrzebujesz programisty na stałe do zespołu, sprawdź body leasing oraz artykuł o tym, dlaczego jedna osoba potrafi dziś zastąpić mały zespół.

Jakub Przepióra

O autorze

Jakub Przepióra

CEO Nice Code sp. z o.o.

Programista z 10-letnim doświadczeniem, założyciel i właściciel software house Nice Code oraz twórca OpenMES — autorskiego systemu do zarządzania produkcją. Specjalista ds. cyberbezpieczeństwa. Buduje sklepy Prestashop i aplikacje webowe na bazie Laravel oraz Symfony, wspierając firmy w digitalizacji procesów i sprzedaży online.

Wycena sklepu, aplikacji webowej lub mobilnej - bezpłatnie w 24h

Opisz nam swój projekt, a my przygotujemy wstępną wycenę bez zobowiązań. Sklepy internetowe, aplikacje dedykowane, aplikacje mobilne.

Bezpłatna wycena

arrow right
contact us background