← Terug naar de blog
Vibe CodingScanaris Team · 9 min lezen · October 03, 2026

Beveiligingschecklist voordat je je met AI gebouwde app lanceert

Snel lanceren is prima, maar er is een korte lijst die je het beste even naloopt voordat je je app voor de wereld openzet. Niets ervan vereist dat je beveiligingsexpert bent, en alles is in een paar minuten van buitenaf te controleren. Deze gids behandelt elk punt met drie dingen: waarom het ertoe doet, hoe je het zelf controleert en hoe je het oplost, met configuratievoorbeelden voor de stacks die AI-gebouwde apps het meest gebruiken (Next.js op Vercel, Supabase, Firebase). Aan het eind krijg je de versie van twee minuten om in je lanceerlijst te plakken.

Hoe aanvallers dit in minuten vinden

De meeste inbraken in AI-gebouwde apps zijn geen slimme hacks. Iemand opent je site, drukt op F12, leest de JavaScript die je app al naar zijn browser heeft gestuurd en kopieert een URL die je app toch al aanroept. Geautomatiseerde scanners doen hetzelfde op grote schaal en kloppen aan op gangbare paden als /.env of /.git bij duizenden sites per dag zonder zelfs te weten dat je bestaat. Alles hieronder kunnen ze controleren zonder enige toegang tot je code, en precies daarom moet jij het als eerste controleren.

1. Geen secrets in de frontend

Waarom het ertoe doet. API-keys en tokens horen alleen op de server. Als een AI-assistent een dienst "koppelt", zet hij de key vaak rechtstreeks in de clientcode, waar iedereen hem in de DevTools kan lezen. Een gelekte Stripe-sk_live_-key kan echt geld verplaatsen; een Supabase-service_role-key geeft je hele database weg; een OpenAI- of Anthropic-key laat jou de rekening van een ander betalen.

Zo controleer je het. Open je site, druk op F12 → tabblad Sources (of Network gefilterd op JS) en doorzoek de bestanden op strings als sk_live, service_role, AKIA, sk-ant, AIza of -----BEGIN. Gebruikt je framework variabelen met een publiek voorvoegsel (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_), zorg dan dat geen ervan een secret bevat: dat voorvoegsel betekent letterlijk "dit gaat naar de browser".

Zo los je het op. Verplaats elk secret naar een omgevingsvariabele op de server en doe de aanroep vanuit een API-route of serverless functie; de browser praat met jouw server, nooit met de aanbieder. En roteer de gelekte key: zodra hij in een publieke bundle heeft gezeten, beschouw je hem als gecompromitteerd, ook nadat je hem hebt verwijderd. Meer in de secrets die je app in de browser lekt.

2. HTTPS en security headers

Waarom het ertoe doet. Serveer alles over HTTPS en stuur HTTP ernaartoe door, zodat niemand het verkeer kan lezen of manipuleren. Voeg daarna de headers toe waarmee browsers je gebruikers verdedigen: Content-Security-Policy om injectie in te dammen, Strict-Transport-Security om HTTPS vast te zetten, X-Frame-Options tegen clickjacking en X-Content-Type-Options zodat de browser bestandstypen niet "raadt". De meeste gegenereerde apps komen standaard zonder een van deze.

Zo controleer je het. Vraag je site op met curl -I https://jouwdomein.nl en bekijk de headers die terugkomen, of gebruik de gratis security headers checker.

Zo los je het op. In Next.js declareer je ze in next.config.js; op Vercel, voor elk framework, in vercel.json:

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
        { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
      ]
    }
  ]
}

De CSP verdient een eigen moment: begin in de modus Content-Security-Policy-Report-Only, kijk wat hij zou blokkeren en zet hem op afdwingen zodra hij niets meer breekt. Zie HTTP security headers uitgelegd.

3. Databaseregels (RLS) op elke tabel

Waarom het ertoe doet. Gebruik je Supabase of Firebase, dan praat je app rechtstreeks vanuit de browser met de database, dus de databaseregels zijn het enige dat tussen een bezoeker en je data staat. Zonder die regels leest en beschrijft iedereen met de publieke key je tabellen zonder in te loggen: precies de fout achter het RLS-lek van Lovable.

Zo controleer je het. Kopieer met de app open een /rest/v1/-aanroep uit het tabblad Network en open hem in een incognitovenster. Geeft hij data terug zonder sessie, dan lig je bloot. In Supabase markeert de Table Editor tabellen met een rode badge "RLS disabled". In Firebase controleer je dat de regels niet nog in testmodus staan (allow read, write: if true of met een vervaldatum).

