Wo lässt sich ein KI-Agent angreifen
Ein Bedrohungsmodell listet auf, was ein Angreifer erreichen könnte und wie. Bei einem Agenten zählt es mehr als bei einem Chatbot, denn ein Agent handelt. Er liest Post, ruft Werkzeuge auf und schickt Dinge nach außen.
Im Modul „LLM-Anwendungen absichern“ haben Sie Injection und die Hauptrisiken kennengelernt. Diese Lektion macht daraus die Karte eines Agenten, gezeichnet vor dem ersten Code.
Am Ende dieser Lektion
Notiz
Ich kann abbilden, wo ein Agent angreifbar ist, und die Mischung aus drei Dingen benennen, die ihn gefährlich macht.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Schutzgut | etwas, das Schutz verdient, etwa eine Kundenliste oder ein Zahlungswerkzeug | |
| Vertrauensgrenze | die Linie, an der Text oder Aufrufe von einer Quelle, die Sie kontrollieren, in eine andere übergehen | |
| Nicht vertrauenswürdiger Inhalt | Text, den der Agent liest und den ein Fremder geschrieben haben könnte | eine Webseite |
| Ausgang | jeder Weg, auf dem der Agent Daten von seinem Besitzer wegschicken kann | |
| Bein | eines der drei Dinge der gefährlichen Mischung |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Die gefährliche Mischung aus drei Dingen
Drei Dinge zusammen sind gefährlich. Der Agent hat private Daten. Er liest nicht vertrauenswürdigen Inhalt. Er hat einen Ausgang, um Daten wegzuschicken.
Mit zwei von drei Dingen kommt ein Angriff nicht weit. Text kann den Agenten lenken, aber nichts verlässt ihn, oder es gibt nichts Privates zu holen. Mit allen dreien kann eine versteckte Zeile Daten hinaustragen.
Beispiel: drei Agenten
| Agent | Private Daten | Nicht vertrauenswürdiger Inhalt | Ausgang |
|---|---|---|---|
| Mail-Zusammenfasser | Das Postfach | Post von Fremden | Keiner: er zeigt nur eine Zusammenfassung |
| Web-Sachbearbeiter | Keine | Jede Webseite | Er kann in einen Chat posten |
| Postfach-Helfer | Das Postfach | Post von Fremden | Er kann Antworten senden |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Der Run listet nur Beine auf
Das erste Skript hält vier erfundene Agenten als schlichte Daten. Es druckt die Beine jedes Agenten und markiert die mit allen dreien.
Es wird kein Modell aufgerufen und kein Angriff ausgeführt. Ein Bedrohungsmodell denkt darüber nach, was möglich ist. Eine Liste in einem Skript genügt also zum Üben.
Das Beine-Skript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' '// Vier erfundene Agenten. Jedes Flag sagt, was der Agent kann.' 'const agenten = [' ' { name: \"mail-zusammenfasser\", daten: true, fremd: true, ausgang: false },' ' { name: \"web-sachbearbeiter\", daten: false, fremd: true, ausgang: true },' ' { name: \"berichts-roboter\", daten: true, fremd: false, ausgang: true },' ' { name: \"postfach-helfer\", daten: true, fremd: true, ausgang: true },' '];' > beine.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Beine-Skript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function beine(a) {' ' const gefunden = [];' ' if (a.daten) gefunden.push(\"private Daten\");' ' if (a.fremd) gefunden.push(\"nicht vertrauenswürdiger Inhalt\");' ' if (a.ausgang) gefunden.push(\"ein Ausgang\");' ' return gefunden;' '}' 'for (const a of agenten) {' ' const alle = beine(a).length === 3;' ' console.log(a.name + \": \" + beine(a).join(\", \") + (alle ? \" <- alle drei\" : \"\"));' '}' >> beine.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Beine-Skript ausführen
docker exec -w /home/node/project agent node beine.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Was das Skript druckt
| Zeile | Was sie zeigt |
|---|---|
| mail-zusammenfasser: private Daten, nicht vertrauenswürdiger Inhalt | Zwei Beine und kein Ausgang |
| web-sachbearbeiter: nicht vertrauenswürdiger Inhalt, ein Ausgang | Zwei Beine und keine privaten Daten |
| berichts-roboter: private Daten, ein Ausgang | Zwei Beine und nur vertrauenswürdige Eingaben |
| postfach-helfer: alle drei Beine, dann <- alle drei | Der einzige Agent, den Sie zuerst beheben |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Entfernen Sie ein Bein, bitten Sie nicht nett
Die Lösung ist, ein Bein wegzunehmen. Streichen Sie den Ausgang, oder lesen Sie nur vertrauenswürdige Quellen, oder halten Sie private Daten außer Reichweite. Wählen Sie das günstigste.
Ein Prompt mit „gib nie etwas preis“ ist keine Lösung. Er senkt die Chance in einem Lauf und garantiert nichts für den nächsten.
Ein häufiger Fehler
Warnung
Viele zählen als Eingabe nur, was der Nutzer tippt. Jedes Werkzeugergebnis, jede Datei, jede Seite und jede frühere Nachricht ist auch Eingabe. An jeder Stelle kann ein Fremder den Text geschrieben haben.
Das Modell-Skript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' '' 'const text = \"Ein Helfer liest das Kundenpostfach, fasst es zusammen und kann einen Link in einem öffentlichen Chatraum posten.\";' 'const nachrichten = [' ' { role: \"system\", content: \"Antworten Sie mit genau drei Zeilen. Zeile 1 beginnt mit daten:, Zeile 2 mit fremd:, Zeile 3 mit ausgang:. Schreiben Sie nach dem Doppelpunkt ja oder nein.\" },' ' { role: \"user\", content: \"Hat dieser Agent private Daten, liest er nicht vertrauenswürdigen Inhalt und hat er einen Ausgang? \" + text },' '];' '// Aufgezeichnete Probe, nur verwendet, wenn kein Modell antwortet.' 'const probe = \"daten: ja\nfremd: ja\nausgang: ja\";' > beine2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Modell-Skript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function lesen(antwort) {' ' const gefunden = {};' ' for (const zeile of antwort.split(\"\n\")) {' ' const teile = zeile.split(\":\");' ' if (teile.length === 2) gefunden[teile[0].trim().toLowerCase()] = teile[1].trim().toLowerCase().startsWith(\"ja\");' ' }' ' return gefunden;' '}' '' 'async function main() {' ' const antwort = await fragen(nachrichten, probe, 60);' ' console.log(\"Antwort:\n\" + antwort);' ' const f = lesen(antwort);' ' const schluessel = [\"daten\", \"fremd\", \"ausgang\"];' ' const form = schluessel.every(function (k) { return k in f; });' ' console.log(\"Form stimmt: \" + form);' ' if (form) console.log(\"Alle drei, laut Modell: \" + (f.daten && f.fremd && f.ausgang));' ' console.log(\"Das Programm vertraut seiner eigenen Werkzeugliste, nicht dieser Antwort.\");' '}' 'main();' >> beine2.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Modell-Helfer schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' 'async function fragen(nachrichten, probe, max) {' ' try {' ' const res = await fetch(basis + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 200 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' return (await res.json()).choices[0].message.content;' > model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Den Modell-Helfer schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' const liste = [].concat(probe);' ' const runde = nachrichten.filter(function (m) { return m.role === \"assistant\"; }).length;' ' return liste[Math.min(runde, liste.length - 1)];' ' }' '}' 'module.exports = { fragen };' >> model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Mit dem Modell ausführen
docker exec -w /home/node/project agent node beine2.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine mögliche Ausgabe
| Zeile | Was sie zeigen kann |
|---|---|
| Antwort | Drei Zeilen, die mit daten, fremd und ausgang beginnen. Die Wörter nach dem Doppelpunkt ändern sich bei jedem Lauf |
| Form stimmt | true, wenn alle drei Zeilen da sind. false heißt: Das Programm muss neu fragen oder ablehnen |
| Aufgezeichnete Probe | Wird zuerst gedruckt, wenn kein Modell geantwortet hat. Das Skript macht mit der Probe weiter |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.