Intencja: czego naprawdę szuka programista korzystający z AI piszącej kod
Osoba sięgająca po generatywną sztuczną inteligencję do pisania kodu chce dwóch rzeczy naraz: szybko działającego rozwiązania oraz pewności, że ten kod nie otwiera drzwi atakującym. Chodzi o świadome korzystanie z GitHub Copilot, ChatGPT czy innych modeli, tak aby zyskać na produktywności, nie ryzykując SQL injection, wycieków danych ani kompromitacji całej infrastruktury.
Kluczowe pytanie brzmi: na ile AI generująca kod faktycznie dba o bezpieczeństwo, a na ile tylko odtwarza średniej jakości wzorce z GitHuba – i jak jako programista wychwycić oraz naprawić jej typowe błędy.
Frazy powiązane: AI generująca kod a bezpieczeństwo, GitHub Copilot podatności, analiza kodu z GitHuba, bezpieczeństwo w Pythonie i JavaScript, AI a OWASP Top 10, audyt bezpieczeństwa kodu AI, prompt engineering pod bezpieczeństwo, testy bezpieczeństwa skryptów AI, błędy bezpieczeństwa w kodzie z AI, dobre praktyki secure coding z AI, automatyczne skanery bezpieczeństwa kodu.

Czym właściwie jest „AI pisząca kod” i jak działa w praktyce
Modele generatywne a tradycyjne narzędzia deweloperskie
Klasyczne narzędzia w IDE – podpowiadanie składni, refaktoryzacja, szybkie importy – działają na bazie statycznej analizy kodu, znajomości składni i dość prostych heurystyk. Inteligencja jest tam mocno „zaszyta” w samym edytorze i kompilatorze. Nie tworzą one nowych rozwiązań, raczej pomagają operować na tym, co już napisał człowiek.
Generatywna sztuczna inteligencja (LLM – Large Language Models) działa inaczej. Modele takie jak GPT, Codex czy inne wyspecjalizowane modele kodu są trenowane na ogromnych zbiorach tekstu i kodu źródłowego. Ich zadaniem jest przewidywanie kolejnych tokenów (słów, znaków, fragmentów kodu) w zadanej sekwencji. W praktyce oznacza to, że:
- nie „rozumieją” kodu jak człowiek, tylko przewidują najbardziej prawdopodobny następny fragment,
- potrafią generować całe funkcje, klasy, a nawet aplikacje na podstawie krótkiego opisu,
- zachowują się jak superzaawansowany „autouzupełniacz” – ale bez sztywnego ograniczenia do bieżącego pliku.
Narzędzia w rodzaju GitHub Copilot, Amazon CodeWhisperer, czy funkcje generowania kodu w ChatGPT często łączą klasyczne wsparcie IDE z modelem generatywnym. Rezultat: sugestie obejmują nie tylko lokalne zmienne, ale też popularne biblioteki, idiomy i całe wzorce projektowe, jakie model „zapamiętał” z GitHuba i innych źródeł.
Z punktu widzenia bezpieczeństwa kluczowe jest to, że model nie ma wbudowanego twardego check-listu secure coding. Jeżeli prosisz o „działający kod logowania”, model da Ci kombinację wszystkiego, co widział – i to w wariancie, który statystycznie wygląda „typowo”. Niestety, „typowo” nie zawsze oznacza „bezpiecznie”.
Jak AI „uczy się” na kodzie z GitHuba
Modele generatywne są trenowane na masowych zbiorach danych: kod z publicznych repozytoriów na GitHubie, projekty open source, dokumentacja, artykuły, tutoriale. W tym miksie znajdują się:
- kod pisany przez bardzo doświadczonych inżynierów bezpieczeństwa,
- kod z hackathonów „byle działało”,
- przykłady z blogów z 2012 roku, które nikt nigdy nie zaktualizował,
- testy, snippet-y, proof-of-concepty exploitów,
- projekty porzucone w połowie refaktoryzacji.
Model nie ma domyślnej świadomości, że projekt X był wzorem secure coding, a projekt Y to „klepnięty na szybko CRUD z dziurami jak ser szwajcarski”. Dla modelu to wszystko jest po prostu materiał treningowy.
Skutek: AI powiela zarówno dobre, jak i złe praktyki. Jeżeli jakaś niebezpieczna konstrukcja (np. łączenie zapytania SQL stringiem bez parametrów) występuje w danych treningowych bardzo często, model może ją traktować jako „naturalny” sposób pisania takiego kodu.
Dodatkowo modele nie mają pełnego wglądu w kontekst Twojego projektu: nie widzą całej architektury, polityk bezpieczeństwa w organizacji, compliance (np. RODO, PCI-DSS). Podpowiedź bazuje głównie na tym, co jest w edytorze i w promptcie, ewentualnie w kilku plikach projektu (zależnie od konkretnego narzędzia).
Konsekwencje trenowania na „prawdziwym kodzie”
Trenowanie na publicznym kodzie z GitHuba ma kilka istotnych skutków:
- Powielanie legacy – stare, nieaktualne biblioteki i idiomy (np. MD5 do hashowania haseł) nadal pojawiają się w odpowiedziach, bo były często obecne w danych.
- Brak kontekstu zagrożeń – model zwykle nie rozróżni, czy fragment z GitHuba to kod produkcyjny, test, czy przykład jak nie pisać aplikacji.
- Brak „instynktu samozachowawczego” – człowiek z doświadczeniem w bezpieczeństwie widzi, że coś „śmierdzi” (np. logika uwierzytelniania w jednym if-ie). Model widzi tylko ciąg tokenów.
- Statystyka zamiast zasad – jeżeli w materiałach treningowych 80% przykładów logowania nie ma limitu prób, to model uzna brak limitu za „normalny”.
Z perspektywy praktyka oznacza to, że AI domyślnie nie będzie za Ciebie pilnować bezpieczeństwa. Można ją do tego „popychać” dobrze sformułowanymi promptami i dodatkowymi narzędziami (skanery, testy), ale sama z siebie nie jest strażnikiem OWASP Top 10.

