Governance & Sicherheit
Governance und Sicherheit von Anfang an — nicht nachträglich angeflanscht
nr-llm bündelt genau die Punkte, nach denen ein Security-Review tatsächlich fragt: wo die Secrets liegen, wer was darf, was das Modell senden und empfangen darf, wie die Kosten gedeckelt sind und wohin die Daten gehen. Jede dieser Maßnahmen ist in einem Architecture Decision Record dokumentiert.
KI in einem CMS wirft jedes Mal dieselben Fragen auf: Sind unsere API-Keys sicher, kann eine Redakteurin die Kosten in die Höhe treiben, könnte das Modell ein Secret preisgeben, und verlassen unsere Daten das Haus? Weil nr-llm gemeinsame Infrastruktur ist und kein einzelnes Feature, beantwortet es diese Fragen einmal, an einer Stelle, für jede Extension der Website.
Die Kontrollen auf einen Blick
- API-Keys als verschlüsselte nr-vault-Identifier gespeichert — nie im Klartext, nie protokolliert
- Backend-Modul nur für Administratoren, dazu kapabilitätsbezogene Berechtigungen über TYPO3-Backend-Gruppen
- Guardrail-Pipeline, die Eingabe, Ausgabe, Reasoning und gestreamte Chunks prüft und maskiert
- Human-in-the-Loop-Freigabe für Aktionen mit Seiteneffekten
- 41 nur lesende Built-in-Tools in fail-closed-Gruppen, mit fail-closed-Netzwerkzugriff
- Budgets pro Benutzer (Requests, Tokens, Kosten — täglich und monatlich) samt Nutzungsanalyse
- Vollständiger Betrieb auf lokalem Ollama oder jedem OpenAI-kompatiblen Endpoint — ohne Datenabfluss
- Signierte Releases: SLSA-Level-3-Provenance, Cosign-Signaturen, SBOMs in SPDX + CycloneDX
Secrets & Schlüsselverwaltung
nr-llm speichert einen LLM-API-Key nie im Klartext. Alle Zugangsdaten von Providern und spezialisierten Diensten liegen als nr-vault-Identifier — eine UUID — vor, während das Secret selbst in der Extension netresearch/nr-vault liegt, die Envelope-Verschlüsselung, Audit-Logging und Zugriffskontrolle bereitstellt.
Zum Aufrufzeitpunkt löst der sichere HTTP-Client des Vaults das Secret auf, fügt es in die ausgehende Anfrage ein, protokolliert den Zugriff und löscht es unmittelbar danach aus dem Speicher. Der Klartext-Schlüssel taucht weder im Code von nr-llm noch in einem Datenbank-Dump oder einer Log-Zeile auf. Zusätzlich werden Fehlermeldungen bereinigt: Secret-tragende Query-Parameter wie ?key= und ?token= werden entfernt, bevor etwas protokolliert oder angezeigt wird.
Zugriffskontrolle
Das gesamte Backend-Modul von nr-llm ist ausschließlich Administratoren vorbehalten. Jeder Backend-Endpoint — Änderungen an Providern, Modellen und Konfigurationen, die Test-Aufrufe zur Entschlüsselung von Vault-Keys, die Task-Ausführung, der Tool-Playground — ist zusätzlich abgesichert, sodass ein Nicht-Administrator ein einheitliches 403 erhält, bevor ein Zustand geändert oder ein Schlüssel entschlüsselt wird.
Über das Administrator-Gate hinaus ist jede der elf KI-Kapabilitäten — Chat, Completion, Embeddings, Vision, Streaming, Tools, JSON-Modus, Audio, Bild, Text-to-Speech und Transkription — eine native Berechtigung der TYPO3-Backend-Gruppen. So kann ein Administrator eine einzelne Kapabilität websiteweit über die Standard-Gruppenbearbeitung erteilen oder entziehen. Benannte Konfigurationen tragen zudem ihre eigene Zugriffsgruppen-ACL, und ein Aufruf muss sowohl die Konfigurations-ACL als auch die Kapabilitäts-Berechtigung erfüllen.
Guardrails: Eingabe, Ausgabe & Streaming-Maskierung
Modellausgaben und Benutzereingaben werden als nicht vertrauenswürdige Inhalte behandelt und durchlaufen eine Guardrail-Pipeline, die ein echtes Verdikt zurückgibt — zulassen, maskieren, wiederholen, Freigabe anfordern oder ablehnen — kein bloßes Boolean. Auf der Antwortseite läuft die Prüfung innerhalb der Persistenzschicht, sodass ein Secret, das ein Modell zurückgibt, maskiert oder die Antwort blockiert wird, bevor sie je gecacht oder erneut ausgeliefert wird. Auf der Eingabeseite wird der ausgehende Prompt geprüft und kann maskiert werden, bevor er die Extension verlässt.
Streaming, früher ein blinder Fleck, ist live abgedeckt: Ein Holdback-Puffer maskiert ein Secret auch dann, wenn es über zwei Chunks verteilt ist, und die Ausgabegrenze ist UTF-8-sicher. Die Prüfung umfasst jede Grenze, die dasselbe Secret überschreiten kann — die Antwort, das Reasoning des Modells, den Benutzer-Turn, den System-Prompt und Vision-Text. Secret-Maskierung und die Durchsetzung des Provider-Content-Filters sind aktiv ausgeliefert, und neue Guardrails werden allein dadurch aktiv, dass sie existieren.
Human-in-the-Loop-Freigabe
Ein Tool, das schreibt oder Seiteneffekte hat, kann vor der Ausführung eine menschliche Freigabe verlangen. Das Tool meldet sich mit einem einzigen Marker an; die Agent-Schleife pausiert daraufhin den gesamten Turn, persistiert ein serialisiertes Transkript für diesen Durchlauf im Zustand „wartet auf Freigabe“ und legt es zur Freigabe oder Ablehnung vor.
Bei Freigabe setzt der Lauf genau dort fort, wo er pausiert hat; bei Ablehnung wird das dem Modell mitgeteilt, und es fährt fort. Die 41 heute ausgelieferten Tools sind alle nur lesend, sodass dieser Pfad für sie nie greift und ihr Verhalten unverändert bleibt — er ist für den Moment da, in dem ein schreibfähiges Tool hinzukommt. Ein „Freigabe anfordern“-Verdikt eines Guardrails läuft in dieselbe Prüfnahtstelle.
Entscheidungen: ADR 084
Tool-Sicherheit
Jedes der 41 Built-in-Tools ist nur lesend, und jedes folgt einem Sicherheitsvertrag: Vom Modell gewählte Argumente werden validiert und begrenzt, Ausgabemengen sind gedeckelt, und jede Secret-tragende Ausgabe wird maskiert oder hinter eine separate Raw-Variante gesperrt, die deaktiviert ausgeliefert wird. Die meisten Tools erfordern Administratorrechte; die nur lesenden Struktur-, Inhalts- und Datei-Tools, die Nicht-Administratoren angeboten werden, setzen die eigenen TYPO3-Berechtigungen dieser Benutzerin durch.
Tools sind in Gruppen mit einer dreistufigen, fail-closed-Freigabekaskade organisiert: Eine deaktivierte Gruppe lässt sich nicht durch eine Einzel-Tool-Übersteuerung reaktivieren, und ein Tool, das ein Skill nicht gewährt hat, ist über Prompt-Injection nie erreichbar. Der Netzwerkzugriff wird pro Gruppe geregelt und ist fail-closed — eine Gruppe ohne Deklaration sendet keine ausgehende Anfrage, und es gibt keinen „beliebiger Host“-Scope. Host-nahe Tools laufen über einen Path-Guard, der settings.php und Schlüsselmaterial selbst für Administratoren strukturell unlesbar macht, und die URL-Prüfung ist auf die eigene Website der Instanz begrenzt. Jeder Lauf ist eine begrenzte Agent-Schleife.
Kosten-Governance
Budgets pro Benutzer deckeln die KI-Ausgaben jeder Backend-Benutzerin unabhängig von den täglichen Limits pro Konfiguration. Ein Budget trägt sechs unabhängige Obergrenzen — Requests, Tokens und Kosten, jeweils täglich und monatlich — und ist eine Obergrenze, kein Zähler: Die Nutzung wird bei Bedarf aus der einen Nutzungstabelle aggregiert, sodass beide nie auseinanderdriften können.
Die Prüfung ist ein reiner Pre-Flight vor jedem Aufruf; über dem Budget führt sie zu einer expliziten Ablehnung, die das überschrittene Limit benennt — nie zu stillem Throttling. Jeder Request wird der aufrufenden Backend-Benutzerin zugeordnet und in einem Analytics-Dashboard für Administratoren aufgerollt — Kosten- und Request-Trends, Aufschlüsselungen nach Provider, Modell und Dienst sowie der Verbrauch jeder Benutzerin gegen ihr Monatsbudget. Idempotente Completions werden gecacht, sodass ein wiederholter Aufruf nicht zweimal bezahlt wird.
Datenhaltung & Datenschutz
Wo das Modell läuft, ist deine Entscheidung. nr-llm spricht mit Ollama und jedem OpenAI-kompatiblen Endpoint — vLLM, LocalAI, LiteLLM —, sodass eine Instanz vollständig auf selbst gehosteten On-Premises-Modellen laufen kann, ohne dass Prompts oder Inhalte das Netzwerk verlassen, oder je Konfiguration einen gehosteten Provider nutzen kann, wo das vertretbar ist.
Weil Tool-Ausgaben und jede Modellantwort an den gewählten Provider gehen, behandelt die Extension beide als nicht vertrauenswürdig: Tool-Ergebnisse sind mengenbegrenzt und um personenbezogene Felder bereinigt, Antworten werden escaped gerendert, und HTML wird nur in einer Sandbox-Vorschau angezeigt.
Entscheidungen: ADR 001
Supply-Chain-Integrität
Jedes Release ist signiert und verifizierbar. Release-Artefakte tragen keyless Cosign-Signaturen (Sigstore), SHA-256-Prüfsummen, eine Software Bill of Materials in den Formaten SPDX und CycloneDX sowie SLSA-Level-3-Provenance-Attestierungen, die sich mit gh attestation verify prüfen lassen. Commits sind kryptografisch signiert und per DCO abgezeichnet.
Die CI-Pipeline führt CodeQL-Semantikanalyse, Gitleaks-Secret-Scanning, OpenSSF Scorecard, Dependency-Review mit CVE- und Lizenz-Gating sowie wöchentliche Dependency-Audits aus; GitHub Actions von Dritten sind auf vollständige Commit-SHAs gepinnt, und die Release-Orchestrierung läuft über einen gemeinsamen, per Scorecard überwachten Reusable Workflow.
Lizenz & Offenheit
nr-llm ist freie und quelloffene Software unter GPL-2.0-or-later, herausgegeben von der Netresearch DTT GmbH. Das Design ist offen dokumentiert: 89 Architecture Decision Records legen jede Sicherheits- und Architekturentscheidung dar — auch die auf dieser Seite — samt der geprüften Alternativen und der Gründe für ihre Ablehnung.
Sicherheitslücken werden über das private Vulnerability-Reporting von GitHub behandelt. Transparenz ist selbst Teil der Haltung: Nichts auf dieser Seite muss man auf Vertrauen hinnehmen, denn die Begründung hinter jeder Maßnahme ist als ADR veröffentlicht.
Entwickler
Für Entwickler: der Governance-Vertrag
Guardrails, Freigabe und Budgets werden von der Middleware-Pipeline durchgesetzt — du rufst sie nicht auf, du fängst ab, was sie werfen. Jeder Governance-Fehlschlag ist eine typisierte Exception, sodass eine konsumierende Extension sauber degradiert, statt einen Stacktrace zu zeigen.
use Netresearch\NrLlm\Exception\GuardrailViolationException;
use Netresearch\NrLlm\Exception\GuardrailApprovalRequiredException;
use Netresearch\NrLlm\Exception\BudgetExceededException;
try {
$response = $this->llm->chat($messages);
} catch (GuardrailViolationException $e) {
// Input or output blocked by policy — show a safe, generic message.
return 'Diese Anfrage wurde von der Content-Policy blockiert.';
} catch (GuardrailApprovalRequiredException $e) {
// Paused: a backend user must approve before the action runs.
return 'Zur Freigabe eingereicht. Sie läuft, sobald ein Administrator sie freigibt.';
} catch (BudgetExceededException $e) {
// This account's per-user AI budget is exhausted.
return 'Das KI-Budget deines Kontos ist vorerst aufgebraucht.';
}
FAQ zu Governance & Sicherheit
Werden meine API-Keys jemals im Klartext preisgegeben?
Nein. Keys werden als nr-vault-Identifier (UUIDs) gespeichert, nicht als Werte. Das Klartext-Secret wird zum Aufrufzeitpunkt im auditierten HTTP-Client des Vaults aufgelöst und unmittelbar danach aus dem Speicher gelöscht; es taucht nie in der Datenbank, den Logs, den Fehlermeldungen oder der Backend-Ausgabe von nr-llm auf.
Kann ich das betreiben, ohne Daten an einen Drittanbieter-KI-Provider zu senden?
Ja. Richte eine Konfiguration auf ein selbst gehostetes Ollama oder einen OpenAI-kompatiblen Endpoint (vLLM, LocalAI, LiteLLM) aus, und die Anfrage verlässt nie dein Netzwerk. Die Provider-Wahl erfolgt je Konfiguration, sodass datensensible Workloads lokal bleiben, während andere einen gehosteten Provider nutzen.
Was hindert den KI-Agenten daran, Secrets zu lesen oder Daten zu ändern?
Alle 41 Built-in-Tools sind nur lesend; Secret-tragende Ausgaben werden maskiert oder hinter deaktivierten Raw-Varianten gehalten; Dateien wie settings.php sind strukturell unlesbar; Tool-Gruppen und Netzwerkzugriff sind fail-closed; und jedes künftige schreibfähige Tool suspendiert den Lauf zunächst für eine menschliche Freigabe.
Wie verhindere ich, dass eine einzelne Redakteurin die Kosten in die Höhe treibt?
Gib ihr ein Budget pro Benutzer mit täglichen und monatlichen Obergrenzen für Requests, Tokens und Kosten. Eine Pre-Flight-Prüfung lehnt den Aufruf mit klarer Begründung ab, sobald eine Obergrenze erreicht ist, und das Analytics-Dashboard zeigt die Ausgaben jeder Benutzerin gegen ihr Budget.
Könnte ein Modell ein Secret preisgeben, das es erhalten hat?
Die Guardrail-Pipeline prüft den Prompt, die Antwort, das Reasoning des Modells, den System-Prompt, Vision-Text und gestreamte Chunks und maskiert Secret-förmige Zeichenketten, bevor sie gecacht, gestreamt oder angezeigt werden — auch ein Secret, das über zwei Streaming-Chunks verteilt ist.
Wie überprüfe ich, dass ein Release nicht manipuliert wurde?
Jedes Release liefert eine Cosign-Signatur, SHA-256-Prüfsummen, SBOMs in SPDX und CycloneDX sowie SLSA-Level-3-Provenance, die du mit gh attestation verify prüfen kannst.