Zo los je het op. Zet Row-Level Security aan op elke tabel met een standaard-weigeren-policy en schrijf regels per operatie die aan de gebruiker gekoppeld zijn. In Supabase het minimum voor een tabel met een kolom user_id:

alter table public.items enable row level security;

create policy "items: alleen eigen rijen" on public.items
  for all to authenticated
  using ((select auth.uid()) = user_id)
  with check ((select auth.uid()) = user_id);

En vertrouw nooit op een verborgen knop in de UI: de aanvraag bestaat nog steeds.

4. Geen blootgestelde gevoelige bestanden

Waarom het ertoe doet. Eén aanvraag naar /.env kan elk secret weggeven dat je app gebruikt; /.git/config laat iedereen je hele repository downloaden; gepubliceerde source maps laten hem je originele code reconstrueren; een vergeten backup.sql is je database in een bestand.

Zo controleer je het. Probeer jouwdomein.nl/.env, /.git/HEAD, /.DS_Store, /backup.sql in de browser, en open een JS-bestand uit je bundle om te zien of het eindigt op een regel //# sourceMappingURL= die naar een bereikbare .map wijst. Op platforms als Vercel of Netlify wordt de .env nooit gedeployd, maar op een VPS met nginx of Apache gebeurt het.

Zo los je het op. Blokkeer dotfiles op de server (in nginx location ~ /\. { deny all; }), schakel source maps uit in productie (productionBrowserSourceMaps: false in Next.js, build.sourcemap: false in Vite) en haal back-ups uit de publieke map.

5. CORS dichtgetimmerd

Waarom het ertoe doet. Een CORS-beleid dat elke origin met credentials weerspiegelt, laat een kwaadaardige site de data van je gebruikers lezen met hun sessie. Access-Control-Allow-Origin: * zonder credentials is onschadelijk voor publieke data; het gevaar is om elke vragende origin terug te kaatsen en Access-Control-Allow-Credentials: true toe te voegen.

Zo controleer je het. Vraag een van je API-endpoints op met curl -I -H "Origin: https://evil.example" https://jouwdomein.nl/api/ietswat. Geeft het antwoord diezelfde origin terug in Access-Control-Allow-Origin plus Allow-Credentials: true, dan heb je het probleem.

Zo los je het op. Houd een gesloten lijst van toegestane origins bij (je productiedomeinen en hooguit je preview-domein) en vergelijk daarmee; elke andere origin krijgt geen header.

6. Cookies en sessies goed ingesteld

Waarom het ertoe doet. Sessiecookies horen Secure (alleen HTTPS), HttpOnly (onleesbaar vanuit JavaScript, zodat een XSS ze niet kan stelen) en SameSite=Lax of Strict (verdedigt tegen CSRF) te dragen. Het is één regel configuratie en sluit een hele klasse account-overnamebugs.

Zo controleer je het. F12 → Application → Cookies en bekijk de kolommen Secure, HttpOnly en SameSite van je sessiecookie. Gebruik je een auth-provider (Supabase Auth, Clerk, NextAuth), dan komen ze meestal goed; de cookies die falen zijn die je eigen app toevoegt.

Zo los je het op. Bij het zetten van de cookie: Set-Cookie: session=…; Secure; HttpOnly; SameSite=Lax; Path=/. In Express: res.cookie(name, value, { secure: true, httpOnly: true, sameSite: 'lax' }).

7. Dependencies met bekende kwetsbaarheden

Waarom het ertoe doet. Je app sleept honderden packages mee. Een kwetsbare versie van een bibliotheek die gebruikersinvoer parset, is een ingang die jij niet hebt geschreven maar die toch van jou is.

Zo controleer en los je het op. Draai npm audit in het project en los eerst de kritieke en hoge bevindingen op; schakel Dependabot of Renovate in op de repository zodat patches naar je toe komen. Stelt je site een publieke package.json bloot, dan adverteer je ook je versies.

8. Rate limits op endpoints die geld kosten of deuren openen

Waarom het ertoe doet. Het inlogformulier, de registratie, het versturen van e-mail en elk endpoint dat een betaalde AI-API aanroept, hebben een limiet per IP of per account nodig. Zonder probeert een script duizenden wachtwoorden of jaagt het 's nachts een tokenrekening omhoog.

