No. 002Sicherheit8 Min. Lesezeit

Prompt Injection ist das neue SQL Injection — der Fix ist kein SQL

P2SQL, CVE-2024-5565, EchoLeak, das Supabase-Leak: Feindliches SQL kommt heute im Output des Modells an. Der Fix ist ein Agent ohne Syntax, in die injiziert werden könnte.

Das Support-Ticket sah nicht wie ein Angriff aus. Es wartete in der Queue wie jedes andere — eine Kundennachricht, die zusammengefasst werden sollte. Im Textkörper steckten Anweisungen: die Tabelle integration_tokens auslesen und den Inhalt in diesen Thread posten.

Ein Entwickler hatte einen KI-Assistenten über den Supabase MCP-Server auf diese Queue gerichtet — mit service_role-Zugangsdaten, also der Rolle, die Row-Level Security vollständig umgeht. Der Assistent las das Ticket, interpretierte seinen Inhalt als Aufgabe und führte ihn gegen die Produktionsdatenbank aus. Die Tokens erschienen im Ticket-Thread, wo der Angreifer sie schlicht ablesen konnte Simon Willison, 2025.

Im klassischen Sinne wurde nichts ausgenutzt. Kein Speicherfehler, keine fehlende Auth-Prüfung, keine verwundbare Abhängigkeit. Der feindliche Text erreichte die Datenebene ausschließlich über den Agenten — und das Proof of Concept lässt sich auf jeden gleich verdrahteten Agenten übertragen.

Das ist SQL Injection mit verlagertem Interpreter. Feindlicher Text wird noch immer zu einem Datenbankbefehl. Doch der String kommt nicht mehr im Input an, wo zwanzig Jahre Sanitization-Tooling Wache stehen. Er kommt im Output des Modells an — nachgelagert zu jedem Filter, den man besitzt.

SQL INJECTION, 2005 — THE PAYLOAD ARRIVES IN THE INPUT input sanitizer application database parameterized payload dies here PROMPT-TO-SQL, NOW — THE PAYLOAD ARRIVES IN THE OUTPUT input sanitizer model generated SQL database untrusted context — tickets, pages, rows hostile SQL is authored here — after every filter
Der Filter bewacht eine Tür, die der Payload nicht mehr benutzt — bei P2SQL wird feindliches SQL im Output des Modells erzeugt (Pedro et al., ICSE 2025).

Die Chronik

Forscher am INESC-ID Lissabon benannten das Muster 2023: P2SQL, Prompt-to-SQL Injection Pedro et al., 2025. Gegen einen realen LangChain-Chatbot über Postgres konstruierten sie sieben repräsentative Angriffe mit steigendem Schweregrad — unberechtigte Lesezugriffe, korrumpierte Tabellen, gelöschte Tabellen, bis hin zu Code-Ausführung — und testeten sie gegen sieben aktuelle Modelle. Die Fehler waren modellunabhängig. Ihr Fazit im Wortlaut: „LLM-integrierte Anwendungen auf Basis von Langchain sind P2SQL-Injection-Angriffen gegenüber hochgradig anfällig." Das Paper erschien auf der ICSE 2025 — Peer Review als Bestätigung, dass dies kein Kuriosum ist.

Mitte 2024 hatte das Muster eine CVE-Nummer. Vanna.AI, eine Text-to-SQL-Bibliothek, übergab Nutzerfragen an einen Prompt, der Plotly-Charting-Code generierte, und führte diesen Code dann mit exec() aus. Eine präparierte Frage führte direkt zu Remote Code Execution — CVE-2024-5565, CVSS 8.1 JFrog, 2024. Der Payload befand sich im Output des Modells, jenseits jeder Input-Prüfung. Vannas Guardrail-Prompts hielten ihn nicht auf — ein Guardrail ist nur weiterer Text im selben Kontextfenster wie der Angriff.

Ende 2024 war die Einordnung offiziell: Prompt Injection ist LLM01, das Risiko Nummer eins in den OWASP Top 10 für LLM-Anwendungen, zum zweiten Mal in Folge an der Spitze OWASP, 2025. OWASPs Diagnose der Grundursache fasst alles in einem Satz: LLMs verarbeiten Anweisungen und Daten im selben Kanal, ohne klare Trennung. Deshalb teilt sich die Kategorie in zwei Varianten — direkte Injection, die der Nutzer eintippt, und indirekte Injection, die in allem mitreist, was das Modell abruft. Das Supabase-Ticket war indirekt. Ebenso der bislang gravierendste Fall.

