KI-Sicherheit

SSE-Redaktion: System-Prompts für LLMs in Streaming-Architekturen verteidigen

Von Better ISMS — Februar 2026

Wenn Sie ein Produkt auf Basis eines LLMs entwickeln, ist Ihr System-Prompt die Logik Ihres Produkts. Wenn ihn jemand extrahiert, erhält er Ihre Argumentation, Ihre Leitplanken, Ihren Wettbewerbsvorteil — einfach alles. Und wenn Sie Antworten über Server-Sent Events (SSE) streamen (was Sie wahrscheinlich tun), ist die Verteidigung gegen Extraktionen schwieriger als man denkt.

Dieser Beitrag beschreibt die SSE-Redaktion, eine Technik, die wir für ISMS Copilot entwickelt haben, um Leaks von System-Prompts mitten im Stream zu erkennen und zu neutralisieren. Wir teilen die Architektur, damit andere Entwickler von LLM-Produkten etwas Ähnliches implementieren können.

Das Problem

Die meisten LLM-Anwendungen streamen Antworten an den Client Stück für Stück via SSE. Jedes Segment („Chunk“) wird in dem Moment gesendet, in dem es generiert wird. Es gibt keinen Schritt „Die vollständige Antwort vor dem Senden prüfen“ — das würde den Zweck des Streamings zunichtemachen.

Dies schafft eine Sicherheitslücke: Wenn ein Jailbreak-Prompt das Modell davon überzeugt, seine Systemanweisungen preiszugeben, fliegen die Inhalte bereits zum Client, bevor Sie eingreifen können. Bis Sie merken, was passiert ist, hat der Benutzer bereits hunderte oder tausende Zeichen Ihres System-Prompts gesehen.

Herkömmliche Ausgabefilter funktionieren hier nicht. Sie können nicht die gesamte Antwort puffern (Latenz zerstört die UX) und Sie können nicht jeden winzigen Chunk isoliert prüfen (ein Fragment aus 5 Wörtern sieht nicht wie ein System-Prompt aus).

Allgemeine Strategien zur Jailbreak-Prävention finden Sie unter Mitigate Jailbreaks and Prompt Injections. Die SSE-Redaktion ist eine Defense-in-Depth-Maßnahme für den Fall, dass diese Präventionen fehlschlagen.

Die Architektur

Die SSE-Redaktion arbeitet in vier Stufen.

Stufe 1 — Fingerprinting. Bevor eine Konversation stattfindet, extrahieren Sie einen Satz von Fingerprint-Phrasen aus Ihrem System-Prompt. Dies sind prägnante Zeichenfolgen, die nur dann gemeinsam auftreten würden, wenn das Modell seine Anweisungen reproduziert. Sie sollten Phrasen aus verschiedenen Abschnitten Ihres Prompts wählen — Rollendefinitionen, Namen von Constraints, Verhaltensregeln. Die Anzahl der Fingerprints und der Schwellenwert für Übereinstimmungen sind abstimmbare Parameter, die Sie geheim halten.

Stufe 2 — Akkumulation und periodische Prüfung. Während das Modell Chunks streamt, sammelt ein Guard den vollständigen Antworttext an. In regelmäßigen Abständen (gemessen an der Zeichenzahl, nicht an den Chunks) prüft er den akkumulierten Inhalt gegen den Fingerprint-Satz. Jeden Chunk zu prüfen wäre ineffizient — die Fingerprints benötigen genügend Kontext, um aussagekräftig übereinstimmen zu können.

Stufe 3 — Fehlerfortpflanzung. Sobald der Guard genügend Übereinstimmungen erkennt, wirft er einen typisierten Fehler (in unserem Fall SystemPromptLeakError). Hier liegt die Feinheit. In einer Streaming-Architektur hat die Schleife zur Chunk-Verarbeitung normalerweise ein try/catch, um fehlerhafte SSE-Daten zu handhaben. Dieser generische Catch-Block wird Ihren Sicherheitsfehler verschlucken, wenn Sie nicht vorsichtig sind. Sie benötigen eine Guard-Clausel, die Ihren spezifischen Fehlertyp erneut wirft, bevor der generische Handler ausgeführt wird:

catch (e) {
  if (e instanceof Error && e.name === 'SystemPromptLeakError') throw e;
  // generic error handling continues for everything else
}

