AI-Entwicklung

Warum AI-Coding-Agents eine Rechtekontrolle brauchen: Shell, Git und Dateisystem als JSON-Policy (2026)

Ca. 16 Min.

Der Sicherheitstext hat die Angriffsfläche schon beschrieben. Dieser schreibt nur das Rechtemodell: ein Tool-Aufruf ist JSON; die Ausführung sitzt beim Host. Shell, Git und Dateisystem sind drei Türen. Allow klicken ist nicht die Sandbox.

Bevor Sie lesen

Tür Was sie schließt Wer ausführt
Shell Befehlszeichenketten, Verbundbefehle allow / ask / deny; Sandbox extra
Git status, diff, commit, push; hooks / config Workspace schreiben ≠ Metadaten schreiben
Dateisystem src, .env, Pfade außerhalb Tool-Regeln + OS-Sandbox
Netz Domains, Ausgang Standard aus; Liste extra öffnen

Der Host bewertet die Policy. Das Modell füllt JSON. Es rückt die Tür nicht.

Rechtekontrolle, weil das Modell nicht ausführt

Ruft ein Coding-Agent ein Tool, gibt das Modell nur JSON aus: Name und Argumente. Der Host läuft git status oder ändert src/orders/A-1042.json. Schema sperrt die Form. Die Rechtepolicy sperrt, ob ein wohlgeformter Aufruf laufen darf. Ohne die zweite Tür ist die erste Höflichkeit.

  • Schema: Argumente schließen. Ein Befehl ist ein String. Ein Pfad bleibt unter einem vereinbarten Präfix.
  • Rechtepolicy: allow / ask / deny. Offizielle Reihenfolge: deny, ask, allow. Ein enges allow durchlöchert kein weites deny.
  • Sandbox: eine OS-Schicht. Lenkt eine Prompt-Injection das Modell, bleibt der Prozess im Workspace. Ein Klick auf Freigabe öffnet die Sandbox nicht.

Wie Tool-JSON gefüllt wird: AI-Coding-Agents und JSON-Toolaufrufe. Wie die Angriffsfläche eingesammelt wird: Agent-Sicherheitskrise und JSON-Validierung. Warum Schema eine Tür ist: Warum AI JSON Schema braucht. Dieser Text wiederholt die drei nicht. Er landet nur Shell, Git und Dateien als Objekte.

Das Rechteobjekt: allow, ask, deny

Claude Code schreibt Regeln unter permissions in settings.json. Der Host bewertet sie, nicht das Modell. CLAUDE.md ändert, was versucht wird. Nicht, was erlaubt ist. Fiktives Repo — keine echten Geheimnisse:

{
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(npm test *)",
      "Read(./src/**)",
      "Edit(./src/**)"
    ],
    "ask": [
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)",
      "Read(./.env)",
      "Edit(./.git/hooks/**)",
      "Edit(./.git/config)"
    ]
  }
}

Ein nackter Toolname wie Bash im deny nimmt das Tool aus dem Kontext. Eine Regel mit Klammern blockiert passende Aufrufe und lässt das Tool stehen. Verbundbefehle matchen pro Teilbefehl: git status erlauben heißt nicht, einen zweiten Befehl danach erlauben. Codex nutzt Profile (:workspace / :read-only) und mischt sie nicht mit dem älteren sandbox_mode. Cursor nutzt eine Präfixliste in permissions.json plus sandbox.json.

Erste Tür: Shell

Das Modell reicht eine Befehlszeichenkette. Der Host matcht die Policy, bevor etwas läuft. Eine Nur-Lese-Abfrage geht meist durch:

{
  "type": "tool_use",
  "id": "call_7f2a",
  "name": "Bash",
  "input": {
    "command": "git status"
  }
}

In derselben Policy ist ein Remote-Push deny. Das Objekt ist wohlgeformt. Die Ausführung bleibt beim Host. Cursors Terminal-Liste matcht Präfixe: git deckt git status. Die offizielle Doku nennt Run Modes bestmögliche Leitplanken, keine harte Grenze. Für eine harte Grenze die Sandbox einschalten.

{
  "type": "tool_use",
  "id": "call_8a01",
  "name": "Bash",
  "input": {
    "command": "git push origin main"
  }
}

Zweite Tür: Git ist kein gewöhnliches Schreiben

Ein beschreibbarer Workspace ist kein beschreibbares .git. Codex hält unter beschreibbaren Wurzeln .git, .agents und .codex standardmäßig nur lesbar; ist .git ein gitdir:-Zeiger, ist auch das aufgelöste Verzeichnis geschützt. Claude Codes Sandbox lässt ein Worktree genug ins geteilte .git schreiben, um zu committen, und lehnt hooks/ und config weiter ab. Cursor schützt ebenso .git/hooks und .git/config. Ein blockierter Push soll ein Objekt hinterlassen:

{
  "tool": "Bash",
  "command": "git push origin main",
  "eval_order": ["deny", "ask", "allow"],
  "matched": "Bash(git push *)",
  "rule": "deny",
  "sandbox": "workspace-write",
  "execute": false
}

Bei Fehler ein tool_result zurückschreiben, das die Trefferregel nennt. Das Remote nicht still anfassen. Commit auf ask: ein Mensch sieht den Diff. Push auf deny, außer diese Sitzung ist ausdrücklich eine Veröffentlichung.

{
  "type": "tool_result",
  "tool_use_id": "call_8a01",
  "is_error": true,
  "content": "denied by policy: Bash(git push *)"
}

Dritte Tür: das Dateisystem braucht zwei Schichten