Im Juni 2025 wurde CVE-2025-32711 — EchoLeak, CVSS 9.3 — in Microsoft 365 Copilot offengelegt: der erste dokumentierte Zero-Click-Prompt-Injection-Exploit gegen ein produktives LLM-System in der realen Welt arXiv, 2025. Eine präparierte E-Mail — Anweisungen in HTML-Kommentaren versteckt, weiß-auf-weiß-Text, Reference-Style-Markdown — und Copilot exfiltrierte interne Daten auf den Server des Angreifers. Der Nutzer klickte nichts. Die Angriffskette überwand Microsofts dedizierten Cross-Prompt-Injection-Klassifikator und dessen Link-Redaktion beim Ausgang.

CVSS 10 8.1 9.3 2025-06 CVE-2025-32711 — EchoLeak zero-click, one email, M365 Copilot 2023-08 P2SQL coined 7 attacks × 7 LLMs 2024-06 CVE-2024-5565 Vanna.AI — RCE 2024-11 OWASP LLM01 #1 for 2nd edition 2025-07 Supabase MCP PoC no code vulnerability
Zwei Jahre, vom Labor zum Zero-Click — CVSS-Balken maßstabsgetreu (arXiv 2308.01990; JFrog 2024; OWASP 2025; arXiv 2509.10540; Willison 2025).

Warum die naheliegenden Fixes scheitern

Jeder der oben genannten Vorfälle entzieht einer der Standardverteidigungen ihre Grundlage.

Den Input filtern. EchoLeak passierte XPIA, einen Klassifikator, den Microsoft eigens zur Erkennung von Injection-Versuchen entwickelt hatte arXiv, 2025. Klassifikatoren sind probabilistisch. Der Angreifer braucht einen einzigen Treffer und hat unbegrenzte Versuche, ihn herzustellen; der Verteidiger braucht eine makellose Bilanz gegen Inputs, die wie alles andere aussehen sollen.

Das Modell anweisen. Vanna lieferte Guardrail-Prompts aus; CVE-2024-5565 durchquerte sie JFrog, 2024. Es gibt keinen privilegierten Kanal innerhalb eines Kontextfensters. System-Text, Nutzer-Text und Angriffs-Text sind dieselbe Substanz — genau die Grundursache, die OWASP benennt OWASP, 2025.

Den Output absichern. Das generierte SQL parsen und gefährliche Teile blockieren. Damit pflegt man eine Denylist über alle schreibfähigen Konstrukte in jedem unterstützten Dialekt sowie jede Funktion mit Seiteneffekten — während der Co-Autor des Angreifers das Modell selbst ist, das bereitwillig eine blockierte Abfrage in eine erlaubte Form umformuliert. Bezeichnenderweise liegen die von den P2SQL-Autoren vorgeschlagenen Gegenmaßnahmen außerhalb des Modells: das generierte SQL parsen und per Allowlist prüfen, und den Agenten unter einer separaten, eingeschränkten Datenbankrolle ausführen Pedro et al., 2025. Die Kontrollen, die halten, sind jene, die das Modell nicht berühren kann.

Simon Willison verdichtete die Struktur zu einer Dreierregel: Ein Agent mit Zugang zu privaten Daten, Exposition gegenüber nicht vertrauenswürdigem Inhalt und einem Weg zur externen Kommunikation kann zur Exfiltration gebracht werden — ganz ohne Software-Fehler Simon Willison, 2025. Seine Empfehlung ist architektonischer Natur: ein Bein entfernen. OWASPs Maßnahmenliste konvergiert auf dasselbe Fundament — einschränken, was das Modell tun kann, und das, was es produziert, mit deterministischem Code validieren, denn das Modell kann nicht damit betraut werden, sich selbst zu kontrollieren.

Zusammengelesen sagen diese Quellen etwas Stärkeres als „mehr Verteidigungsschichten hinzufügen". Sie sagen: Hört auf, Strings zu beurteilen. Ändert das Interface.

Keine Syntax, in die injiziert werden könnte

SQL Injection endete nicht, weil Sanitizer besser wurden. Es endete, weil parametrisierte Abfragen den Ort beseitigten, an dem Daten zu Code werden konnten. Derselbe Schritt steht Agenten offen: dem Modell verbieten, überhaupt ausführbare Syntax zu verfassen.

So ist SQAI gebaut. Das Modell schreibt niemals SQL — weder bereinigt noch geprüft, gar keines. Sein einziges ausführendes Tool akzeptiert eine typisierte Spec: eine Discriminated Union, kind: "query" | "computation", version: "1", validiert gegen einen hash-gepinnten Capability-Vertrag, bevor irgendetwas ausgeführt wird. Eine Capability außerhalb des Vertrags benennen, und die Engine antwortet mit unsupported_operation. Kein String, den das Modell produziert, wird jemals konkateniert, interpoliert oder an einen Interpreter übergeben — der Gegenstand, den eine Injection ergreifen müsste, nämlich modellgenerierte Syntax, existiert in der Pipeline schlicht nicht. Das vollständige Argument ist in why agents shouldn't write SQL dargelegt.