Das ist nur eine einzige Zeile, aber ohne sie ist das gesamte Erkennungssystem wirkungslos. Der Guard löst aus, protokolliert die Erkennung und der Stream liefert munter weiter Ihren System-Prompt an den Angreifer aus. Wir haben das auf die harte Tour gelernt — unser Guard erkannte Leaks in den Logs perfekt, tat aber absolut nichts, um sie zu stoppen.

Stufe 4 — Redaktion. Sobald der Fehler bis zum Stream-Controller durchgereicht wird, sendet dieser ein redact-SSE-Event an den Client. Der Client ersetzt alles, was bereits gerendert wurde, durch eine Verweigerungsmeldung. Der Server ersetzt gleichzeitig den gespeicherten Inhalt in der Datenbank, damit der Leak nicht bestehen bleibt.

Was der Benutzer sieht

Der Angreifer sieht kurzzeitig Teile des gestreamten Inhalts — vielleicht für ein paar Sekunden — dann wird die gesamte Antwort durch eine generische Verweigerung ersetzt. Die Erfahrung ist: Text erscheint, verschwindet dann und wird ersetzt. Die Teilinhalte, die er erhascht hat, sind unvollständig und mit normalem Antworttext vermischt, was sie für eine Extraktion unbrauchbar macht.

Erfahren Sie mehr über die Funktionsweise von Verweigerungsmeldungen unter Handle Refusals and Scope Limits.

Das Problem mit dem Catch-Block

Dies verdient besondere Betonung, da es die Art von Bug ist, die jeden Test besteht, aber in der Produktion scheitert.

Wenn Sie asynchrone Generatoren für das Streaming verwenden, sieht Ihre SSE-Parsing-Schleife wahrscheinlich so aus:

for (const line of sseLines) {
  try {
    const data = JSON.parse(line);
    const text = extractText(data);
    await onChunkCallback(text);  // <-- guard runs here
    yield text;
  } catch (e) {
    console.error('Error parsing chunk:', e);
    // continues to next line
  }
}

Der Callback befindet sich innerhalb des try-Blocks. Wenn der Guard einen Fehler wirft, protokolliert der catch-Block dies als Parsing-Fehler und macht weiter. In unserem Fall erkannte der Guard den Leak bei jedem einzelnen Chunk nach dem Schwellenwert korrekt — die Logs zeigten die wiederholte Auslösung des SystemPromptLeakError — während der Stream normal beendet wurde, den vollständigen geleakten Prompt in der Datenbank speicherte und an den Client sendete.

Die zusätzliche Komplikation: Dieses Verhalten ist laufzeitabhängig. In Node.js können sich Fehler asynchroner Generatoren aus Callbacks anders fortpflanzen als in Deno. Unsere Tests bestanden in der Node.js-Testumgebung, weil der Fehler sich zufällig fortpflanzte. In der Deno-Produktionsumgebung wurde er verschluckt. Wenn Sie dies bauen, testen Sie in Ihrer tatsächlichen Produktions-Runtime, nicht nur in Ihrem Test-Runner.

Bemerkenswerte Design-Entscheidungen

Warum Fingerprints anstelle von Embedding-Ähnlichkeit oder exaktem Matching? Fingerprints sind schnell (String-Matching), deterministisch (keine Modellaufrufe) und robust gegen Paraphrasierung. Das Modell paraphrasiert seinen eigenen System-Prompt während eines Leaks selten — es reproduziert ihn wortgetreu oder nahezu wortgetreu. Embedding-Ähnlichkeit erhöht die Latenz pro Prüfung und birgt das Risiko von False Positives bei legitimen Compliance-Inhalten. Exaktes Substring-Matching ist zu fehleranfällig (Leerzeichen, Formatierungsunterschiede).

Warum periodisch und nicht bei jedem Chunk prüfen? Chunks sind klein (oft 3–10 Zeichen). Ein einzelner Chunk ist für die Erkennung bedeutungslos. Das Akkumulieren bis zu einem Schwellenwert vor der Prüfung reduziert die Rechenlast und stellt sicher, dass genug Kontext für ein zuverlässiges Matching vorhanden ist.

Warum nicht die gesamte Antwort puffern? Puffern zerstört die Streaming-UX. Benutzer erwarten, dass Text in Echtzeit erscheint. Ein Puffer von 2 Sekunden ist spürbar; das Puffern einer vollständigen Antwort von über 4000 Zeichen ist inakzeptabel. Die SSE-Redaktion bewahrt das Echtzeit-Streaming für 99,99 % der Konversationen und greift nur bei einem aktiven Leak ein.