Zo los je het op. Een eenvoudige rate limit aan de serverkant (per IP en per minuut) en bij betaalde aanbieders een uitgavenplafond in hun dashboard. Auth-providers leveren meestal al actieve pogingenlimieten: controleer dat je ze niet hebt uitgezet.

9. Fouten die niet te veel prijsgeven

Waarom het ertoe doet. Een foutpagina met de volledige stack trace, de SQL-query of het serverpad is een kaart voor wie aanvalt. Hetzelfde geldt voor headers als X-Powered-By die exacte versies aankondigen.

Zo los je het op. Generieke foutpagina's in productie, met de details alleen in je logs. Verwijder X-Powered-By (in Next.js poweredByHeader: false).

10. Domein en e-mail klaar voor echte gebruikers

Waarom het ertoe doet. Verstuur je e-mail (bevestigingen, wachtwoordresets), dan belandt die zonder SPF, DKIM en DMARC in de spam of, erger, kan iedereen mail versturen uit naam van jouw domein. En een verlopend certificaat of domein haalt de hele site onderuit.

Zo controleer en los je het op. Publiceer SPF- en DMARC-records in de DNS, schakel DKIM in bij je verzendprovider en zet automatische verlenging aan voor domein en certificaat. Een halfuur werk dat de slechtst mogelijke dag voorkomt.

In welke volgorde je het aanpakt als je een uur hebt

  • Eerst secrets in de frontend en databaseregels: de twee fouten die echte data aan iedereen weggeven.
  • Dan blootgestelde bestanden en CORS: goedkoop op te lossen en zwaar afgetast door geautomatiseerde scanners.
  • Vervolgens headers, cookies en foutpagina's: ze verharden wat al werkt.
  • Als laatste dependencies, rate limits en e-mail: minder urgent op de lanceerdag, onmisbaar de week erna.

Je checklist van 2 minuten vóór de lancering

  • Geen sk_live_, service_role of privésleutels in je JavaScript; publieke variabelen nagekeken.
  • HTTPS afgedwongen, met HSTS, X-Frame-Options, X-Content-Type-Options en een CSP minstens in rapportmodus.
  • Row-Level Security (of Firebase-regels) op elke tabel; de incognitotest geeft leeg terug.
  • .env, .git, back-ups en source maps niet bereikbaar.
  • CORS beperkt tot je eigen origins, nooit de origin met credentials terugkaatsen.
  • Cookies met Secure, HttpOnly en SameSite.
  • npm audit schoon van kritieke en hoge bevindingen.
  • Pogingenlimieten op inloggen, registratie en AI-endpoints; uitgavenplafonds bij aanbieders.
  • Foutpagina's zonder traces; geen X-Powered-By.
  • SPF, DKIM en DMARC gepubliceerd; automatische verlenging van domein en certificaat.

Gewoon even regelen

In plaats van dit allemaal met de hand te controleren, draai je Scanaris: het controleert deze punten en zo'n 40 andere op je live site in 30 seconden, rangschikt de bevindingen op impact en geeft je een kant-en-klare prompt om elk ervan met je AI op te lossen, voordat iemand anders ze vindt. Zet monitoring aan en het vertelt je wanneer er na de lancering weer iets van deze lijst breekt.

Veelgestelde vragen

Vervangt dit een professionele beveiligingsaudit?

Nee. Deze lijst dekt wat van buitenaf te controleren is en wat in bijna elke AI-gebouwde app misgaat. Een audit bekijkt ook je bedrijfslogica, de rechten tussen gebruikers en de code zelf. Maar zonder deze lijst zou de audit met dezelfde punten beginnen.

Hoe lang duurt dit allemaal?

Controleren: tien minuten met een scanner of een halfuur met de hand. Oplossen: tussen een middag en een dag, afhankelijk van hoeveel punten falen; secrets en RLS kosten het meeste tijd omdat ze je dwingen code naar de server te verplaatsen.

En na de lancering?

Herhaal de lijst elke keer dat de AI een nieuwe functie genereert die data of keys raakt, en stel een wekelijkse automatische herscan in: apps breken door veranderingen, niet door tijd.

Hoe staat je site ervoor?

Laat Scanaris er even overheen gaan en check het in 30 seconden, gratis.

Mijn site scannen

Gerelateerde checks

Beveiligingsgidsen per stack