Sicherheit
Auf dieser Seite
Der Hub führt Skripte aus, die ein Modell geschrieben hat, mit Ihren Rechten, in Ihren Anwendungen. Die Seite sagt, was der Hub begrenzt, welche Risiken bleiben und was Ihren Rechner verlässt, und nennt die dafür wiederholten Messungen. Sie richtet sich an alle, die entscheiden, ob sie ein Modell mit ihren Anwendungen verbinden.
Die Messungen liefen unter Debian 13 mit dem Hub 0.1.0, gebaut aus seinen Quellen; die an einem laufenden Hub nutzten ein Wegwerf-Home-Verzeichnis mit eigenem Token.
Was den Rechner verlässt
Alles, was der Hub zurückgibt, geht an das Sprachmodell und damit an alle, die es ausführen.
| Was | Verlässt den Rechner |
|---|---|
| Das Skript, das das Modell geschrieben hat | Ja: Das Modell ist sein Autor |
stdout, stderr und result eines Skripts | Ja: Sie können den Inhalt eines Dokuments enthalten |
| Die Fehlerspur | Ja: Sie enthält Pfade des Rechners |
state | Ja: Er enthält Inhalte aus den geöffneten Dokumenten |
| Der Pfad einer Aufnahme | Ja: er gehört zur Antwort |
| Das Bild einer Aufnahme | Nur wenn das Modell die Datei liest |
| Das Audit-Journal, das Token und die Konfiguration | Nie |
Wer in einer verbundenen Anwendung ein vertrauliches Dokument öffnet, weiß, dass das Modell dessen Inhalt lesen kann. Bei der Wiederholung gab get_state die Bezeichnung Notes einer Ebene zurück, die ein Skript angelegt hatte, mit content_origin auf document; diese Bezeichnung wird so gelesen wie der Inhalt eines Dokuments.
Der Hub verbindet sich nur mit Brücken auf 127.0.0.1. Unter strace -f -e trace=connect,bind,listen durch eine Sitzung hindurch, die ein Skript enthielt, das seine Frist überschritt, machte der Hub insgesamt ein connect über IP: zu 127.0.0.1, auf dem Port der Blender-Brücke. cargo test --locked --test invariants sucht im Quelltext nach jeder weiteren.
Wer eine Brücke erreichen kann
Eine Brücke lauscht nur auf 127.0.0.1, nimmt jeweils eine Verbindung an und antwortet einem Client, der mit dem Token beginnt. ss -ltn zeigte einen lauschenden Socket für die Blender-Brücke, auf dem für den Lauf gesetzten Port: 127.0.0.1:9313. Vier Proben wurden an sie gesendet, bevor sich der Hub verband:
- Ein
hellomit falschem Token: 0 Bytes zurück, und die Verbindung wurde sofort geschlossen. - Eine HTTP-Anfrage: 0 Bytes zurück, und die Verbindung wurde sofort geschlossen.
- Nichts gesendet: 0 Bytes zurück, und die Verbindung wurde nach 5,0 s geschlossen.
- Ein
hellomit dem richtigen Token: 99 Bytes zurück, diehello-Antwort, die die Anwendung und die Versionen nennt und das Token nicht enthält. Die Verbindung blieb offen.
Der eigene UNO-Port von LibreOffice hat keine Authentifizierung. Mit soffice, das auf 127.0.0.1:2102 lauschte, und ohne vorgelegtes Token las ein Python-Client mit python3-uno die LibreOffice-Version 25.2.3.2, öffnete ein Calc-Dokument und schrieb eine Zelle hinein. Dieser Weg umgeht das Token, die Skriptsperre und das Audit-Journal.
Was der Hub begrenzt
Die Grenzen sind Schlüssel des Abschnitts [hub] in config.toml, in der Datei, die init schreibt; die Werte unten sind die Standardwerte, die sie aufführt.
- Skriptgröße,
max_script_bytes, 262 144 Bytes: Ein Skript von 300 009 Bytes wurde mitscript is 300009 bytes; the limit is 262144 bytesabgelehnt. - Ausgabe pro Strom,
max_output_bytes, 1 048 576 Bytes: Ein Skript, das 2 000 000 Zeichen ausgab, lieferte einstdoutvon 1 048 576 Bytes und"truncated": true. - Zeit,
default_timeout_s, 30 s: Im Modusclikamtimeoutnach 30,0 s, kein Kindprozess blieb zurück, und der nächste Aufruf war nach 31 msok. Im Modustcpkamtimeoutnach 31,2 s (32,0 s im zweiten Lauf), dannbusyfür den nächsten Aufruf. - Ein Skript zur Zeit pro Anwendung: das
busyoben. Im Modustcpwurde die Anwendung nicht angehalten; sie führte ihr Skript von 40 Sekunden bis zum Ende aus, und der Hub antwortete 40,3 s nach dem Start wieder mitok(40,1 s im zweiten Lauf).
Nur der Modus cli beendet ein Skript, das seine Zeit überschreitet. In den Modi tcp und uno kann der Hub ein Skript in der Anwendung nicht unterbrechen: Er antwortet timeout, lehnt neue Skripte mit busy ab und wartet.
Die Skriptsperre
Die Sperre liest den Text eines Skripts, bevor es gesendet wird. Ein Skript, das os.remove aufrief, wurde abgelehnt, bevor es Inkscape erreichte, mit Kategorie, Konstrukt und Zeile: G-1 (file deletion) at line 3: os.remove. Lässt sich ein Pfad aus dem Text nicht prüfen, lässt die Sperre das Skript durch und fügt stderr eine Warnung hinzu, zum Beispiel path not statically verifiable (open()).
Ein Skript, das eine zweite Datei schrieb und mit runpy ausführte, löschte eine Datei, die es selbst angelegt hatte, und der Hub antwortete ok. Das ist die Grenze, die die README des Repositorys nennt: Die Sperre sieht runpy, pickle, http.server, die Speicherfunktionen der Anwendungen und einen Pfad, der einer Funktion als Parameter übergeben wird, nicht. Der Bediener hebt die Sperre mit allow_dangerous_scripts = true im Abschnitt [security] auf; die beiden Werkzeuge kennen keinen solchen Parameter, und das Journal verzeichnet dann guard: bypassed.
Zu den Fehlalarmen der Sperre gab cargo test --locked --test guard realistic -- --nocapture aus: false positives: 0 of 21 realistic scripts (0.0%).
Dateien, Modi und verweigerter Start
Nach init hatten config.toml und token beide den Modus 600. Eine Aufnahme, die get_state angefordert hatte, war eine Datei im Modus 600 in einem Verzeichnis im Modus 700 unter XDG_RUNTIME_DIR; sie war nach dem Ende des Hubs mit Exit-Code 0 noch vorhanden.
Der Hub verweigerte den Start, mit Exit-Code 1 und einer erklärenden Zeile, in fünf Fällen:
| Fall | Meldung, ohne den Pfad |
|---|---|
| die Token-Datei im Modus 0640 | has mode 0640; expected 0600 (chmod 600) |
| keine Token-Datei | does not exist |
config.toml im Modus 0644 | configuration file refused: … has mode 0644; expected 0600 (chmod 600) |
| das Laufzeitverzeichnis des Hubs im Modus 0755 | has mode 0755; expected 0700 (chmod 700) |
XDG_RUNTIME_DIR nicht gesetzt | XDG_RUNTIME_DIR is not set; refusing to write volatile files elsewhere |
Der Wert des Tokens erschien in keiner dieser Meldungen. libremodular-launch libreoffice lehnte eine Brückendatei im Modus 0664 ab, bevor es irgendetwas startete, mit Exit-Code 2: has mode 0664 and can be changed by the group or by others (chmod go-w).
Das Audit-Journal
Jeder Aufruf schreibt eine Zeile in audit.jsonl im Zustandsverzeichnis, im Modus 600, auch get_state. Vier Aufrufe (ein Skript, das lief, eines, das die Sperre ablehnte, eines, das einen Fehler auslöste, und eines für eine deaktivierte Anwendung) schrieben vier Zeilen. Eine Zeile enthält das Datum, das Werkzeug, das Ziel, den Status, die Dauer, die Größe und den SHA-256 des Skripts, das Ergebnis der Sperre und die Größe der Ausgabe:
{
"ts": "2026-10-21T08:56:27.564Z",
"tool": "execute_script",
"target_app": "inkscape",
"status": "refused",
"duration_ms": 0,
"script_bytes": 60,
"script_sha256": "3696b8a4f24f23da34ba239bbb401c56cd78fb53c2bef48ab2f7d668fd1fdbf8",
"guard": [
"G-1"
],
"output_bytes": 524
}
Die Datei hält jeden Eintrag in einer Zeile; hier ist er umbrochen, damit er sich lesen lässt.
Eine Markierungszeichenfolge, die in die Skripte gesetzt wurde, fand sich nicht im Journal, ebenso wenig das Token. Der Skripttext wird nur geschrieben, wenn der Bediener audit_script_text = true setzt.
Die Tests des Repositorys
Diese Befehle sind die der CI des Repositorys. Sie liefen außerhalb des Repositorys (CARGO_TARGET_DIR).
| Befehl | Ergebnis |
|---|---|
cargo fmt --check | Exit-Code 0 |
cargo clippy --all-targets --locked -- -D warnings | Exit-Code 0 |
cargo test --locked | 328 bestanden, 0 fehlgeschlagen, 3 ignoriert: zwei brauchen ein echtes LibreOffice, einer einen Benutzer, der nicht root ist |
cargo test --locked --test invariants | 36 bestanden |
python3 scripts/build_bridges.py --check | Exit-Code 0 |
python3 -m unittest discover -s tests/bridges | 189 Tests, OK, 6 übersprungen: zwei brauchen root, vier gelten nur unter Windows |
Eine Schwachstelle melden Sie wie unter Über das Projekt beschrieben.