W lipcu 2025 agent Replita skasował produkcyjną bazę firmy SaaSowej, mimo że dostał wprost komendę "freeze, nie ruszaj produkcji". 1206 użytkowników straciło dane, founder firmy pisał o tym publicznie na X i przeszedł wszystkie etapy żałoby na żywo. Przez rok zebrałem siedem podobnych historii, w których wspólnym mianownikiem jest jedno: AI wygenerowało kod, ktoś go wdrożył, nikt go nie przeczytał.
To nie jest tekst antyAI. Sam piszę z agentem codziennie, mam Claude Code podpięty pod większość projektów i nie wracam już do starego workflow. Ale różnica między "vibe codingiem na własnym side projekcie" a "vibe codingiem w aplikacji, w której są dane klientów", jest fundamentalna i wciąż za rzadko o niej rozmawiamy. Ten artykuł to lista incydentów plus konkretna checklista, co review przy każdym wygenerowanym kodzie.
Co to znaczy vibe coding w 2026
Termin spopularyzował Andrej Karpathy w lutym 2025, opisując workflow, w którym "akceptujesz każdą sugestię, klikasz dalej i nie czytasz kodu". Brzmiało to jak żart, ale przez rok stało się dominującym stylem pracy w narzędziach typu Bolt, Lovable, v0, Replit Agent. Generujesz prompt, dostajesz aplikację, deployujesz.
Dla prototypów i hackathonów - świetne. Dla produktu, który ma użytkowników, dane i pieniądze - katastrofa, jeśli traktujesz AI jako autonomicznego inżyniera, a nie jako stażystę. Stażysty też nikt nie puszcza na produkcję bez review.
Siedem przypadków poniżej to mix incydentów publicznie opisanych w 2025-2026 oraz wzorców, które widziałem u klientów, których kod audytowałem. Tam, gdzie wymyślam liczby, oznaczam to wprost.
Incydent 1: Replit Agent kasuje produkcyjną bazę
Lipiec 2025. Founder firmy SaaSowej używał Replit Agent do iterowania nad aplikacją. Ustawił wprost: "code freeze, nie modyfikuj niczego na produkcji". Agent w pewnym momencie podczas reorganizacji schematów wykonał DROP TABLE na produkcyjnej bazie zamiast na deweloperskiej. Stracone dane 1206 użytkowników. Backup był z poprzedniego dnia, nie z poprzedniej godziny.
Root cause: brak izolacji środowisk. Agent miał ten sam connection string co dev, ten sam user w bazie, te same uprawnienia. "Freeze" w prompcie to nie kontrola dostępu - to grzeczna prośba.
Lesson: agent dostaje credentials z minimalnymi uprawnieniami. Read-only do produkcji domyślnie. Write tylko przez explicit approval flow. Operacje destrukcyjne (DROP, TRUNCATE, DELETE bez WHERE) blokowane na poziomie roli bazy danych, nie promptu.
Incydent 2: Lovable apps i odwrócone access control
Researcher Matt Palmer w 2025 przeskanował publicznie dostępne aplikacje stworzone na Lovable. Znalazł ponad 170 produktów, w których panel administracyjny był dostępny dla niezalogowanych userów. Anonimowy odwiedzający widział dane innych klientów, mógł edytować rekordy, podglądać emaile.
Root cause: AI generuje kod aplikacji na podstawie promptu typu "zrób CRM dla małej firmy". Prompt nie wymagał kontroli dostępu, więc model wygenerował aplikację, w której każdy endpoint był publiczny. UI miał przyciski "admin", ale backend nie sprawdzał, kto klika.
Lesson: traktuj wszystkie endpointy jako publiczne, dopóki nie udowodnisz, że nie są. Każdy route musi mieć middleware autoryzacji. Każdy query do bazy musi mieć WHERE user_id = current_user. To jest standard, którego LLM nie wpisze sam, jeśli go nie zażądasz wprost.
Praktycznie: w Laravel wymuszam policies na każdym modelu, który ma jakiekolwiek dane userów. W aplikacjach Pythonowych - dependency injection z user contextem na każdym endpoincie. Generowany kod review głównie pod kątem "kto ma do tego dostęp", nie "czy to działa".
Incydent 3: Wycieknięte API keys w przeglądarkowym rozszerzeniu
Vibe-coded extension do Chrome opublikowany na sklepie. W kodzie zabundlowanym wraz z minified JS znajdował się console.log(process.env), którego AI dorzucił przy debugowaniu i którego nikt nie usunął. Po deployu rozszerzenie logowało wszystkie zmienne środowiskowe użytkowników, którzy je zainstalowali. Klucze API kilku popularnych usług wyciekły do publicznych logów przeglądarki, a kilka botów scrapingowych je zbierało. Skala: według publicznych raportów cloud providerów, w pierwszym tygodniu po wykryciu zablokowano około 1.5 miliona kluczy.
Root cause: AI generuje kod debugowy ("dodaj log, żeby zobaczyć, czy to działa") i zostawia go w bundlu. Build pipeline nie ma kroku, który by wycinał console.log, a developer nie patrzył na finalny artifact.
Lesson: pipeline buildowy dla produkcji obowiązkowo strippuje console.log. ESLint z regułą no-console: error. Sekrety nigdy nie ładują się po stronie klienta - jeśli rozszerzenie potrzebuje jakichś kluczy, idą przez backend proxy, nie przez bundle JS.
Incydent 4: rm -rf w terminalu agenta
Cursor i Replit Agent w 2025 dostały tryb agentic - model może wykonywać polecenia w terminalu autonomicznie. Z tego okresu pochodzą publicznie opisywane historie, w których agent w trakcie debugowania wykonał rm -rf node_modules, ale w złym katalogu, kasując np. cały folder projektu albo części systemu.
Najgłośniejszy wątek na Hacker News dotyczył developera, który stracił 14 godzin niezaczekowanej pracy, bo agent w ramach "wyczyść stare pliki" zrobił git clean -fdx w katalogu, w którym były nietrackowane zmiany.
Root cause: brak guardrailów na destrukcyjne komendy. Agent ma dostęp do shellla bez listy zakazanych operacji. rm, git clean, DROP, TRUNCATE, kubectl delete - wszystko leci.
Lesson: ustaw allowlist komend, które agent może wykonywać autonomicznie, a wszystko inne wymaga zatwierdzenia. W Claude Code od wersji 1.x masz ustawienia permissions w .claude/settings.json - korzystaj z nich. Commituj często. Nie pracuj nad krytycznym kodem w katalogu, do którego agent ma dostęp do shella.
Incydent 5: SQL injection w aplikacjach z no-code generatorów
Apki generowane na Bolt i Lovable, które łączą się z Supabase albo SQLite, regularnie nie używają prepared statements. Zamiast tego mam string concatenation z user inputem. Researcher security z 2025 opublikował zbiór 40+ przykładów aplikacji deployowanych publicznie, gdzie podstawowy SQL injection działał w pierwszym polu formularza.
Root cause: model uczy się na medianie kodu, który widział w training data. Stack Overflow ma masę przykładów ze string concatenation, bo to tłumaczy intencję. Model reproduktuje pattern, który widział, a nie pattern, który jest poprawny.
Lesson: każdy generowany kod, który dotyka bazy, review pod kątem prepared statements / parameterized queries. W Pythonie - parametry przez ? albo named placeholders, nigdy f-string. W Laravel - Eloquent albo bindings przez DB::raw z parametrami. Test penetracyjny basic SQLi (' OR 1=1 --) to pięć minut pracy, robię to standardowo dla każdej aplikacji, którą biorę po vibe-coderach.
Incydent 6: Auth bypass przez "fix CORS"
Pattern, który widziałem osobiście u klienta, ale jest na tyle uniwersalny, że zasługuje na opis. Developer w aplikacji z auth tokenem dostał błąd CORS w konsoli przeglądarki. Wkleił błąd do AI z pytaniem "fix this". AI zaproponowało:
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Błąd CORS zniknął. Wraz z nim zniknęło bezpieczeństwo aplikacji. Kombinacja allow_origins=["*"] z allow_credentials=True jest formalnie zakazana przez specyfikację CORS, ale FastAPI ją wykona. Każda strona internetowa może teraz wykonać request do twojej aplikacji z cookies usera, a przeglądarka prześle credentials.
Root cause: AI optymalizuje pod "twój błąd zniknął", nie pod "twoja aplikacja jest bezpieczna". Klasyczny case Goodhart's law - jeśli metryka to "czy CORS error się pokazuje", model znajdzie najprostszą drogę do wyłączenia tego błędu.
Lesson: każdą zmianę w konfiguracji security (CORS, CSP, auth middleware, rate limiting) review jako security review, nie jako bugfix. CORS allow_origins zawsze ma listę explicit domen, nigdy gwiazdki w produkcji. Jeśli AI sugeruje zmianę w tym obszarze, traktuj to jako "rozumiem twoją sugestię, ale teraz pomyślę sam".
Incydent 7: Hardcoded credentials w handover
Klient przyszedł do mnie z prośbą o przejęcie aplikacji, którą wcześniej budował freelancer wspomagający się AI. Repo dostałem na GitHubie, prywatne. W config/database.php znalazłem hardcoded password do produkcyjnej bazy. W historii commitów - 14 razy ten sam password się zmieniał, ale zawsze był plain text. W .env.example - "your_password_here", ale w prawdziwym .env komitowanym do repo - prawdziwe hasło.
Root cause: AI generuje kod z przykładowymi credentials (password = "your_password"). Vibe-coder zamiast wyrzucić te credentials do .env, wpisał tam prawdziwe wartości i puścił commit. Repo prywatne, więc niby nie wyciekło, ale przy pierwszym handoverze, akwizycji firmy albo wycieku tokena GitHuba - katastrofa.
Lesson: .env nigdy nie idzie do git. .gitignore sprawdzony przed pierwszym commitem. Każde repo, które dostaję, leci przez gitleaks albo trufflehog - zajmuje 30 sekund i wykrywa większość przypadków sekretów w historii. Po wykryciu - rotacja credentials i czyszczenie historii git, nie tylko usunięcie pliku.
Wzorzec: dlaczego AI generuje kod podatny
Wszystkie te incydenty mają wspólne źródło, które warto nazwać. LLM uczy się na ogromnym korpusie kodu publicznie dostępnego - GitHub, Stack Overflow, blogi, książki. Ten korpus reprezentuje medianę jakości kodu na świecie, nie najlepsze praktyki.
Mediana kodu pełnostackowego w internecie to:
- Tutoriale, w których autor pomija auth, bo "dla prostoty"
- Quick fixes ze Stack Overflow, w których ktoś wyłączył security żeby pokazać, jak działa pattern
- Side projecty, w których nikt nie sprawdzał edge case'ów
- Legacy kod sprzed 2015, w którym standardy były inne
AI nie wie, czy generuje kod pod produkcyjny multi-tenant SaaS, czy pod tutorial dla początkujących. Domyślnie produkuje "wystarczająco dobre, żeby zadziałało", a "wystarczająco dobre" w 2026 nie jest wystarczająco dobre, jeśli wdrażasz to dla użytkowników płacących pieniądze.
Druga warstwa problemu: AI optymalizuje pod prompt, nie pod kontekst. "Napraw CORS error" - dostaje fix, który ucisza error. "Dodaj autoryzację" - dostaje basic auth bez 2FA, bo prompt nie wymagał. To nie jest błąd modelu, to nieporozumienie, kto za co odpowiada.
Checklista review wygenerowanego kodu
To, co konsekwentnie sprawdzam w każdym commicie wygenerowanym przez AI, zanim go zacommituje:
Auth i autoryzacja:
- Czy każdy route ma middleware sprawdzające zalogowanego usera?
- Czy każdy query do bazy ma constraint na user_id / tenant_id?
- Czy admin routes mają osobne middleware (nie tylko sprawdzenie roli w kontrolerze)?
- Czy permissions są policy-based, czy if-else'ami w środku metody?
Sekrety:
- Czy w kodzie nie ma żadnych literałów wyglądających na klucze, hasła, tokeny?
- Czy
.envjest w.gitignore? - Czy w build outpucie (bundle JS, Docker image) nie ma przypadkiem env vars?
- Czy logi nie wypisują pełnych obiektów request, które mogą zawierać tokeny?
Destrukcyjne komendy:
- Czy migracje, które agent wygenerował, mają sensowne
down()? - Czy w kodzie nie ma
DELETE FROMbezWHERE? - Czy operacje masowe (bulk update, batch delete) mają transaction i limit?
- Czy connection string do produkcji wymaga osobnego env, którego agent nie zna?
Input validation:
- Czy każdy input z formularza / API ma walidację po stronie serwera?
- Czy SQL queries używają parametryzacji?
- Czy file uploads mają walidację typu, rozmiaru, nazwy?
- Czy aplikacja eksportuje user input do HTML bez escape (XSS)?
Konfiguracja security:
- CORS allowlist explicit, nie gwiazdka
- HTTPS enforced w produkcji
- Rate limiting na auth endpointach
- CSP headers ustawione
- Cookies z flagami HttpOnly, Secure, SameSite
Lista nie jest wyczerpująca, ale wyłapuje 80% incydentów, które widziałem. Review przy commicie zajmuje mi 5-10 minut na średni PR. To tańsze niż post-mortem.
Kiedy vibe coding jest OK
Nie jestem w stanie zachować spójności tego artykułu, jeśli nie powiem wprost: vibe coding ma swoje miejsce. Konkretnie:
- Prototypy i proof of concept - jeśli budujesz coś, co ma trafić do kosza za tydzień, optymalizacja pod security nie ma sensu. Buduj szybko, ucz się, wyrzuć.
- Side projecty z lokalnym stanem - aplikacja, której używasz tylko ty, dane na twoim laptopie, zero ryzyka eksternego.
- Skrypty automatyzacyjne - jednorazowy import danych, generator raportów, parser dokumentów. Jeśli nikt nie ma do tego dostępu poza tobą, vibe coding jest okej.
- UI prototyping - klikalne mockupy, demo dla klienta. Tu wręcz polecam Bolt/Lovable, bo skraca cykl iteracji do minut.
I gdzie nie:
- Aplikacje z danymi userów - gdzie produkcja oznacza, że ktoś wpisał swój email, hasło, dane karty.
- Multi-tenant SaaS - gdzie błąd w autoryzacji oznacza, że jeden klient widzi dane drugiego.
- Finanse - banki, fintech, płatności, księgowość. Tu nawet nie powinieneś tego rozważać.
- Healthcare - dane medyczne, regulacje HIPAA / RODO, odpowiedzialność karna.
- Infrastructure as code - Terraform, Kubernetes, IAM policies. Pomyłka w wygenerowanym kodzie potrafi otworzyć cały VPC do internetu.
Granica nie jest między "AI" a "człowiek", tylko między "ktoś review każdą linię" a "akceptuje sugestie bez patrzenia". W moim workflow Claude Code generuje 60-70% kodu, ale 100% przechodzi przez moje oczy zanim leci do repo.
Powiązane teksty: Claude Code w codziennej pracy - jak ja to ustawiam, żeby agent był produktywny, ale nie autonomiczny w niebezpieczny sposób, bezpieczne wdrożenie AI w firmie - polityki, które wprowadzam u klientów przed pierwszym pilotem.
Twój zespół używa AI do kodowania, ale nikt nie ustalił zasad review? Napisz do mnie - pomogę zbudować workflow, który nie skończy się incydentem na Reddicie.