Waarom vibe-coded apps vaker kwetsbaar zijn
Apps gebouwd met Cursor, Bolt, Lovable, v0 of Replit Agent bevatten — keer op keer — dezelfde kwetsbaarheidspatronen. Niet omdat AI "slecht" is, maar omdat AI optimaliseert voor werkend, niet voor veilig. Een pentester-analyse van het probleem en wat eraan te doen.
Wat is vibe coding?
"Vibe coding" — een term die in 2025 viraal ging — beschrijft een nieuwe manier van software bouwen: in plaats van zelf code te schrijven, beschrijft de gebruiker wat de software moet doen aan een AI-tool, die vervolgens werkende code produceert. Cursor, Bolt.new, Lovable, v0, Replit Agent en Claude Code zijn de bekendste tools. Met een goede prompt heb je in een middag een werkende MVP.
Het effect op productontwikkeling is dramatisch. Solo founders bouwen in weken wat eerder een team van vijf in een halfjaar bouwde. Indie hackers gaan live met productie-applicaties zonder ooit een ORM, een security header of een autorisatiemodel handmatig te configureren.
Het effect op security is helaas net zo dramatisch — maar dan de andere kant op.
Het patroon dat we keer op keer zien
In nagenoeg elke vibe-coded applicatie die ik review duiken dezelfde klasses van kwetsbaarheden op. Dit is geen toeval, en het is geen onkundigheid van de bouwer. Het is een direct gevolg van hoe AI coding tools werken.
1. Missende autorisatie op endpoints
De AI genereert een endpoint zoals GET /api/users/:id. Authenticatie is aanwezig — de gebruiker moet ingelogd zijn. Maar autorisatie — de check of déze gebruiker dít specifieke user-object mag opvragen — ontbreekt. Resultaat: elke ingelogde gebruiker kan elk ander gebruikersaccount opvragen door simpelweg het ID in de URL te veranderen.
Waarom mist de AI dit? Omdat in de prompt stond "voeg authenticatie toe". Object-level access control stond er niet in. De AI heeft geen ingebouwde notie van "wie mag wat" — dat moet je expliciet uitleggen.
2. IDOR via sequentiele ID's
Hieraan gerelateerd: vrijwel alle vibe-coded apps gebruiken auto-increment integer ID's in URLs. ?order=1042 ophogen naar ?order=1043 en — als de autorisatiecheck mist (zie boven) — zie je iemand anders zijn bestelling, dossier, projectje of wat dan ook. Dit is de klassieke IDOR-kwetsbaarheid, en in vibe-coded code is hij vrijwel standaard aanwezig.
3. Hardcoded secrets en blootgestelde API-keys
Stripe-keys in client-side bundles. OpenAI-tokens in .env.local-bestanden gecommit naar git. Database-URLs in server-rendered Next.js pages die per ongeluk via getServerSideProps mee de client in gaan. Supabase service-role keys publiek toegankelijk.
De reden? De AI plaatst de key daar waar de feature "in één keer werkt". Dat is vaak de verkeerde kant van de netwerkgrens — server-only secrets belanden client-side, of nog erger, in publieke git repos.
4. Onveilige database-queries op edge cases
Goed nieuws: 80% van de tijd gebruikt de AI keurig een ORM met parameterized queries. Slecht nieuws: bij de andere 20% — vooral filter, search en advanced query features — wordt opeens user input rechtstreeks in een query string geconcatenateerd. Klassieke SQL injection, op het laatste feature dat je verwachtte.
5. Te ruime CORS
Access-Control-Allow-Origin: * in combinatie met credentials: 'include'. Werkt prima — en geeft elke willekeurige website toestemming om in naam van uw ingelogde gebruikers requests te doen naar uw API. Een fatale combinatie die door geen enkele scanner als kritiek wordt geflagd, omdat hij configuratie- en gebruiksspecifiek is.
Waarom doet de AI dit? Omdat de prompt was "los die CORS-error op". De AI lost het op met de meest permissieve configuratie die de error wegneemt.
6. Admin-routes die alleen client-side beschermd zijn
De React app heeft een mooi route-guard component dat checkt of user.role === 'admin'. Gebruiker omzeilen? Open de browser-devtools, of doe direct een request naar het API-endpoint. Server-side is er geen check — de admin route was visueel beschermd, niet werkelijk beschermd.
7. Supabase/Firebase met onbeschermde tabellen
Supabase en Firebase zijn enorm populair in vibe-coded apps — terecht, want ze schalen prima en het AI-model snapt ze. Maar: Row-Level Security (RLS) is bij Supabase standaard uit. De AI maakt tabellen aan, de data stroomt — en niemand zet RLS aan, of RLS-policies worden gemaakt die er goed uitzien maar via filterketens cross-tenant data toegankelijk maken.
8. Prompt injection & AI feature abuse
Als uw app een LLM aanroept met user input (een chatbot, een document-analyseflow, een AI-agent), dan is dat een aanvalsoppervlak. Gebruikers kunnen system prompts hijacken, data extracten uit context, of tools aanroepen die u niet bedoeld had. Dit is een complete nieuwe categorie van kwetsbaarheden waar de meeste vibe-coded apps geen verdediging tegen hebben — omdat het standaard niet bestaat, je moet het expliciet bouwen.
Waarom AI dit consistent fout doet
Even fundamenteel: dit zijn geen bugs in de AI-tools. Het zijn de directe gevolgen van hoe ze werken. Drie structurele oorzaken:
De trainingsdata is gemiddeld onveilige code
AI-coding tools zijn getraind op publieke code-repositories. Het mediaan-niveau van security in publieke code is laag — de meeste tutorials, voorbeeldprojecten en GitHub-snippets hebben geen productie-grade security. De AI imiteert wat hij gezien heeft.
De optimalisatiefunctie is "make it work"
Vraag een AI "fix this CORS error" en hij kiest de configuratie die het probleem wegneemt. Vraag hem "let users edit their profile" en hij bouwt een endpoint. Hij is niet getraind om te vragen: "moeten andere users dit kunnen zien? wie mag dit?" Die vragen stelt een ervaren ontwikkelaar — een AI niet.
Natural language is per definitie ambigu
Wanneer u zegt "let users edit their profile", denkt u: "users kunnen alleen hun eigen profiel editen". De AI denkt dat misschien ook — en bouwt het. Of niet — en bouwt een endpoint waar iedereen alle profielen kan editen. U weet pas welke van de twee als u de gegenereerde code grondig leest. En als u dat zou kunnen, had u het zelf wel geschreven.
Dit is geen kritiek op AI-tools of op vibe coders. AI-tools zijn buitengewoon — ze comprimeren maanden in dagen. Het punt is alleen: shipped functionaliteit ≠ shipped security. En dat gat moet iemand bewust dichten.
Waarom scanners deze problemen missen
"Run gewoon Snyk, Semgrep of Dependabot" is het standaard-advies. Nuttig — voor bekende CVE's en library-kwetsbaarheden. Maar het bovenstaande patroon is bijna volledig logica, autorisatie en architectuur. Dat is:
- Niet pattern-matchable — het hangt af van uw datamodel en bedoelde toegangsregels
- Niet in een signature-database — het is business logic, geen library-bug
- App-specifiek — een scanner weet niet wie wat zou moeten zien
- Vaak verspreid over meerdere files — een aanvaller combineert drie kleine zaken tot één breach
De enige manier om ze te vinden is dat een mens als aanvaller denkt terwijl hij door uw applicatie heen werkt. Dat is wat een pentest doet.
Wat u eraan kunt doen — voor en tijdens het bouwen
Stel autorisatie expliciet
Bij elke nieuwe feature: in de prompt opnemen "make sure only the owner can read/edit/delete". Dat ene zinnetje verandert wat de AI bouwt. Standaard zou het de check niet inbouwen — gevraagd doet hij het wel.
UUIDs in plaats van auto-increment ID's
Default: gebruik UUIDs als public resource identifiers. Auto-increment ID's blijven prima als interne database-keys, maar exposeer ze niet in URLs. Dit elimineert IDOR-via-guessing als hele klasse.
RLS aanzetten — direct
Voor Supabase/Firebase: zet Row-Level Security per tabel áán bij creatie, niet later. Test policies door als andere user te queryen. Een policy die compileert is niet hetzelfde als een policy die juist filtert.
Lees zelf wat de AI bouwt
Dit is moeilijk maar essentieel. Voor elk endpoint dat user data raakt: lees de gegenereerde code. Zoek naar autorisatiechecks. Vraag de AI: "audit this endpoint for authorization, IDOR, and input validation issues — what's missing?" — en hij vindt vaak zelf de problemen.
Plan een pentest vóór serieuze launch
Voordat u live gaat met betalende klanten, voordat u personenidentificeerbare informatie verwerkt, voordat een investeerder due diligence doet — laat een handmatige pentest uitvoeren. Een week werk, vaste prijs, met een rapport in begrijpelijke taal. Resync's vibe-coded app security audit is precies hierop ingericht.
Conclusie
Vibe coding is een geweldige ontwikkeling — voor productontwikkeling, voor solo founders, voor experimenten. Maar security is een eigenstandige discipline die de AI niet voor u doet. De vulnerability-patronen in vibe-coded apps zijn voorspelbaar, en dat is goed nieuws: voorspelbare problemen zijn oplosbaar.
Wat niet werkt: hopen dat het wel goed komt. Wat wel werkt: bewust security in uw prompts inbouwen, RLS standaard aan, UUIDs als public IDs, en — vóór serieuze launch — een onafhankelijke pentest. Ship fast. Stay secure.
Audit uw vibe-coded app.
Handmatige pentest specifiek voor AI-gegenereerde apps. Vaste prijs, 1 week doorlooptijd, hertest inbegrepen.
Naar de dienst-pagina →