Sicherheitsrunde dokumentiert: vier offene Entscheidungen, Kleinkram, bewusste Nicht-Befunde
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,79 @@
|
||||
Shell schreiben. Das Markdown-Rendering ist jetzt entschärft
|
||||
(`src/markdown.ts`), aber eine echte CSP wäre die Schranke dahinter.
|
||||
Braucht eine Runde Prüfen, was inline benötigt wird (Themes, xterm).
|
||||
Schon ein `default-src 'self'` würde auswärtige Requests und die
|
||||
Fremdnavigation unabhängig vom Sanitizer abschneiden.
|
||||
|
||||
## Aus der Sicherheitsrunde 2026-07-19 (vier Angriffsflächen geprüft)
|
||||
|
||||
Behoben und gepusht (6d44f77): Befehlsinjektion im SessionStart-Hook über den
|
||||
Projektpfad, ungeprüfter Pool-Name als `CLAUDE_CONFIG_DIR`, `check_name` gegen
|
||||
Steuerzeichen (`.desktop`-Injektion), Bild-Beacon im Panel. Dazu `cargo audit`
|
||||
nachgeholt: `plist` auf 1.10.0, `quick-xml` auf 0.41.0 im Laufzeitpfad.
|
||||
|
||||
Offen sind die vier Punkte, die eine Designentscheidung brauchen:
|
||||
|
||||
- [ ] **`term_start` prüft das Fenster-Label nicht (`terminal.rs:96-211`).**
|
||||
Jedes Fenster des Terminal-Prozesses kann sich selbst in die Terminals-Map
|
||||
eintragen (Schlüssel ist `window.label()`, Zeile 207-210) und danach per
|
||||
`term_write` in eine frisch gestartete Shell schreiben. Damit ist auch das
|
||||
abgelöste Panel-Fenster gefährlich, nicht nur das angedockte — und jedes
|
||||
Skript im Webview wird zu Codeausführung, auch ohne XSS.
|
||||
Zu entscheiden: Soll das Panel-Fenster je ein eigenes Terminal starten
|
||||
dürfen? Wenn nein, ist die Prüfung auf `term-*` ein enger Fix.
|
||||
|
||||
Strukturell dahinter: Die Fenster-ACL scheint für App-Commands nicht zu
|
||||
greifen (`gen/schemas/acl-manifests.json` enthält kein App-Manifest) —
|
||||
**vor dem Bauen darauf verifizieren**, die beiden Prüfagenten waren sich
|
||||
in diesem Punkt uneins.
|
||||
|
||||
- [ ] **`write_panel(path)` liest jede Datei, ohne Rückfrage (`mcp.rs:256-259`).**
|
||||
Keine Prüfung gegen Projektordner oder Archiv-Home. Das Tool steht in
|
||||
`PANEL_PERMISSIONS` (`pool.rs:185-188`), läuft also prompt-frei — und
|
||||
umgeht damit das Read-Permission-Modell von Claude Code (`~/.ssh/id_rsa`,
|
||||
`.credentials.json`, fremde `.env`). Rückkanal zum Modell besteht über
|
||||
`write_panel` → `archive_panel` → `search_archive`.
|
||||
Zu entscheiden: Allowlist (Projektordner + Archiv-Home, nach
|
||||
`canonicalize`) oder `path` aus der prompt-freien Freigabe nehmen.
|
||||
Zusätzlich fehlt ein Größenlimit (`path=/dev/zero` hängt den Prozess).
|
||||
|
||||
- [ ] **`archive_panel(dir)` vergibt dauerhaft Schreibrechte (`archive.rs:33-91`).**
|
||||
`dir` ist nicht nur Ablageort: Über `set_project_archive_home` →
|
||||
`add_archive_permission` landet `additionalDirectories += dir` **und**
|
||||
`allow += "Edit(dir/**)"` in der `.claude/settings.json` des Projekts.
|
||||
Der einzige Guard (archive.rs:41) lehnt nur Vorfahren des Home ab —
|
||||
`~/.claude` passiert, womit die nächste Session eigene **Hooks** schreiben
|
||||
darf. `create_dir_all` legt das Ziel vorher an.
|
||||
Vorschlag: `dir` aus dem MCP-Tool entfernen, Archiv-Home nur über die UI.
|
||||
|
||||
- [ ] **Nicht-atomare Schreibvorgänge auf fremde Dateien.**
|
||||
Überall `fs::write` (truncate + write), nirgends temp + `rename`.
|
||||
Betrifft u. a. die `.claude/settings.json` der Projekte, Claudes
|
||||
`.claude.json` in den Pools (`pool.rs:289`), die Registry und die
|
||||
App-Settings. Die Leseseite haben wir gehärtet, die Schreibseite nicht:
|
||||
Absturz oder volle Platte hinterlässt abgeschnittenes JSON in Dateien,
|
||||
die der App nicht gehören.
|
||||
|
||||
Kleinere Punkte aus derselben Runde, bewusst zurückgestellt:
|
||||
`panel_file` und Geschwister (`paths.rs:55-84`) ohne `check_name` (zweite
|
||||
Linie); `write_secret_file` (`unix.rs:48-55`) schreibt erst mit umask-Rechten
|
||||
und setzt danach 0600, `create_new` mit Modus löst das samt Symlink-Frage;
|
||||
API-Key steht unter macOS kurz in der Prozess-Kommandozeile
|
||||
(`macos.rs:101-103`, `ps`-sichtbar, Linux/Windows nicht betroffen); die PTY-Umgebung
|
||||
wird nicht bereinigt (`terminal.rs:134-144`, kein `env_clear` — ein
|
||||
`ANTHROPIC_API_KEY` aus dem Shell-Profil sticht den Pool-`apiKeyHelper`);
|
||||
Bidi-/Zero-Width-Zeichen in den Befehlskacheln (`commands-view.ts:123`), was
|
||||
Anzeige und Zwischenablage auseinanderlaufen lässt.
|
||||
|
||||
Ausdrücklich **kein** Handlungsbedarf (Stand 2026-07-19): `sync_all_desktops`
|
||||
räumt `aicontrol-*.desktop` auf — der Präfix gehört uns. Falls es je stört,
|
||||
wäre `art.lintus.`-Präfix die saubere Variante.
|
||||
|
||||
Nicht als Sicherheitsgrenze missverstehen: Pools trennen Konfiguration, nicht
|
||||
Zugriff. Die Keychain-Einträge sind bewusst über `/usr/bin/security` angelegt,
|
||||
damit der `apiKeyHelper` promptfrei liest — womit jeder Prozess des Nutzers
|
||||
jeden Pool-Key lesen kann. Beim Design so gewollt, aber nichts, worauf man
|
||||
Isolationsversprechen bauen sollte.
|
||||
|
||||
- [ ] **`write_app_setting` verliert die übrigen App-Settings (`settings.rs:71`).**
|
||||
Dieselbe Fehlerklasse wie die `.claude.json` in `pool.rs`, nur eine Datei
|
||||
|
||||
Reference in New Issue
Block a user