Vibecoding · · 7 min czytania
Czy kod od AI jest bezpieczny? Vibecoding a bezpieczeństwo
Kod od AI nie jest bezpieczny ani niebezpieczny, jest niesprawdzony. Realne ryzyka i checklista.
Krótka odpowiedź na pytanie z tytułu: kod od AI nie jest ani bezpieczny, ani niebezpieczny — jest niesprawdzony. Model językowy generuje to, co statystycznie najbardziej prawdopodobne, a nie to, co najbezpieczniejsze. Różnica jest subtelna do momentu, w którym Twój endpoint trafia do internetu z zahardkodowanym kluczem albo zapytaniem SQL sklejanym ze stringa. Vibecoding nie tworzy nowych klas podatności. On je tylko przyspiesza — i to jest sedno problemu.
Dlaczego w ogóle o tym rozmawiamy
Przez ostatnie dwa lata zmienił się profil osoby, która wypuszcza kod do produkcji. Wcześniej „wysyłam do prod” oznaczało kogoś, kto przeszedł przez code review, zna różnicę międzyGET a POST i wie, czemu nie wolno ufać danym od użytkownika. Dziś ten sam deploy robi osoba, która poprosiła agenta o „dodaj logowanie” i wkleiła wynik. Kod działa, demo przechodzi, klient jest zadowolony. Podatność jest niewidoczna, bo nic się nie pali — dopóki ktoś nie zacznie szukać.
To nie jest tekst straszący AI. Sam piszę większość kodu z asystentem i nie wrócę do edytora bez niego. Ale traktowanie wygenerowanego kodu jak gotowego do wdrożenia to błąd kategorii. To jest pierwszy szkic od bardzo szybkiego juniora — nie audyt bezpieczeństwa. Stawka jest realna: wyciek bazy klientów, przejęte konto, kara z RODO. I nie chodzi o to, czy umiesz programować — chodzi o to, czy ktoś sprawdził kod pod kątem bezpieczeństwa, zanim wyszedł na świat.
Realne klasy ryzyka, nie teoretyczne
Pomińmy abstrakcje. Oto co faktycznie wychodzi z modeli, gdy poprosicie o „działający kod”, posortowane według tego, jak często widzę to w praktyce:
- Sekrety w kodzie. Klucze API, hasła do bazy, tokeny — wstawione wprost do pliku „dla przykładu”, który potem trafia do repozytorium. Model nie wie, że Twój przykład pojedzie na produkcję. Co gorsza, raz wypchnięty sekret zostaje w historii Gita na zawsze, nawet po usunięciu z bieżącego pliku — jedyną realną naprawą jest rotacja klucza.
- Injection — SQL i komendy. Zapytania budowane przez konkatenację stringów zamiast parametryzacji.
"SELECT * FROM users WHERE id = " + userIdto klasyk, który model wciąż podsuwa, bo widział go miliony razy w danych treningowych. - XSS we frontendzie. Renderowanie danych od użytkownika bez escapingu,
dangerouslySetInnerHTMLz niezaufanym wejściem, brakującyContent-Security-Policy. - Niepewne zależności. Model sugeruje paczkę, która istnieje, ale jest porzucona, ma znaną podatność albo — w najgorszym wariancie — nie istnieje wcale, a ktoś złośliwy zarejestrował tę nazwę w npm (typosquatting i „slopsquatting”).
- Zbyt szerokie uprawnienia. Bucket S3 ustawiony jako publiczny, rola IAM z
*:*, CORS otwarty na*, port bazy wystawiony na świat. „Żeby działało” — i działa, dla wszystkich. - Słabe uwierzytelnianie. JWT bez weryfikacji podpisu, hasła hashowane MD5, brak rate limitingu na endpoincie logowania, sesje bez wygaśnięcia.
Żadna z tych rzeczy nie jest nową podatnością. Wszystkie są w OWASP Top 10 od lat. Nowe jest tempo, w jakim trafiają do produkcji.
Dlaczego AI pogarsza niektóre ryzyka
Dwa mechanizmy robią z asystenta mnożnik ryzyka, a nie samo źródło.
Prędkość. Gdy piszesz ręcznie, masz naturalną bramkę czasową — każda linia kosztuje sekundy myślenia. Z agentem dostajesz 200 linii w dziesięć sekund. Objętość kodu, który „przelatuje” przez Twoją uwagę bez prawdziwej recenzji, rośnie o rząd wielkości. Luka w procesie review nie jest stała — skaluje się proporcjonalnie do tego, jak szybko generujesz kod.
Pewność siebie. To groźniejsze. Kod od modelu jest składniowo perfekcyjny: ma sensowne nazwy zmiennych, komentarze, obsługę błędów, każdy nawias domknięty. Wygląda jak kod seniora. Nasz mózg czyta tę estetykę jako sygnał kompetencji i obniża czujność. Tymczasem ładnytry/catch może łapać błąd i milcząco go połykać, a ładnie nazwana funkcjasanitizeInput może nie sanityzować niczego. Plausibilność to nie poprawność.
Do tego dochodzi halucynacja: model potrafi z pełnym przekonaniem wymyślić flagę konfiguracyjną, metodę SDK albo paczkę, której nie ma. W kontekście bezpieczeństwa to oznacza, że „włączyłem szyfrowanie” może być wywołaniem nieistniejącej opcji, która cicho nic nie robi.
Lista kontrolna przed wdrożeniem
Zanim wygenerowany kod pojedzie do produkcji, przejdź przez te punkty. Nie musisz robić wszystkiego ręcznie — większość da się zautomatyzować — ale żaden punkt nie może być pominięty „bo to tylko MVP”.
- Sekrety. Czy w diffie nie ma żadnego klucza, hasła, tokena? Czy wszystko wrażliwe siedzi w zmiennych środowiskowych, a
.envjest w.gitignore? - Wejście użytkownika. Czy każde zewnętrzne dane (request, formularz, parametr URL, plik) są walidowane i parametryzowane? Zapytania do bazy — nigdy przez konkatenację.
- Uprawnienia. Czy role, bucket-y i CORS są zawężone do minimum? Zasada najmniejszych uprawnień — domyślnie zamknięte, otwierasz tylko to, co konieczne.
- Zależności. Czy każda nowa paczka faktycznie istnieje, jest utrzymywana i nie ma znanych CVE? Sprawdź liczbę pobrań i datę ostatniej publikacji, zanim dodasz ją do
package.json. - Uwierzytelnianie i autoryzacja. Czy chronione endpointy naprawdę sprawdzają tożsamość i uprawnienia? Brak kontroli dostępu na poziomie obiektu to najczęstsza dziura w API.
- Obsługa błędów. Czy
catchnie połyka błędu po cichu? Czy komunikaty błędów nie wyciekają stack trace'ów ani danych wrażliwych do użytkownika? - Zrozumienie. Czy potrafisz wytłumaczyć, co robi każda nieoczywista linia? Jeśli nie rozumiesz fragmentu, nie wdrażasz go — prośba o wyjaśnienie modelu jest darmowa.
Narzędzia, które robią tę pracę za Ciebie
Lista kontrolna z głowy nie skaluje się. Na szczęście większość tych klas wykrywają automaty — i powinny być bramką w CI, nie opcją.
Skanowanie sekretów. Gitleaks albo TruffleHog jako hook pre-commit i krok w pipeline. Dodatkowo push protection na poziomie repozytorium (GitHub i GitLab mają to wbudowane). To pierwsza i najtańsza linia obrony — sekret, który nigdy nie trafił do historii, nie wymaga rotacji.
SAST — analiza statyczna. Semgrep, CodeQL albo Snyk Code czytają kod bez uruchamiania go i wyłapują wzorce injection, XSS czy niepewne API. Semgrep ma czytelną składnię reguł i łatwo dopisać własne pod Twój stack.
Audyt zależności. npm audit, Dependabot albo Snyk — sprawdzają znane podatności w drzewie zależności i podnoszą PR-y z aktualizacjami. Włącz to w CI z progiem: high i critical blokują merge.
Skan infrastruktury. Jeśli masz Terraform albo manifesty Kubernetes, Checkov lub tfsec wyłapią publiczny bucket i zbyt szeroką rolę IAM, zanim cokolwiek powstanie. To szczególnie ważne przy vibecodingu, bo modele chętnie generują konfigurację „na otwarto”, żeby tylko przeszła — bezpieczne domyślne ustawienia wymagają już świadomej decyzji człowieka.
Ważne: te narzędzia też dają fałszywe alarmy. Ich rolą nie jest zastąpić myślenia, tylko zredukować powierzchnię, którą musi przejrzeć człowiek. Zielony pipeline to nie certyfikat bezpieczeństwa — to brak znanych problemów.
Właściwe nastawienie: AI to szybki junior, nie audytor
Najzdrowszy model mentalny, jaki znam: traktuj asystenta jak bardzo zdolnego, bardzo szybkiego stażystę. Pisze imponująco dużo kodu, zna składnię lepiej niż Ty, nigdy się nie męczy. I — jak każdy junior — nie ma kontekstu Twojego systemu, nie ponosi konsekwencji incydentu i czasem mówi z pełną pewnością rzeczy nieprawdziwe.
Z juniorem nie robisz dwóch rzeczy: nie wdrażasz jego kodu bez review i nie robisz z niego recenzenta własnej pracy. Te same dwie zasady dotyczą modelu. Możesz poprosić AI o wskazanie potencjalnych problemów bezpieczeństwa — to bywa pomocne jako dodatkowa para oczu — ale to nie zwalnia z prawdziwej weryfikacji. Recenzent, który napisał kod, i tak ma ślepą plamkę dokładnie tam, gdzie popełnił błąd.
Odpowiedzialność za bezpieczeństwo zostaje przy człowieku, który naciska „deploy”. To nie kwestia nieufności wobec narzędzia — to kwestia tego, kto odbierze telefon o trzeciej w nocy.
TL;DR
Kod od AI nie jest z natury bezpieczny ani niebezpieczny — jest niesprawdzony. Realne ryzyka to stare znajome: sekrety w kodzie, injection, XSS, niepewne zależności, zbyt szerokie uprawnienia i ślepa wiara w ładnie wyglądający kod. AI pogarsza je przez prędkość i fałszywą pewność siebie. Obrona to lista kontrolna przed wdrożeniem plus automaty w CI: skan sekretów, SAST, audyt zależności, skan infrastruktury. Nastawienie, które działa: AI to szybki junior, a nie audytor bezpieczeństwa — review i odpowiedzialność zostają przy Tobie.