Eine Schicht sind Tool-Regeln. Die andere ist die OS-Sandbox. Die offizielle Doku trennt sie, weil sie andere Aufrufe stoppen:

  • Tool-Regeln: Claudes Read-/Edit-deny gilt für eingebaute Datei-Tools und erkannte Befehle wie cat / head. Ein Sprachskript, das Dateien selbst öffnet, liegt außerhalb.
  • OS-Sandbox: eine Prozessgrenze. Standard-Schreibzugriff bleibt im Arbeitsverzeichnis und im Sitzungs-Temp. Extra-Pfade sind explizit. Netz ist standardmäßig aus.
  • Geheimdateien: .env ins deny. Nicht auf einen Prompt „keine Geheimnisse lesen“ verlassen.

MCP-Tools sind eine weitere Tabelle. Jedes Tool braucht seine Tür. Protokollgrenze: MCP Tool Schema vs. Function Calling. Dieser Text schreibt nicht, wie Coding-Agents MCP rufen. Er verlangt nur, dass ein verbundenes Tool einen Namen im Rechteobjekt hat.

Fünf Schritte zu einer ausführbaren Policy

Nicht bei „bitte vorsichtig ausführen“ starten. Die Türen schreiben:

  1. Zuerst deny schreiben. Push, hooks, config, .env und Pfade außerhalb einmal festziehen.
  2. Nur-Lese-Befehle auf allow. status, diff, test. Ein Regel pro Teilbefehl bei Verbunden.
  3. Schreiben und Commits auf ask. Ein Mensch sieht Pfad und Diff. Eine Edit-Freigabe stirbt mit der Sitzung.
  4. OS-Sandbox einschalten. Codex: :workspace, nicht beiläufig :danger-full-access. Cursor: Run Everything nicht als Standard. Claudes bypassPermissions bleibt im isolierten Container.
  5. Die Policy als JSON prüfen. allow neben deny legen. Geteilte Regeln ins Versionsarchiv. Lokale Lockerung bleibt lokal.

Wie Schema zur Tür wird: Agents API + JSON Schema. Dieser Text verlangt nur, dass jede Tür eines Coding-Agents ein Objekt ist, das der Host bewertet.

Eine Rechteabweichung prüfen: zwei JSON-Spuren ausbreiten

Eine überschrittene Tür ist meist eine schiefe Regel, kein wilderes Modell.

  • Policy und jenen tool_use formatieren. Sehen, ob deny traf oder allow leckte.
  • Mit JSONPath extrahieren $.permissions.deny und $.input.command ziehen.
  • Einen Durchlass und eine Ablehnung JSON Diff. Zuerst die Regel, dann den Prompt.
  • Git-Metaregeln und src-Schreibregeln getrennt prüfen. A-1042.json ändern ist nicht hooks ändern.
  • Keine Policy-Dateien, Repo-Pfade oder Sitzungslogs in einen öffentlichen Formatter. JSONSort läuft lokal im Browser.

Lassen sich beide Spuren gegen die Regeln neu aufbauen, haben Sie ein Rechtemodell gesammelt. Sonst nur „ich habe Allow geklickt“.

Häufige Fallen

  • Schema für Rechte halten. Schema sperrt die Form. Ein wohlgeformtes git push braucht trotzdem deny.
  • Nur allow schreiben. Offiziell kommt deny zuerst. Ohne deny beschleunigt die Liste nur Freigaben.
  • Workspace-Schreiben für Git-Schreiben halten. hooks und config sind eine andere Tür. Offizielle Defaults schützen sie.
  • Tool-deny ohne Sandbox. Ein Skript, das Dateien selbst öffnet, liegt außerhalb der Tool-Regeln. Es braucht eine Prozessgrenze.
  • bypass / full-access / Run Everything auf dem Laptop. Offiziell für isolierte Umgebungen. Alltag: workspace + ask.
  • Codex alt und neu mischen. Steht sandbox_mode, greifen Profile nicht. Eine Variante wählen.

FAQ

Heißt „erlauben und nicht mehr fragen“ dauerhafte Freigabe?

Nicht immer. Bei Claude Code landet eine dauerhafte Bash-Freigabe in settings.local.json an der Repo-Wurzel; eine Edit-Freigabe stirbt mit der Sitzung. Cursors Liste liegt in permissions.json. Das geschriebene Objekt lesen, nicht das Button-Label.

Brauche ich deny, wenn die Sandbox an ist?

Ja. Die Sandbox hält den Prozess im Workspace. deny hält Befehle, die darin nicht laufen dürfen, etwa push. Die Schichten schließen andere Türen.

Warum ist Git eine eigene Tür?

Repo-Metadaten sind keine gewöhnliche Datei. src ändern ist nicht hooks und config ändern. push ist Ausgang, kein Schreibzugriff. Offizielle Produkte heben das aus „Workspace beschreibbar“ heraus.

Reicht Nur-Lesen?

Zum Lesen von Code. Nicht zum Ändern von A-1042. Codex :read-only, Claude plan und Cursors Nur-Lese-Sandbox sind Erkunden-Profile, keine Veröffentlichungs-Profile.

Darf die Policy in Git?

Ja, und sie sollte. Geteiltes deny / allow gehört ins Versionsarchiv. Lokale Lockerung bleibt lokal und wird nicht commitet. Managed Settings schalten bypass und auto aus.

Schluss

Coding-Agents brauchen Rechtekontrolle, weil das Modell nur JSON füllt. Shell, Git und Dateisystem sind drei Türen. Nach dem Schema bewertet der Host noch einmal.

Schreiben Sie, welches deny git push träfe. Können Sie auf einen Pfad zeigen, ist die Policy prüfbar. Modelle wechseln. Die Türen sollten zuerst stehen.

Weiterlesen

Änderungsprotokoll: Erstveröffentlichung