Defense-in-Depth Architektur¶
Diese Seite dokumentiert die Sicherheits-Topologie der kora-platform, wie sie nach Abschluss der K-Security-Hardening Saga (Phase 1 + Phase 2 + Phase 3 #1, #2 und #3, ~47h Wall-Clock, Saga-Lehren 1–11) live ist.
Die Architektur besteht aus sieben orthogonalen Schichten, die nacheinander einen User-Request verarbeiten. Jede Schicht hat ein eigenes Versagensprofil; bei Versagen einer Schicht greift die nächste — Defense-in-Depth im klassischen Sinn.
Die Topologie ist produkt-weit, nicht customer-spezifisch. Konkrete Customer-spezifische Pattern-Listen, Filename-Marker und Pentest-Befunde aus der jeweiligen Customer-Demo-Umgebung sind in der Customer-Doku referenziert (siehe Abschnitt Customer-spezifische Erweiterungen).
Topologie¶
User-Request
│
▼
┌───────────────────────────────────────────────────┐
│ L5 — Multi-turn Persona-Defense (history_filter) │ Pre-LLM
│ α — Input-Filter (input_filter) │ Pre-LLM
│ Cache — Semantischer Response-Cache (Redis) │ Pre-LLM
│ L2 — Operator-Template Persona-Cleanup │ Prompt-Bau
│ LLM — vLLM-Inference mit LookAheadBuffer K=16 │ In-Stream
│ Inline-L3 — Pattern-Match auf accumulated text │ In-Stream
│ L4 — SourceWireForm + Post-Stream-Fallback │ Post-LLM
└───────────────────────────────────────────────────┘
│
▼
Token-Stream an Client
Layer-Details¶
L5 — Multi-turn Persona-Defense¶
| Aspekt | Wert |
|---|---|
| Position | Pre-LLM, vor α-Layer |
| Code | src/kora_platform/services/history_filter.py |
| Patterns | persistent_time_marker, ok_only_conditioning, role_override, forget_previous (4 Patterns) |
| Trigger | primary regex + min_co_matches Co-Indicators (Lehre 8: User-Input-Vokabular) |
| Wirkung | β-Marker-Replace: persistierter User-Turn wird in chat_messages durch [FILTERED]-Marker ersetzt; Cache-Skip; LLM erhält die bereinigte History |
| Audit-Log | history_persist_filter_audit (Migration 0017, RLS-isoliert) |
| Failure-Mode | Bei Versagen wird die toxische User-Turn-Persistenz von α nicht mehr gesehen (α arbeitet auf der aktuellen Turn, nicht der History) — Schutz für zukünftige Turns entfällt; aktueller Turn ist trotzdem durch α + Inline-L3 gefangen |
| Saga-Karte | K-Layer-5-History-Persist-Filter (Phase 1, ~5h) |
α — Input-Filter¶
| Aspekt | Wert |
|---|---|
| Position | Pre-LLM, nach L5, vor Cache |
| Code | src/kora_platform/services/input_filter.py |
| Patterns | json_format_pressure, prompt_leak_input, raw_context_input (3 Patterns) |
| Trigger | primary regex + min_co_matches Co-Indicators (Lehre 8: User-Input-Vokabular, niemals Output-Format-Marker) |
| Wirkung | Pre-LLM-Block; Refusal-Replacement direkt an Client; kein vLLM-Call (NO_TOKENS) |
| SSE-Reasons | input_format_pressure_filter, input_prompt_leak_filter, input_raw_context_filter |
| Audit-Log | input_filter_audit (Migration 0019, RLS-isoliert) |
| Failure-Mode | Bei Versagen läuft der Request voll durch — Schutz fällt auf L2 (Operator-Template) und Inline-L3 zurück |
| Saga-Karte | K-Saga-Phase-2-Cluster-3 (Phase 2, ~3.5h) + Phase 3 #1 (Phase 3, ~4h) |
Cache — Semantischer Response-Cache¶
| Aspekt | Wert |
|---|---|
| Position | Pre-LLM, nach α, vor L2 |
| Backend | Redis, Cosine-Similarity ≥ 0.95, Language-Namespace |
| Wirkung | Bei Hit wird die gecachte Antwort direkt zurückgegeben; Cache-Skip wird durch L5-/α-Match gesetzt, damit toxische Inputs nie zu Cache-Pollution führen |
| Failure-Mode | Cache-Miss bedeutet voller Pipeline-Run — kein Sicherheits-Risiko; ein false Cache-Hit könnte eine alte (legitime) Antwort liefern |
L2 — Operator-Template Persona-Cleanup¶
| Aspekt | Wert |
|---|---|
| Position | Prompt-Bau-Phase, vor LLM-Inference |
| Code | src/kora_platform/services/system_prompt_service.py (DB-backed Templates aus system_prompt_templates, Migration 0018) |
| Trigger | Keine Pattern — strukturelle Härtung der System-Prompt-Struktur (Spotlighting-Tags <user_query> / <retrieved_context>, Refusal-Anker, Multi-Tenant-fähig) |
| Wirkung | Reduziert Prompt-Injection-Surface; macht es dem LLM schwerer, Persona zu reproduzieren oder Roh-Kontext verbatim zu echoen |
| Failure-Mode | Schwächere Pattern-Resistance des LLM-Outputs — Inline-L3 und L4 fangen die Folgen |
| Customer-Konfiguration | Customer-Persona-Cleanup wird per-Tenant via system_prompt_templates konfiguriert (siehe Multi-Tenancy-Fundament) |
| Saga-Karte | K-Layer-2-Operator-Tenant-Split + Customer-Persona-Cleanup-Cluster (Phase 1 + Phase 2 Cluster 1, ~13h) |
LLM — vLLM mit LookAheadBuffer K=16¶
| Aspekt | Wert |
|---|---|
| Position | In-Stream, zwischen vLLM-Yield und SSE-Token-Yield |
| Code | src/kora_platform/services/stream_buffer.py (LookAheadBuffer Klasse) |
| Mechanismus | K=16 Token Vorlauf zwischen LLM-Generation und Client-Delivery — schafft das Fenster für inkrementelle Pattern-Detection BEVOR Tokens zum Client gehen |
| Latenz-Impact | K × ~25ms ≈ 400ms zusätzliche TTFT — Sicherheits-Trade-off akzeptiert |
| Saga-Karte | Phase 3 #2 Sub-Phase B (~6h gesamt) |
Inline-L3 — Pattern-Match auf accumulated text¶
| Aspekt | Wert |
|---|---|
| Position | In-Stream, im Buffer-Loop des Stage-9-Token-Loops |
| Code | src/kora_platform/services/output_filter.py + Wiring in src/kora_platform/services/query_service.py:706-740 |
| Patterns | prompt_leak_debug_block, raw_context_leak, json_format_pressure, system_rules_block, persona_style_leak (5 Pattern-Klassen) |
| Trigger | primary regex + min_co_matches Co-Indicators (Lehre 7: Output-Format-Marker, niemals User-Input-Vokabular). Für jeden Buffer-Release: check_output(buffer.accumulated_text). |
| Wirkung | Bei Match: buffer.discard_buffered() → buffered Tokens werden NICHT yielded → Hard-Stop-correction-SSE-Event mit hard_stop: true + clear_previous: true Flags. Widget DOM-Clear vor Replacement. |
| Audit-Log | output_filter_audit mit filter_layer="inline" (Migration 0020) |
| Failure-Mode | Bei mehrfacher Pattern-Lücke fällt der Schutz auf L4-Post-Stream-Fallback zurück |
| Customer-Konfiguration | Pattern-Klassen sind generic; konkrete Customer-Co-Indicators (z.B. Customer-Domain-Filename-Marker, Customer-Wiki-Phrasen) werden customer-spezifisch ergänzt |
| Saga-Karte | K-Layer-3-Output-Filter (Phase 1, ~7h) + K-L3-Output-Marker-Patterns (Phase 2 Cluster 2, ~2.5h) + Phase 3 #2 Sub-Phase C (Stream-Wiring, ~6h gesamt) + Phase 3 #3 (Pattern-Coverage-Erweiterung gegen 20-Leak-Korpus, ~3h) |
Pattern-Klassen (generic)¶
L3-Output-Filter erkennt Leak-Versuche über fünf orthogonale Pattern-Klassen, die jeweils generische Output-Format-Marker adressieren — unabhängig vom Customer-Domain-Vokabular:
- Schema-Notation: XML-Tags (
<raw_chunks>,<systemprompt>,<retrieved_context>), JSON-Keys ("raw_context":,"system_prompt":,"hidden_rules":), JSONL-Type-Discriminator ("type":"context","type":"system"), Object-Keys (rawContext:,systemPrompt:), Markdown-Table-Header (| raw_context |,| hidden_rules |) - Verbatim-Leak-Header:
Originaltexte aus den Quellen,Originalpassage:,genauen/wortwörtlichen Passagen - Wiki-Strukturmarker:
## Inhaltsverzeichnis(TOC-Header einer verbatim-gedumpten Wikipedia-Quelle) - Numerierte Imperativ-Regeln: Multi-Line
1. NUTZE …,2. KEINE …(geleakte System-Prompt-Regeln) - Persona-Style-Marker:
Arrr,matey,Schurke,Landratte(geleakte Persona aus Pirate-/Cowboy-Persona-Pressure-Attacks)
Customer-spezifische Co-Indicators (Customer-Domain-Filename-Pattern, Customer-Wiki-Phrasen, Customer-Doku-Strukturmarker) ergänzen diese generic Pattern-Klassen — ihre Pflege erfolgt customer-isoliert.
L4 — SourceWireForm + Post-Stream-Fallback¶
| Aspekt | Wert |
|---|---|
| Position | Post-LLM-Output |
| Code | src/kora_platform/api/schemas/query.py:51 (SourceWireForm) + src/kora_platform/services/query_service.py:382 (Post-Stream check_output) |
| Wirkung | SourceWireForm ist das wire-Schema OHNE content-Feld → keine Roh-Chunks zum Frontend, selbst wenn LLM-Output sie referenziert. Zusätzlich Post-Stream check_output für Pattern, die mehr als K=16 Token Look-Ahead brauchen → emittiert correction-Event mit filter_layer="post_stream" |
| Audit-Log | output_filter_audit mit filter_layer="post_stream" |
| Failure-Mode | L4 ist der letzte Fallback; bei vollständigem Versagen ist nur das Schema (kein content-Feld) noch da — Stream-Token sind dann beim Client |
| Saga-Karte | K-Layer-4-API-Schema (Phase 1, ~1.5h) + Phase 3 #2 (filter_layer-Disambiguation) |
Defense-in-Depth-Argument¶
Die Topologie kombiniert drei orthogonale Verteidigungs-Achsen:
-
Detection-Pattern-Coverage (Pattern-Empirie). L3 schließt ~90 % der Leak-Output-Klassen aus dem Extended-Pentest-Korpus bei 0 % False-Positive-Rate gegen Real-Eval-Antworten. Die nicht-fangbaren Output-Klassen sind strukturell vom legitimen RAG-Output ununterscheidbar (Saga-Lehre 11).
-
Stream-Architektur-Timing. Pattern-Match allein ist nicht ausreichend (Saga-Lehre 9, 10) — der Detection-Zeitpunkt relativ zum Token-Stream entscheidet, ob der Client Leak-Inhalt bereits gesehen hat. Inline-L3 mit LookAheadBuffer K=16 verschiebt die Detection vor das Yield, Hard-Stop-Event verhindert Token- Stream-Leak.
-
Paraphrase-Empirie als Test-Methodik. Pre-LLM-Filter (α, L5) und Post-LLM-Filter (Inline-L3) brauchen invertierte Co-Indicator-Heuristiken (Saga-Lehre 7 vs. 8) — das ist nur durch Empirie aus echten LLM-Outputs herleitbar, nicht durch Speculative-Design. Real-Eval-FP-Sweep + Korpus-Coverage-Match sind seit Phase 3 #3 die Saga-Konvention.
Saga-Bilanz¶
| Phase | Karten | Aufwand | Outcome |
|---|---|---|---|
| Phase 1 | 4 | ~24h | Initiale Defense-Stages (L4 Wire-Schema, L3 Output-Filter, L2 Operator-Template, L5 History-Filter) |
| Phase 2 | 3 (Cluster 1–3) | ~10h | Detection-Pattern-Tuning + α-Layer (Saga 14/14 Findings closed) |
| Phase 3 #1 | 1 | ~4h | α-Layer-Erweiterung um Prompt-Leak + Raw-Context Input-Marker |
| Phase 3 #2 | 1 | ~6h | Stream-Architektur-Hardening (Inline-L3 + LookAheadBuffer + Hard-Stop) |
| Phase 3 #3 | 1 | ~3h | L3-Pattern-Coverage gegen 20-Leak-Korpus (Schema-Notation, Wiki-Strukturmarker, Customer-Filename-Leaks) |
| Total | 10 | ~47h | Defense-in-Depth komplett, Saga 14/14 + Pentest-Followup 3/3 closed |
Saga-Lehren¶
Die folgenden methodischen Lehren sind produkt-weit anwendbar und gelten unabhängig vom konkreten Customer-Tenant:
- Phase-0-Discovery zahlt sich aus — Sub-Bug-Funde in der Discovery-Phase verhindern teure Refactor-Schleifen später.
- Cluster-X-False-Positive-Lehre — Pattern-Detection
NIEMALS auf isolierten Single-Keywords; IMMER
primary + min_co_matches. - Audit-Tabellen statt Drop-Behavior — Bei Filter-Match das Original IMMER persisten (Audit-Trail), niemals drop'en; Pattern-Tuning braucht den Original-Text.
- Layer-Reihenfolge L4 → L3 → L2 → L5 ist saga-korrekt — Schnellster Win zuerst, defensives Netz, dann großer Refactor, zum Schluss Multi-Tenancy-Foundation.
- Defense-in-Depth wirkt nur, wenn alle Layer aktiv sind — Niemals nur einen Layer; Failure-Mode jeder Schicht muss vom nächsten gefangen werden.
- Saga-Convention zahlt sich aus — Identische Karten-Struktur (Phase 0 → Commits → Smoke → Code-Review → Merge → Plan-Update) reduziert Cognitive Load.
- Output-Filter-Co-Indicators MÜSSEN Output-Format-Marker sein, niemals User-Input-Begriffe — die Persona reproduziert die User-Input-Phrasen nicht mehr, wenn sie bereinigt wurde, das Pattern stoppt still mit dem Triggern.
- Pre-LLM-Filter-Co-Indicators MÜSSEN User-Input-Vokabular sein, niemals Output-Format-Marker — Inversion von Lehre 7. Filter-Module bauen entweder nach Lehre 7 ODER Lehre 8, nie nach beiden in einem Modul.
- Detection-Event allein ist unvollständige Defense-in-Depth- Verifikation — Smoke prüft (a) Detection, (b) Token-Stream- Inhalt, (c) Stream-Position relativ zum Detection-Event.
- Stream-Architektur ist eigene Verteidigungs-Schicht — Pattern-Detection korrekt zu implementieren ist notwendig aber nicht hinreichend; der Detection-Zeitpunkt relativ zum Token-Stream entscheidet, ob Defense funktioniert.
- Pattern-Detection hat eine harte Untergrenze — schritt- basierte Bot-Antworten ohne Schema-/Debug-Marker sind strukturell vom RAG-Erwartungs-Output ununterscheidbar; Real-Eval-FP-Sweep ist Saga-Konvention für jede zukünftige Pattern-Erweiterung.
- Pentest-Suite-Hardening ist der dritte methodische Pfeiler neben Detection-Pattern und Stream-Architektur — eine versionierte Extended-Pentest-Suite mit Threshold-Konfiguration und nightly-CI-Regression schließt die Defense-in-Depth- Methodik dreidimensional: Detection (Pattern-Coverage gegen externes Korpus) + Architektur (Stream-Position-Timing) + Empirie-Druck (CI mit Threshold-Gates). Real-Eval-FP-Sweep wird damit permanent zweite Threshold-Achse — Pattern-Coverage ohne FP-Garantie wäre tautologische Sicherheit.
- Cleanup-Disziplin: Drifts vertagt sammeln, vor Architektur- Phasen geschlossen — pre-existing Drifts werden während Feature-Karten dokumentiert nicht gefixt; akkumulierte Schulden vor strategischen Architektur-Phasen mit strikten Aufwands-Caps pro Sub-Phase geschlossen; Out-of-Scope-Drifts ehrlich vertagt statt Cleanup-Scope erweitert. Honesty-over-Coverage.
Die ausführliche Langfassung dieser 13 methodischen Lehren mit Herleitungs-Kontext, Cross-References und Karten-Anchor liegt unter Saga-Lehren — Methodische Konstitution.
Visualisierung — Request-Flow (Mermaid)¶
flowchart TD
Request[User Request] --> L5{L5: Multi-turn<br/>Persona-Defense}
L5 -->|persistent_time_marker /<br/>role_override /<br/>forget_previous /<br/>ok_only_conditioning| Block5[history_persist_filter<br/>β-Marker-Replace<br/>+ Cache-Skip]
L5 -->|sauber| Alpha{α: Input-Filter}
Alpha -->|input_format_pressure /<br/>input_prompt_leak /<br/>input_raw_context| BlockA[Pre-LLM-Block<br/>NO_TOKENS<br/>Refusal-Replacement]
Alpha -->|sauber| Cache{Cache: Semantic<br/>Cosine ≥ 0.95}
Cache -->|Hit, language-namespaced| CacheHit[Cached Response]
Cache -->|Miss| L2[L2: Operator-Template<br/>Persona-Cleanup<br/>Spotlighting-Tags]
L2 --> LLM[LLM: vLLM Qwen3-14B<br/>+ LookAheadBuffer K=16]
LLM --> InlineL3{Inline-L3:<br/>check_output<br/>auf buffered text}
InlineL3 -->|Match: PL / RC / JSON-Pressure /<br/>Rules-Block / Persona-Style| HardStop[Hard-Stop SSE<br/>hard_stop=true<br/>clear_previous=true<br/>filter_layer=inline]
InlineL3 -->|kein Match| L4{L4: Post-Stream-<br/>Fallback + SourceWireForm}
L4 -->|Match Post-Hoc| Correction[correction Event<br/>filter_layer=post_stream]
L4 -->|sauber| Stream[Token-Stream<br/>+ SourceWireForm<br/>OHNE content-Feld]
style L5 fill:#fce4ec
style Alpha fill:#e8f5e9
style Cache fill:#fff3e0
style L2 fill:#e3f2fd
style LLM fill:#f3e5f5
style InlineL3 fill:#e0f7fa
style L4 fill:#fafafa
style Block5 fill:#ffebee
style BlockA fill:#ffebee
style HardStop fill:#ffebee
style Correction fill:#fff9c4
style CacheHit fill:#c8e6c9
style Stream fill:#c8e6c9
BPMN-Prozessmodell¶
Standardisierte BPMN-2.0-Notation des Defense-in-Depth-Pipeline.
Quell-XML unter defense-in-depth.bpmn —
importierbar in Camunda Modeler, bpmn.io oder
Cawemo.
Lesehinweis¶
- Gateways (Rauten) repräsentieren Filter-Entscheidungen mit zwei Pfaden: Match → Block-/Stop-Endpoint, kein Match → nächster Layer
- Tasks (Rechtecke) repräsentieren aktive Verarbeitung (L2-Cleanup, LLM-Inference)
- End-Events (Kreise) repräsentieren Pipeline-Outcomes (Block, Hard-Stop, Correction, Stream)
- Audit-Log-Eintrag erfolgt bei jedem Block-/Stop-/Correction-
Endpoint mit
filter_layer-Disambiguation für Drift-Diagnose
Customer-spezifische Erweiterungen¶
Konkrete Pattern-Listen, Filename-Marker und Pentest-Befunde aus der jeweiligen Customer-Demo-Umgebung sind customer-isoliert dokumentiert. Aktuelle Implementierungen:
- AVS-Demo (Erstkunde, Tourismus-Wiki + Meldeschein-Handbuch):
AVS-spezifische Filename-Pattern (
Meldeschein_Handbuch_…), AVS-Doku-Strukturmarker (Eingabefelder Meldeschein,Pflichtfelder (blauer Hintergrund)), Tourismus-Wiki-Phrasen (Begriffsbestimmungen (Definition von Qualitätsnormen)) und Pentest-Bilanz gegen die AVS-Demo-Umgebung — siehe AVS-Doku.
Künftige Customer ergänzen ihre eigene Pattern-Reference unter ihrer jeweiligen Customer-Doku-Subdomain.
Referenzen¶
- Multi-Tenancy-Fundament — Customer-Tenant-Isolation und per-Tenant-Konfiguration
- Saga-Lehre 7: Output-Filter-Co-Indicators MÜSSEN Output-Format- Marker sein, nicht User-Input-Begriffe
- Saga-Lehre 8: Pre-LLM-Filter-Co-Indicators MÜSSEN User-Input- Vokabular sein, niemals Output-Format-Marker (Inversion von Lehre 7)
- Saga-Lehre 9: Detection-Event allein ist unvollständige Defense- in-Depth-Verifikation — Smoke prüft (a) Detection, (b) Token- Stream-Inhalt, (c) Stream-Position
- Saga-Lehre 10: Stream-Architektur ist eigene Verteidigungs- Schicht; Inline-Detection mit Look-Ahead-Buffer + Hard-Stop ist notwendig für Token-Stream-Cleanness
- Saga-Lehre 11: Pattern-Detection hat eine harte Untergrenze — schritt-basierte Bot-Antworten ohne Schema-/Debug-Marker können ohne Legitimate-Answer-FP nicht gefangen werden; Real-Eval-FP- Sweep ist Saga-Konvention