Warum auch in der Datenbank ersetzen? Wenn Sie nur auf dem Client redigieren, bleibt der geleakte Inhalt serverseitig bestehen. Jeder mit Datenbankzugriff, jede Exportfunktion oder jeder Endpunkt für den Konversationsverlauf würde ihn offenlegen.

Was dies nicht löst

Die SSE-Redaktion ist eine Defense-in-Depth-Maßnahme, kein Allheilmittel.

Es verhindert nicht, dass das Modell versucht, Informationen preiszugeben. Das regeln die Anweisungen Ihres System-Prompts (explizite Verweigerungsanweisungen, Constraint-Abschnitte). Die SSE-Redaktion ist das Sicherheitsnetz für den Fall, dass diese Anweisungen fehlschlagen — und mit genug Kreativität sind Jailbreaks gelegentlich erfolgreich.

Es verhindert keine Leaks, die kürzer als der Erkennungsschwellenwert sind. Wenn jemand das Modell dazu bringt, einen einzelnen Satz des System-Prompts zu verraten, wird die Fingerprint-Anzahl den Schwellenwert nicht erreichen. Dies ist beabsichtigt — man wägt ab zwischen dem Abfangen vollständiger Extraktionen (hohe Konfidenz) und dem Markieren teilweiser Erwähnungen (hohes False-Positive-Risiko).

Der Angreifer sieht vor der Redaktion tatsächlich Teilinhalte. Für einige Sekunden ist der gestreamte Text sichtbar. Dies liegt in der Natur von Streaming-Architekturen. Der Teilinhalt ist unvollständig und unstrukturiert, aber es ist keine Null-Exposition.

Die SSE-Redaktion ergänzt bewährte Sicherheitsmethoden für System-Prompts, ersetzt diese aber nicht. Siehe System Prompts und Protect Workspace and Custom Instructions für grundlegende Sicherheitsmaßnahmen.

Checkliste für die Implementierung

Wenn Sie dies für Ihr eigenes LLM-Produkt bauen möchten:

  1. Extrahieren Sie Fingerprint-Phrasen aus Ihrem System-Prompt — wählen Sie prägnante, abschnittsübergreifende Zeichenfolgen.

  2. Bauen Sie einen Guard, der gestreamte Inhalte akkumuliert und periodisch gegen die Fingerprints prüft.

  3. Definieren Sie eine typisierte Fehlerklasse mit einem eindeutigen Namen für die Leak-Erkennung.

  4. Überprüfen Sie jeden Catch-Block in Ihrer Streaming-Pipeline — fügen Sie Re-Throw-Guards für Ihren Fehlertyp hinzu.

  5. Handhaben Sie den Fehler in Ihrem Stream-Controller, indem Sie ein redact-Event senden und gespeicherte Inhalte ersetzen.

  6. Behandeln Sie das redact-Event auf dem Client, indem Sie den gerenderten Inhalt durch eine Verweigerungsmeldung ersetzen.

  7. Testen Sie in Ihrer Produktions-Runtime, nicht nur in Ihrem Test-Runner.

  8. Halten Sie Ihre Fingerprints, Schwellenwerte und Prüfintervalle geheim.

Abschließender Gedanke

Der schwierigste Teil war nicht der Erkennungsalgorithmus — es war ein einzeiliger Bug in einem Catch-Block, der das gesamte System lautlos deaktivierte. Sicherheit in Streaming-Architekturen scheitert oft an der Ebene der „Rohrleitungen“, nicht am Algorithmus. Wenn Sie LLM-Sicherheitsfunktionen entwickeln, verfolgen Sie den vollständigen Fehlerpfad von der Erkennung bis zur Aktion am Frontend und verifizieren Sie diesen in Ihrer tatsächlichen Produktionsumgebung.

Für einen breiteren Überblick über KI-Sicherheitspraktiken bei ISMS Copilot siehe AI Safety & Responsible Use Overview.

Better ISMS entwickelt Compliance-Tools für Informationssicherheitsteams. ISMS Copilot ist unser KI-Assistent für ISO 27001, SOC 2, DSGVO und verwandte Frameworks.

War das hilfreich?