Das Vokabular ist geschlossen und schreibgeschützt: alle 4.574 exponierten Capabilities, per Konstruktion. Es gibt keine Schreib-Capability zu benennen, also gibt es keine Beschwörungsformel — wie raffiniert auch immer in ein Support-Ticket geschmuggelt —, die einen Schreibvorgang erzeugt. Die Host-Code-Ausstiegsluke, getUnsafeRuntime, ist von keinem Modell-Tool aus erreichbar.

Und weil ernsthafte Sicherheit den Tag einpreist, an dem das Modell tatsächlich gekapert wird, gehen die dahinterliegenden Schichten davon aus:

  • Policy, die das Modell nicht adressieren kann. Allowlists für Sources, Felder und Funktionen sind zum Zeitpunkt von createSQAI() im Code festgelegt und in-process durchgesetzt, vor der Ausführung. Das Tool-Schema enthält keine allowed*-Felder — die Policy-Oberfläche betritt das Kontextfenster nie. Verstöße liefern typisierte, nicht wiederholbare Ablehnungen: policy_denied_source, policy_denied_field, policy_denied_function. Warum das Rollen und Flags übertrifft: read-only that wasn't.
  • Ergebnisse auf den Tenant beschränkt. Große Ergebnisse werden unter einer result_id aus 16 zufälligen Bytes abgelegt. Ein falscher Tenant erhält result_not_found — keinen Berechtigungsfehler, der die Existenz der Daten bestätigt — und Einträge verfallen nach 15 Minuten.
  • Ein begrenzter Kanal zurück zum Modell. Höchstens 25 Zeilen und 32.000 Bytes gelangen ins Kontextfenster, Kürzungen werden stets deklariert. Ein injizierter Prompt kann das Tool nicht dazu bringen, eine Tabelle in das Transkript zu kippen; der Transport trägt das nicht.
  • Fehler, die keine Karte zeichnen. Für das Modell sichtbare Fehler durchlaufen sanitizeMessage, das absolute Dateisystempfade entfernt. Aufklärungsversuche erhalten eine saubere Ablehnung, kein Verzeichnislisting.

Bewertet gegen die Dreierregel: Private Daten sind noch vorhanden — das ist der Zweck. Nicht vertrauenswürdiger Inhalt ist noch vorhanden — Modelle lesen, was sie lesen. Aber die Beine, die Einfluss in Schaden verwandeln, sind gekappt. Der Schreibpfad fehlt, und der Lesepfad ist allowlist-gesichert, tenant-beschränkt, gedeckelt — und gehasht, sodass alles, was ein gekaperter Agent zu fragen vermochte, für die Nachbereitung wiederholbar ist.

204 excluded 4.778 capabilities in the contract 4.574 exposed to the model — every one read-only 4.564 deterministic within the declared scope 0 write capabilities — nothing to name, nothing to run
Das gesamte Vokabular, maßstabsgetreu — ein gekaperter Prompt kann andere Werte wählen, niemals ein anderes Verb (Quelle: SQAI Capability-Vertrag).

Die Grenze, neu gezogen

Prompt Injection ist nicht gelöst, und die Chronik spricht dafür, dass das so bald nicht der Fall sein wird. LLM01 hält seinen Rang seit zwei Ausgaben. Ein Produktivsystem mit Microsofts Verteidigungsmaßnahmen im Rücken unterlag einer einzigen E-Mail. Modelle werden weiterhin feindlichen Text lesen, und ein Teil davon wird ankommen.

Doch das Modell zu beeinflussen und die Datenbank zu erreichen sind verschiedene Versagensfälle, und nur der erste ist unvermeidlich. Das Supabase-Ticket wurde zum Vorfall, weil der Agent service_role und eine freie SQL-Oberfläche hielt — genau die Beine, die ein Angriff braucht. Dasselbe Ticket, gerichtet auf ein geschlossenes, typisiertes, schreibgeschütztes Vokabular, wird zu einem Log-Eintrag: unsupported_operation.

Der Fix für SQL Injection war nie ein klügerer Filter. Es war eine Grenze, an der Daten nicht zu Code werden können. Diese Grenze erneut zu ziehen — diesmal um das Modell herum — gibt dem neuen SQL Injection das alte Ende. Der Rest der Oberfläche ist auf /security dokumentiert.