Co to znaczy, że kod jest „bezpieczny”? Krótki fundament praktyka
Wymiar techniczny: podatności, ataki i wektory
Bezpieczeństwo aplikacji to nie abstrakcja. W codziennej pracy sprowadza się do odporności na konkretne klasy ataków. Najczęściej przewijają się:
- SQL Injection / NoSQL Injection – wstrzyknięcie fragmentu zapytania do bazy poprzez niewłaściwie obsługiwane dane wejściowe,
- XSS (Cross-Site Scripting) – wstrzyknięcie i wykonanie złośliwego JavaScriptu w przeglądarce użytkownika,
- CSRF (Cross-Site Request Forgery) – „podstawienie” użytkownikowi zaufanej strony formularza, który wysyła żądanie w jego imieniu,
- RCE (Remote Code Execution) – uzyskanie możliwości wykonania dowolnego kodu na serwerze, zwykle poprzez błędne korzystanie z eval, exec itp.,
- IDOR (Insecure Direct Object Reference) – dostęp do cudzych zasobów po prostu przez zmianę identyfikatora w URL,
- SSRF (Server-Side Request Forgery) – zmuszenie serwera do wykonywania zapytań HTTP w imieniu atakującego, np. do usług wewnętrznych,
- Niebezpieczna deserializacja – wczytywanie zewnętrznych danych do obiektów w sposób umożliwiający wykonanie złośliwego kodu,
- Błędy w przechowywaniu sekretów – hasła w plain text, klucze API w repozytorium, słabe hashowanie.
Do tego dochodzi klasyczny model CIA:
- Confidentiality (poufność) – dane mogą zobaczyć tylko ci, którzy powinni,
- Integrity (integralność) – dane nie mogą być modyfikowane bez uprawnień,
- Availability (dostępność) – system jest dostępny wtedy, kiedy ma być.
Bezpieczny kod to taki, który minimalizuje ryzyko naruszenia tych trzech aspektów, również w obliczu błędów użytkowników, złośliwych żądań i „kreatywności” atakujących.
Wymiar procesowy: odpowiedzialność, compliance i ryzyko
Bezpieczeństwo to także proces. Kod generuje się w kontekście organizacji, przepisów, polityk. Znaczenie mają:
- Wymagania regulacyjne – np. RODO (ochrona danych osobowych), PCI-DSS (karty płatnicze), wymogi branżowe,
- Polityki bezpieczeństwa firmy – standardy haseł, przechowywania logów, szyfrowania danych, dostępu do baz,
- Procesy wytwórcze – code review, testy bezpieczeństwa, CI/CD z automatycznym skanowaniem,
- Odpowiedzialność prawna – za wyciek danych odpowiada organizacja, nie „model AI”.
Jeżeli aplikacja naruszy przepisy, organ nadzorczy nie przyjmie tłumaczenia: „to Copilot tak napisał”. Formalnie zawsze odpowiada człowiek / zespół / firma. AI jest tylko narzędziem, nawet jeżeli to narzędzie generuje całe moduły kodu.
Stąd ważna konkluzja: bezpieczeństwo trzeba wbudować w proces developmentu, a nie oczekiwać go od pojedynczego narzędzia. AI może przyspieszyć pracę, ale nie zastąpi threat modelingu, code review ani skanerów bezpieczeństwa.
OWASP Top 10 jako drogowskaz przy analizie kodu generowanego przez AI
OWASP Top 10 to lista najczęstszych i najbardziej krytycznych klas podatności w aplikacjach webowych. Najnowsze edycje grupują problemy w kilka kategorii, obejmując m.in.:
- błędy w kontrolach dostępu,
- błędy kryptograficzne,
- wstrzyknięcia (SQLi, NoSQLi, OS Injection),
- problemy z bezpieczną konfiguracją,
- problemy z logowaniem i monitorowaniem.
Lista OWASP jest prostym sposobem na spojrzenie na generowany przez AI kod: które punkty Top 10 mogą być naruszone przez ten fragment? Jeśli generujesz np. endpoint logowania czy formularz rejestracji, od razu warto ocenić go przez pryzmat co najmniej kilku pozycji: wstrzyknięcia, bezpieczeństwo haseł, kontrola dostępu, logowanie i monitoring.
Jak AI faktycznie generuje kod – błyskawiczne wsparcie czy „średnia z GitHuba”
Wzorce i „statystyczna średnia z Internetu”
Mechanizm generowania kodu przez AI jest bezlitośnie prosty: przewidywanie kolejnego tokenu. Model nie analizuje zagrożeń, nie wykonuje threat modelingu, nie robi przeglądu architektury. Stara się wygenerować coś, co „pasuje” do kontekstu prompta i kodu w edytorze, bazując na tym, co widział w treningu.
To ma zalety:
- potrafi zasugerować idiomatyczny kod w danym języku,
- zna popularne biblioteki i frameworki,
- tworzy szablony, których normalnie nie chciałoby się pisać ręcznie.
Ma też poważne wady: „średni” kod z Internetu często jest daleki od secure coding guidelines. Tutoriale skupiają się na tym, aby „zadziałało” – rzadziej, aby było odporne na ataki. Jeżeli w treningu dominują właśnie takie przykłady, model będzie je powielał.
Efekt bywa komiczno-smutny: prosisz o „proste API do logowania w Node.js”, dostajesz login bez ochrony przed brute force, bez rate limiting, bez logowania podejrzanych prób. Wszystko działa, dopóki ktoś nie zacznie „pukać” w endpoint milion razy z rzędu.
Gdy AI ślepo powiela niebezpieczne fragmenty – przykład prostego logowania
Spójrz na uproszczony przykład w Pythonie (flaskopodobny pseudokod, ale bardzo realistyczny dla kodu z GitHuba):
@app.route("/login", methods=["POST"])
def login():
username = request.form["username"]
password = request.form["password"]
user = db.execute(
f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
).fetchone()
if user:
session["user_id"] = user["id"]
return redirect("/dashboard")
else:
return "Invalid credentials", 401
Tego typu kod naprawdę można znaleźć w publicznych repozytoriach – jako przykład, stary projekt, test itd. Model, widząc podobny prompt (np. „napisz prostą funkcję logowania w Flasku”), potrafi wygenerować niemal identyczny fragment.
Problemów jest kilka:
- SQL Injection – łączenie zapytania SQL z inputem użytkownika wprost w stringu,
- Hasła w plain text – brak jakiegokolwiek hashowania (bcrypt/argon2),
- Brak limitów prób – można brute-forcować do woli,
- Brak logowania podejrzanych prób – utrudnia wykrycie ataków.
Alternatywa, której oczekujesz jako minimum bezpieczeństwa, wygląda raczej tak:
@app.route("/login", methods=["POST"])
def login():
username = request.form.get("username", "").strip()
password = request.form.get("password", "")
user = db.execute(
"SELECT id, password_hash FROM users WHERE username = :username",
{"username": username}
).
Najczęściej zadawane pytania (FAQ)
Czy GitHub Copilot i inne AI same dbają o bezpieczeństwo generowanego kodu?
Nie. Copilot, ChatGPT i podobne narzędzia nie mają wbudowanego „instynktu bezpieczeństwa”. Działają statystycznie: przewidują kolejny fragment kodu na podstawie tego, co widziały w danych treningowych. Jeśli w tych danych dominują przykłady bez walidacji wejścia czy z niebezpiecznymi konstrukcjami, AI chętnie je powieli.
Bezpieczeństwo trzeba jej niejako „narzucić”: precyzyjnym promptem (np. „zadbaj o ochronę przed SQL Injection, XSS i uwierzytelnianie oparte na tokenach”), code review oraz dodatkowymi narzędziami (skanery SAST/DAST, testy jednostkowe z „złośliwymi” danymi). AI to szybki pomocnik, ale strażnikiem bezpieczeństwa nadal musi być programista.
Jakie typowe błędy bezpieczeństwa pojawiają się w kodzie generowanym przez AI?
Najczęściej wychodzą na wierzch klasyki z OWASP Top 10. W kodzie z AI często widać m.in.:
- zapytania SQL budowane zwykłym konkatenowaniem stringów (SQL Injection),
- brak sanityzacji danych wyjściowych w HTML (XSS),
- brak limitu prób logowania i blokady konta,
- hasła przechowywane z użyciem przestarzałych funkcji (MD5, SHA-1) zamiast bcrypt/Argon2,
- wystawianie wewnętrznych URL‑i bez autoryzacji (IDOR, SSRF).
Na pierwszy rzut oka wszystko „działa”, ale z perspektywy bezpieczeństwa taki kod wymaga gruntownego doczyszczenia. Dobrą praktyką jest traktowanie gotowca z AI jak szkicu, który dopiero trzeba wzmocnić pod kątem bezpieczeństwa.
Jak korzystać z AI do pisania kodu, żeby nie wprowadzić podatności?
Po pierwsze – precyzyjny prompt. Zamiast „napisz endpoint logowania w Node.js”, lepiej poprosić: „napisz bezpieczny endpoint logowania w Node.js z użyciem parametrów zapytań, hashowaniem haseł bcryptem, ochroną przed brute force i opisem potencjalnych podatności”. To zmusza model do „myślenia” o bezpieczeństwie.
Po drugie – zawsze wykonuj code review, nawet jeśli „kod napisał Copilot”. Dobrym nawykiem jest też puszczanie kodu przez skanery bezpieczeństwa (np. w pipeline CI), oraz dopisywanie testów z „złośliwym” inputem: znaki specjalne w SQL/HTML, bardzo długie stringi, dziwne kombinacje parametrów. AI przyspiesza pracę, ale nie zastępuje podstawowego warsztatu secure coding.
Czy AI generująca kod jest zgodna z OWASP Top 10?
Domyślnie – nie. Model nie ma zakodowanej check‑listy w stylu „OWASP Top 10 2021 – wszystkie punkty odhaczone”. Traktuje OWASP raczej jako tekst, który kiedyś ktoś gdzieś napisał, a nie jako zestaw twardych reguł, których musi przestrzegać.
Możesz natomiast wymusić lepsze zachowanie. Pomaga proszenie wprost: „uwzględnij OWASP Top 10, wypisz, jak każda z pozycji jest adresowana w tym kodzie” albo „przeanalizuj poniższy kod pod kątem OWASP Top 10 i popraw go”. To nadal nie daje stuprocentowej pewności, ale bardzo podnosi poziom rozmowy z modelem.
Czy kod z AI jest bezpieczniejszy w Pythonie niż w JavaScript (lub odwrotnie)?
Sam język nie czyni kodu automatycznie bezpiecznym. Python i JavaScript mają inne typowe wektory ataku (np. XSS i CSRF częściej kojarzą się z frontendem/Node.js, a niebezpieczna deserializacja pojawia się w Pythonie w innych miejscach), ale AI potrafi wygenerować podatny kod w każdym z nich.
Różnica jest raczej w ekosystemie i bibliotekach: w Django czy FastAPI łatwiej o sensowne wzorce auth, w Next.js lub NestJS – o gotowe mechanizmy ochrony. Jeśli w promptach poprosisz o użycie popularnych, sprawdzonych frameworków i mechanizmów (ORM z parametryzowanymi zapytaniami, gotowe middlewares bezpieczeństwa), szansa na wstrzelenie się w bezpieczniejsze rozwiązanie rośnie niezależnie od języka.
Jak mogę sprawdzić bezpieczeństwo kodu wygenerowanego przez AI?
Najlepiej połączyć kilka podejść. W praktyce wygląda to tak:
- ręczny code review z listą kontrolną (SQLi, XSS, CSRF, IDOR, przechowywanie sekretów, logowanie błędów),
- automatyczne skanery bezpieczeństwa (SAST w CI/CD, np. SonarQube, Semgrep, plus DAST dla wystawionych API),
- testy jednostkowe i integracyjne z „złośliwym” inputem,
- zadanie modelowi dodatkowego promptu: „przeanalizuj ten kod pod kątem bezpieczeństwa, wypisz ryzyka i zaproponuj poprawki”.
AI potrafi pomóc także na etapie audytu, ale ostateczną decyzję i odpowiedzialność nadal ponosi człowiek. To trochę jak z linijką w ręku stolarza – narzędzie jest przydatne, ale samo stołu nie wypoziomuje.
Czy mogę zrzucić odpowiedzialność za wyciek danych na „błąd AI”?
Nie. Z punktu widzenia prawa i compliance (RODO, PCI‑DSS itd.) odpowiedzialna jest organizacja, która wdrożyła system i dopuściła kod do produkcji. Narzędzie – nawet bardzo „inteligentne” – nie jest stroną w postępowaniu i nie da się na nie zrzucić winy.
Dlatego proces musi nadążać za technologią: jasne polityki bezpieczeństwa, obowiązkowe code review, skanowanie w pipeline’ach, przeglądy architektury. AI może przyspieszyć development, ale jeśli wciągniesz ją w chaotyczny proces bez kontroli jakości, po prostu szybciej dostarczysz podatności na produkcję.
Najważniejsze punkty
- AI generująca kod jest zaawansowanym „autouzupełniaczem” opartym na statystyce, a nie inżynierem bezpieczeństwa – przewiduje kolejne tokeny, zamiast świadomie projektować bezpieczne rozwiązania.
- Modele trenowane na GitHubie kopiują zarówno dobre, jak i fatalne praktyki: od solidnych wzorców secure coding po „byle działało” z hackathonu, więc w wygenerowanym kodzie mogą pojawić się klasyczne dziury jak SQL injection czy XSS.
- Brak kontekstu projektowego sprawia, że AI nie uwzględnia architektury systemu, polityk bezpieczeństwa ani wymogów compliance – kod wygląda poprawnie składniowo, ale może być kompletnie nieprzystający do realnych wymagań bezpieczeństwa.
- Statystyka wygrywa z zasadami: jeżeli w danych treningowych dominują przykłady bez limitu prób logowania czy z użyciem przestarzałych algorytmów (np. MD5 do haseł), model będzie takie rozwiązania proponował jako „normalne”.
- AI nie odróżnia kodu produkcyjnego od testów, PoC exploitów czy „antyprzykładów” z blogów, więc może bez mrugnięcia okiem podsunąć konstrukcje, które człowiek z minimalnym doświadczeniem w security uznałby za czerwony alarm.
- Bezpieczeństwo wygenerowanego kodu wymaga aktywnej postawy programisty: świadomych promptów nastawionych na secure coding, użycia skanerów bezpieczeństwa, testów oraz zwykłego „instynktu samozachowawczego” przy przeglądzie zmian.
- AI świetnie przyspiesza pracę (szczególnie przy boilerplate czy prototypowaniu), ale nie zastępuje znajomości OWASP Top 10 ani praktyk bezpieczeństwa – traktowanie jej jak strażnika security to proszenie się o kłopoty, i to raczej szybkie.






