Vibe Coding Security: So machst du KI-Code wirklich sicher
Das Security-Unternehmen Escape hat 5.600 öffentlich erreichbare Vibe-Coding-Apps gescannt, also Anwendungen, die zu großen Teilen von KI generiert wurden. Das Ergebnis: über 2.000 Schwachstellen und rund 400 offen einsehbare Secrets, darunter API-Keys und Datenbank-Zugänge. Das eigentlich Bemerkenswerte daran ist nicht die Zahl selbst. Es ist die Tatsache, dass all diese Apps funktioniert haben. Sie sahen fertig aus, sie liefen, sie waren online. Und genau das ist die Falle.
Vibe Coding hat verändert, wer heute Software veröffentlicht. Du beschreibst, was du willst, die KI schreibt den Code, und aus einer Idee wird an einem Wochenende eine echte App. Was dabei gern untergeht: Funktionieren und Sicherheit sind zwei völlig verschiedene Eigenschaften. Der Browser zeigt dir sofort, ob etwas funktioniert. Ob es sicher ist, zeigt dir niemand, bis es jemand ausnutzt.
Ich baue seit über 20 Jahren Software im Bereich Web und arbeite selbst täglich mit Claude Code. Das hier wird also kein Anti-KI-Artikel, im Gegenteil: Ich halte KI-gestütztes Entwickeln für den größten Produktivitätssprung meiner Laufbahn. Aber ich sehe eben auch, was passiert, wenn generierter Code ungeprüft in Produktion geht. Die Lücken, die dabei entstehen, sind keine exotischen Spezialfälle. Es sind immer wieder dieselben vier Klassiker.
Genau die schauen wir uns an. Zuerst die Zahlen, damit du das Problem einordnen kannst. Dann die vier häufigsten Lücken in KI-Code, jeweils mit echtem Code in unsicher und sicher. Danach wird es konstruktiv: wie du KI so einsetzt, dass sie dir keine Lücken einbaut. Und am Ende gibt es, wie immer, eine ehrliche Einordnung ohne Panikmache.
Was Vibe Coding ist und warum gerade jetzt
Der Begriff stammt von Andrej Karpathy, ehemals KI-Chef bei Tesla und Mitgründer von OpenAI. Gemeint ist ein Arbeitsstil, bei dem du der KI in normaler Sprache beschreibst, was du bauen willst, den generierten Code weitgehend akzeptierst und dich vom Ergebnis leiten lässt. Du gibst die Richtung vor, die KI tippt. Der Name ist Programm: Du folgst dem Vibe, nicht jeder einzelnen Zeile.
Die Werkzeuge dafür sind 2026 überall. Claude und ChatGPT schreiben dir komplette Endpoints in den Chat, Editoren wie Cursor bauen ganze Features direkt im Projekt um, und Plattformen wie Lovable oder v0 machen aus einem Absatz Text eine deploybare Anwendung samt Datenbank. Die Einstiegshürde ins Programmieren war nie niedriger, und das ist erstmal eine großartige Nachricht. Leute, die vor zwei Jahren an der Frage gescheitert wären, wie man ein Projekt überhaupt aufsetzt, veröffentlichen heute eigene Tools.
Genau diese Erfolgsgeschichte hat aber eine Kehrseite: Es entsteht gerade so viel Code wie nie zuvor, geschrieben von Systemen, die auf “läuft” optimieren, geprüft von Menschen, die oft noch nicht wissen, wonach sie schauen müssten. Wie groß das Problem ist, lässt sich inzwischen beziffern.
Die Zahlen: Wie unsicher KI-Code wirklich ist
Zu KI-generiertem Code gibt es mittlerweile eine ganze Reihe von Untersuchungen. Sie messen Unterschiedliches, ergeben zusammen aber ein klares Bild. Drei davon reichen:
| Untersuchung | Ergebnis |
|---|---|
| Carnegie Mellon University, Studie zu KI-Code | 61 Prozent funktional korrekt, aber nur 10,5 Prozent sicher |
| Escape, Scan von 5.600 live Vibe-Coding-Apps | über 2.000 Schwachstellen, rund 400 offen einsehbare Secrets |
| GitHub-Großanalyse von 7.703 KI-Dateien | rund 12 Prozent mit Schwachstelle, bei Python fast jede fünfte Datei |
Was bedeutet das? Auf den ersten Blick wirken die Zahlen widersprüchlich: Die eine Analyse findet in rund 12 Prozent der Dateien eine Lücke, die andere hält fast 90 Prozent des Codes für unsicher. Der Grund ist, dass sie Verschiedenes messen. Die GitHub-Großanalyse von 7.703 KI-Dateien zählt, wie viele Dateien eine konkrete Schwachstelle enthalten, und landet bei etwa 12 Prozent, bei Python fast jeder fünften. Carnegie Mellon prüft strenger, nämlich ob eine Lösung Angriffen wirklich standhält, und findet nur 10,5 Prozent, die das tun. Und Escape zeigt, was am Ende in der echten Welt herauskommt: über 2.000 Lücken in Apps, die alle live und benutzbar waren.
Die eigentliche Botschaft steckt in der CMU-Zahl. 61 Prozent des Codes tun, was sie sollen, aber nur ein Bruchteil davon ist auch sicher. Dazwischen liegt eine Grauzone: Code, der in jeder Demo glänzt und trotzdem angreifbar ist. Genau diese Grauzone ist das Problem, denn sie fühlt sich nach Erfolg an. Die App läuft, die Nutzer kommen, und niemand ahnt, dass die Tür offen steht.
Und ja, automatisierte Scanner melden gelegentlich Dinge, die sich bei genauem Hinsehen als harmlos entpuppen. Aber selbst die vorsichtigste dieser Zahlen bedeutet: In jedem größeren KI-Projekt steckt statistisch mehr als eine echte Lücke.
Warum KI unsicheren Code schreibt
Dahinter steckt keine Böswilligkeit und auch kein Modellfehler, sondern nüchterne Mechanik. Sprachmodelle lernen aus vorhandenem Code, und ein erheblicher Teil davon stammt aus Tutorials, Foren-Antworten und schnellen Beispiel-Snippets. Dieser Code wurde geschrieben, um ein Konzept zu zeigen, nicht um einem Angriff standzuhalten. Die String-verkettete Datenbank-Query aus zehntausend Tutorials wird so zum Muster, das die KI selbstbewusst reproduziert.
Dazu kommt: Die KI kennt dein Bedrohungsmodell nicht. Sie weiß nicht, ob dein Endpoint öffentlich erreichbar ist, ob hinter der ID in der URL sensible Daten stecken oder ob dein Formular ein beliebtes Ziel für Bots ist. Wenn du “baue mir einen Endpoint, der Nutzer nach Email sucht” promptest, bekommst du exakt das: den kürzesten Weg von der Anfrage zur Antwort. Sicherheitsprüfungen, die du nicht verlangst, sind aus Sicht des Modells unnötige Komplexität.
Das ist der Kernpunkt: Unsicherer KI-Code ist meistens kein Modell-Versagen, sondern ein Anforderungs-Problem. Die KI liefert, was bestellt wurde, und Security stand nicht auf der Bestellung. Die gute Nachricht daran: Anforderungen kannst du ändern. Dazu kommen wir gleich. Vorher schauen wir uns an, wie die vier häufigsten Lücken konkret aussehen, denn erkennen musst du sie so oder so.
Die vier häufigsten Lücken in KI-Code
Die Scans aus dem Zahlen-Abschnitt finden immer wieder dieselben Schwachstellen-Klassen. Diese vier begegnen dir in Vibe-Coding-Projekten am häufigsten, und alle vier stehen seit Jahren in den OWASP Top 10, der Standard-Liste der kritischsten Sicherheitsrisiken im Web. Cross-Site-Scripting (XSS) gehört ebenfalls zu den Dauerbrennern, dagegen hilft vor allem eine saubere Content-Security-Policy, die ich im Artikel über Security Headers zeige. Hier konzentriere ich mich auf die vier Lücken, die in generiertem Backend-Code am häufigsten unbemerkt durchrutschen.
1. SQL Injection durch String-Verkettung
Der Klassiker, und in generiertem Code erschreckend verbreitet. So sieht ein typischer Endpoint aus, wie ihn dir die KI auf einen schnellen Prompt hin liefert:
// Unsicher: User-Eingabe landet direkt im SQL-String
app.get("/api/users", async (req, res) => {
const email = req.query.email;
const result = await db.query(
`SELECT * FROM users WHERE email = '${email}'`,
);
res.json(result.rows);
});Das funktioniert in jedem Test. Bis jemand statt einer Email das hier schickt:
/api/users?email=' OR '1'='1Aus deiner Query wird SELECT * FROM users WHERE email = '' OR '1'='1', und die Bedingung ist plötzlich für jede Zeile wahr. Der Angreifer bekommt deine komplette Nutzertabelle. Mit etwas mehr Kreativität liest er auch andere Tabellen aus oder löscht sie gleich ganz. Die Eingabe wurde Teil des Befehls, und genau das ist die Definition einer Injection.
Die Lösung ist seit Jahrzehnten dieselbe und kostet keine Zeile mehr:
// Sicher: Parametrisierte Query, Eingabe und Befehl bleiben getrennt
app.get("/api/users", async (req, res) => {
const email = req.query.email;
const result = await db.query("SELECT * FROM users WHERE email = $1", [
email,
]);
res.json(result.rows);
});Der Platzhalter $1 sorgt dafür, dass die Datenbank die Eingabe immer als Wert behandelt, niemals als Befehl. Was auch immer jemand eintippt, es bleibt ein Suchbegriff. Deine Prüfregel für jeden generierten Datenbank-Zugriff lautet deshalb: Steht eine Variable direkt im Query-String, ist es eine Lücke. Keine Ausnahmen, keine Diskussion.
2. Hartcodierte Secrets und API-Keys
Die rund 400 offenen Secrets aus dem Escape-Scan sind kein Zufallsfund, sondern ein Muster. Wenn du die KI bittest, einen externen Dienst anzubinden, schlägt sie gern den direktesten Weg vor:
// Unsicher: Der Key liegt im Frontend-Code, sichtbar für jeden Besucher
const API_KEY = "sk_live_51Hx7f2K9q...";
async function loadData() {
const res = await fetch(`https://api.example.com/data?key=${API_KEY}`);
return res.json();
}Läuft dieser Code im Browser, kann jeder Besucher den Key mit einem Rechtsklick auslesen. Landet er in einem öffentlichen GitHub-Repo, finden ihn automatisierte Scanner-Bots, und zwar innerhalb von Minuten, nicht Tagen. Mit einem gestohlenen Key telefoniert dann jemand anderes auf deine Rechnung mit der API, oder schlimmer: Er bekommt Zugriff auf die Daten dahinter.
Die sichere Variante trennt sauber: Der Key lebt in einer Umgebungsvariablen auf dem Server, und dein Frontend redet nur mit deinem eigenen Backend.
// Sicher: Server-seitige Route, der Key verlässt den Server nie
const API_KEY = process.env.EXAMPLE_API_KEY;
app.get("/api/data", async (req, res) => {
const upstream = await fetch(`https://api.example.com/data?key=${API_KEY}`);
res.json(await upstream.json());
});Dazu gehören zwei Handgriffe, die du dir zur Gewohnheit machst: Die Werte stehen in einer .env-Datei, und die .env steht in der .gitignore. Und falls doch einmal ein Key im Repo gelandet ist, hilft kein nachträgliches Löschen des Commits. Die Git-Historie vergisst nichts, und die Scanner waren wahrscheinlich schneller als du. Ein einmal veröffentlichter Key gilt als verbrannt und wird sofort rotiert, also beim Anbieter widerrufen und neu erzeugt.
3. Fehlende Auth-Checks
Diese Lücke ist die heimtückischste der vier, weil sie in keinem Test auffällt. Die KI baut dir brav einen Login und geschützte Routen, und trotzdem fehlt das Entscheidende. Schau dir diesen Endpoint an:
// Unsicher: Eingeloggt ja, aber gehört ihm die Rechnung auch?
app.get("/api/invoices/:id", requireLogin, async (req, res) => {
const result = await db.query("SELECT * FROM invoices WHERE id = $1", [
req.params.id,
]);
res.json(result.rows[0]);
});Die Route prüft, ob jemand eingeloggt ist. Sie prüft aber nicht, ob die Rechnung mit der ID 4711 auch wirklich diesem Nutzer gehört. Jeder Kunde kann die Zahl in der URL hochzählen und fremde Rechnungen lesen, mit Namen, Adressen und Beträgen. Dieses Muster heißt Broken Access Control und steht nicht zufällig auf Platz 1 der OWASP Top 10. Die Behebung ist eine Zeile in der Query:
// Sicher: Die Query prüft die Besitzfrage gleich mit
const result = await db.query(
"SELECT * FROM invoices WHERE id = $1 AND user_id = $2",
[req.params.id, req.session.userId],
);Merksatz dazu: Login beantwortet, wer jemand ist. Zugriffskontrolle beantwortet, was er darf. Das sind zwei verschiedene Fragen, und die KI beantwortet ungefragt nur die erste. Wie moderne Login-Verfahren die erste Frage inzwischen elegant lösen, habe ich im Artikel über Passkeys beschrieben. Aber der beste Login nützt nichts, wenn danach jeder alles abrufen darf. Frag bei jedem generierten Endpoint: Wo im Code steht die Zeile, die prüft, ob dieser Nutzer diese Daten sehen darf? Findest du sie nicht, hast du die Lücke gefunden.
4. Path Traversal und Command Injection
Die vierte Klasse taucht überall dort auf, wo generierter Code mit Dateien oder der Kommandozeile arbeitet. Ein Download-Endpoint wie fs.readFile("./public/uploads/" + req.query.file) sieht harmlos aus, bis jemand ?file=../../.env anfragt und sich mit den ../ aus dem Upload-Ordner nach oben arbeitet. Schon liefert dein Server seine eigene .env-Datei aus, inklusive aller Secrets aus Lücke Nummer 2. Das ist Path Traversal: Der Angreifer wandert mit ../ durch dein Dateisystem.
Command Injection funktioniert nach demselben Prinzip, nur auf der Kommandozeile. Baut die KI etwas wie exec("convert " + dateiname) für die Bildverarbeitung, kann ein Dateiname wie foto.jpg; rm -rf / eigene Befehle anhängen, und dein Server führt sie aus. Auch hier gilt das Muster aus Lücke 1: Eingabe wird Teil eines Befehls.
Die Gegenmittel: Eingaben validieren, bevor sie in Pfade oder Befehle wandern, Pfade nach dem Zusammenbauen gegen das erlaubte Verzeichnis prüfen, und statt exec mit zusammengeklebten Strings Funktionen nutzen, die Argumente getrennt übergeben, wie execFile. Wenn dir das gerade zu schnell ging, reicht fürs Erste die Faustregel: Überall, wo User-Eingaben auf Dateisystem oder Shell treffen, ist erhöhte Wachsamkeit Pflicht.
Bleib auf dem Laufenden
Erhalte neue Inhalte direkt in dein Postfach
Was erwartet dich?
Neue Artikel & Videos
Wenn ich was Neues veröffentliche, erfährst du's hier zuerst.
Plattform & Kurs-Updates
Neue Kurse, Referenz-Updates und gelegentlich Sonderpreise zum Launch.
Einmal die Woche in deinem Postfach
Kurz, auf den Punkt, kein Spam.
So nutzt du KI trotzdem sicher
Jetzt kennst du die vier Lücken, und vielleicht denkst du gerade: Dann lasse ich das mit dem Vibe Coding lieber. Das wäre die falsche Schlussfolgerung. Die richtige lautet: KI-Tempo behalten, aber vier Gewohnheiten dazunehmen.
Security gehört in den Prompt
Erinnere dich an den Kernpunkt von vorhin: Die KI liefert, was bestellt wurde. Also bestell richtig. Der Unterschied zwischen unsicherem und sicherem generiertem Code liegt oft in zwei, drei Sätzen im Prompt:
Baue den Endpoint mit parametrisierten Queries, niemals String-Verkettung in SQL.
Keine Secrets im Code, alle Keys kommen aus Umgebungsvariablen.
Validiere alle Eingaben an der Systemgrenze.
Prüfe bei jeder Route, ob der eingeloggte Nutzer auf genau diese Daten zugreifen darf.Noch besser: Schreib diese Regeln nicht in jeden einzelnen Prompt, sondern einmal in die Projektregeln deines Tools, also etwa in die CLAUDE.md deines Projekts oder die Rules-Datei von Cursor. Dann gelten sie automatisch für jede Anfrage. Zusätzlich lohnt sich ein zweiter Durchgang: Lass die KI ihren eigenen Code mit einem frischen Prompt wie “Prüfe diesen Code gegen die OWASP Top 10 und liste konkrete Funde” reviewen. Das findet erstaunlich viel, aber sei ehrlich zu dir: Es ist eine zusätzliche Schicht, kein Freifahrtschein. Dieselben blinden Flecken, die beim Schreiben zur Lücke führten, können auch beim Selbst-Review zuschlagen.
Reviewen wie beim Praktikanten-Code
Stell dir vor, ein talentierter, aber unerfahrener Praktikant hätte den Code geschrieben: schnell, eifrig, manchmal brillant, aber ohne Gespür dafür, was in Produktion schiefgehen kann. Würdest du seinen Code ungelesen mergen? Eben. Genau so behandelst du generierten Code. Lies den Diff, bevor du ihn übernimmst, und zwar wirklich, nicht als Scroll-Ritual auf dem Weg zum Accept-Button.
Die wichtigste Regel dabei: Übernimm nichts, was du nicht erklären kannst. Wenn die KI HTML-Attribute oder CSS-Konstrukte verwendet, die du noch nie gesehen hast, schlag sie nach, zum Beispiel in meiner HTML- und CSS-Referenz. Das kostet zwei Minuten und zahlt doppelt ein: Du prüfst den Code, und du lernst dabei genau die Grundlagen, die dich beim nächsten Mal schneller machen. Warum dieses Verständnis auf Dauer über deinen Wert als Entwickler entscheidet, habe ich im Artikel über KI in der Softwareentwicklung ausführlicher aufgeschrieben.
Schutzschichten einziehen
Selbst mit guten Prompts und aufmerksamem Review rutscht mal etwas durch. Deshalb baust du Schichten ein, die unabhängig voneinander greifen. npm audit prüft deine Abhängigkeiten auf bekannte Lücken, ein Secrets-Scanner wie gitleaks durchsucht dein Repo nach versehentlich committeten Keys, und Rate Limiting auf deinen Endpoints bremst automatisierte Angriffe aus, bevor sie Schaden anrichten. Alle drei sind in wenigen Minuten eingerichtet.
Die vierte Schicht kennst du vielleicht schon von hier: Security Headers geben dem Browser Schutzregeln mit, die auch dann noch greifen, wenn eine Lücke im Code durchgerutscht ist. Zwanzig Minuten Aufwand, und eine ganze Klasse von Angriffen läuft ins Leere. Genau das ist Defense in Depth: Keine Schicht ist perfekt, aber ein Angreifer muss durch alle durch.
Grenzen kennen: Was du selbst können musst
Die unbequeme Wahrheit zum Schluss dieses Abschnitts: Alle Gewohnheiten von oben setzen voraus, dass du grob verstehst, wonach du suchst. Eine Checkliste hilft nur dem, der erkennt, wann sie zutrifft. Deshalb ist Grundwissen der eigentliche Multiplikator beim Vibe Coding. Nicht, weil du der KI das Tippen abnehmen sollst, sondern weil du derjenige bist, der beurteilt, was sie getippt hat.
Wenn du gerade erst anfängst, systematisch mit KI zu entwickeln, ist der kostenlose 5-Tage-Kurs KI Coding Partner ein guter Startpunkt: Dort geht es um Prompting, Problemzerlegung und Projektkontext, also genau die Fähigkeiten, mit denen aus wildem Vibe Coding ein kontrollierter Workflow wird.
Meine ehrliche Einordnung
Wenn du meine Artikel kennst, weißt du, dass jetzt der Teil kommt, den die Schlagzeilen gern weglassen. Drei Dinge gehören zur Wahrheit dazu.
Erstens: KI-Code ist nicht unsicherer als das, was Menschen jahrelang aus Tutorials kopiert haben. Die String-verkettete Query gab es lange vor ChatGPT, und sie stammt aus denselben Quellen, aus denen die Modelle gelernt haben. Neu sind Tempo und Menge. Wo früher ein Copy-Paste-Projekt pro Woche entstand, entstehen heute hunderte pro Tag, und deutlich mehr davon gehen tatsächlich online.
Zweitens: Die Studienzahlen verdienen einen kritischen Blick. Automatisierte Scanner melden auch Fehlalarme, und gescannt wurden viele Hobby-Projekte, die nie den Anspruch hatten, sicher zu sein. Die Prozentzahlen schwanken je nach Methode stark. Sie sind eine Warnleuchte, kein Untergangsszenario.
Drittens, und das ist mir am wichtigsten: Ich höre nicht auf, mit KI zu bauen, und du solltest es auch nicht. Der Unterschied zwischen gefährlich und produktiv liegt nicht im Werkzeug, sondern darin, ob jemand am Steuer sitzt, der die vier Lückenklassen aus diesem Artikel erkennt. Genau dieser Jemand kannst du ab heute sein.
Deine Vibe-Coding-Security-Checkliste
Zum Abhaken, bevor dein nächstes KI-Projekt online geht:
- Security-Anforderungen stehen im Prompt oder in den Projektregeln, nicht nur in deiner Hoffnung
- Jede generierte Datenbank-Query verwendet Platzhalter, nirgends steht eine Variable direkt im Query-String
- Codebase nach hartcodierten Keys durchsucht, alle Secrets in Umgebungsvariablen ausgelagert
.envsteht in der.gitignore, versehentlich committete Keys wurden rotiert, nicht nur gelöscht- Für jeden Endpoint beantwortet: Wer darf das aufrufen, und wo im Code steht diese Prüfung?
- Alle Stellen geprüft, an denen User-Eingaben auf Dateipfade oder Shell-Befehle treffen
npm auditgelaufen und die KI hat ihren eigenen Code gegen die OWASP Top 10 reviewt, beides als Ergänzung, nicht als Ersatz- Security Headers gesetzt als Schicht, die auch bei durchgerutschten Fehlern noch greift
- Nichts deployt, was du nicht Zeile für Zeile erklären kannst
Wie es weitergeht
Die vier Lückenklassen zu erkennen ist der Anfang. Sie systematisch zu schließen, bevor sie entstehen, ist der nächste Schritt, und dafür braucht es mehr als einen Artikel: ein Verständnis dafür, wie Angriffe wirklich ablaufen, wie Authentifizierung und Zugriffskontrolle sauber zusammenspielen und wie du eine Anwendung Schicht für Schicht härtest.
Genau dafür habe ich den Web Security Mastery Kurs gebaut. In 30 Tagen gehst du vom Security-Mindset über die OWASP Top 10 bis zum Praxis-Audit deiner eigenen Anwendung. Die komplette zweite Woche dreht sich um die Angriffe aus diesem Artikel, von XSS über SQL und Command Injection bis Path Traversal und File Uploads. Woche 3 nimmt sich Authentifizierung und Broken Access Control vor, und am Tag 25 steht Secrets Management auf dem Plan. Alles in verdaulichen Tagesportionen, direkt an einer echten Anwendung.
Web Security Mastery
Weitere Blog Artikel
Bleib auf dem Laufenden
Erhalte neue Inhalte direkt in dein Postfach
Was erwartet dich?
Neue Artikel & Videos
Wenn ich was Neues veröffentliche, erfährst du's hier zuerst.
Plattform & Kurs-Updates
Neue Kurse, Referenz-Updates und gelegentlich Sonderpreise zum Launch.
Einmal die Woche in deinem Postfach
Kurz, auf den Punkt, kein Spam.