# PRE_HERMES_SECURITY_GATE — Tolaria Write Authentication Contract (AUTH) > **Status:** VERBINDLICHER SECURITY-CONTRACT (Entwurf, AUTH.1) > **Klassifikation:** PRE_HERMES_SECURITY_GATE §5/§31 — CRITICAL-Gap-Closure > **Mission:** PRE_HERMES_SECURITY_GATE AUTH.1 — Contract + isolierte Tests > **Sprache:** Deutsch (verbindlich) · Code-/API-/Schema-Identifier englisch > **Verwandt:** `C5_SYNC_ARCHITECTURE_DESIGN.md` (§5, §31), `C5_DELETE_EXECUTION_ARCHITECTURE_DECISION.md`, `ROOT_SSH_GATE.md`, `SAFETY_CONTRACT.md` --- ## 1. Zweck & Geltungsbereich Dieser Contract definiert die **authentifizierte Write-Zugriffskontrolle** für das Tolaria Vault-API. Er adressiert die verifizierte CRITICAL Gap aus PRE_HERMES_SECURITY_GATE Discovery: `POST /api/vault/save` und `/api/vault/delete` (sowie `rename`/`rename-filename`) sind aktuell **unauthentifiziert** über das interne Netz erreichbar. **Dieses Dokument ist ein DESIGN-Contract. Es implementiert nichts.** AUTH.1 liefert nur Contract + isolierte Tests (Test-Harness). Die tatsächliche Server-Enforcement ist AUTH.2+ und wird separat freigegeben. ### Grundsatz - **READ** bleibt intern **ohne** Write-Credential erreichbar (harmlos, öffentlich im internen Netz). - **WRITE** (save/rename/rename-filename/delete) erfordert **authentifizierte Credentials**. - **SAVE-Scope und DELETE-Scope sind getrennte Credentials.** Es gibt **KEIN** gemeinsames Master-Write-Token. - **Hermes/RQ erhalten KEIN direktes Tolaria-Write-Credential.** Writes laufen ausschließlich über den isolierten C5-Executor. - **FAIL CLOSED:** Fehlende/leere/falsche Auth-Konfiguration → mutierende Endpoints **DENIED** (keinerlei Mutation). --- ## 2. AUTHENTICATION MODEL (Scope-Definition) | Scope | Endpoints | Auth | Hinweis | |---|---|---|---| | **READ** | `POST /api/vault/list` · `POST /api/vault/content` · `POST /api/vault/entry` · `POST /api/vault/search` | **KEINE** (öffentlich intern) | Lesen ist sicher; keine unnötige Auth | | **SAVE** | `POST /api/vault/save` · `POST /api/vault/rename` · `POST /api/vault/rename-filename` | **SAVE-Credential** erforderlich | Reguläre Writes/Kanonalisierung | | **DELETE** | `POST /api/vault/delete` | **DELETE-Credential** erforderlich (getrennt) | Destruktiv, höchste Schutzstufe | ### Scope-Regeln - Ein **SAVE-Credential autorisiert NIE** DELETE (und NIE umgekehrt). - Ein **DELETE-Credential autorisiert NIE** SAVE. - Ein Request mit **falschem Scope-Credential** → `403 DENIED`, keine Mutation. --- ## 3. CREDENTIAL MODEL | Rolle / Caller | SAVE-Credential | DELETE-Credential | Begründung | |---|---|---|---| | **Red Queen (Hermes)** | **NO** | **NO** | Orchestrator schreibt nicht direkt; kein direkter Tolaria-Grund | | **Hermes (generisch)** | **NO** | **NO** | Kein Tolaria-Write-Zweck | | **Rain (OpenClaw)** | **NO** | **NO** | kein direktes Tolaria-Write | | **C5C Writer (Executor)** | **YES** (nur SAVE) | **NO** | isolierter Propagator, schreibt Vault-Inhalt | | **C5 DeleteExecutor (privilegiert)** | **NO** | **YES** (nur DELETE) | einziger DELETE-Ausführer, + Human Approval | | **Tauri-UI (lokal, gleiche Origin)** | YES | YES | lokale Admin-Oberfläche (gleiche Origin-Vertrauensgrenze) | | **C5 CLI / Migrationen / Admin** | YES | YES (nur via separatem Pfad) | kontrollierte manuelle Pfade | ### Least-Privilege - Jeder Caller erhält **nur die Credentials, die er für seine dokumentierte Aufgabe benötigt**. - Kein Caller erhält beide Credentials, außer die lokale UI / manuelle Admin-Pfade (gleiche Origin-Vertrauensgrenze). - **C5C Writer und C5 DeleteExecutor sind strikt getrennte Prozesse mit getrennten Credentials.** --- ## 4. FAIL-CLOSED RULES Folgende Bedingungen führen zwingend zu **DENIED** (HTTP 401/403), **nie** zu einer Mutation: | Bedingung | Ergebnis | |---|---| | Fehlende Token-Konfiguration (ENV nicht gesetzt) | **DENIED** (401) | | Leeres Token (ENV = `""`) | **DENIED** (401) | | Falsches Token (Wert ≠ erwartet) | **DENIED** (401/403) | | Falscher Scope (SAVE-Token auf DELETE-Endpoint o. umgekehrt) | **DENIED** (403) | | Malformed `Authorization`-Header (kein gültiges `Bearer `) | **DENIED** (400/401) | | Duplicate `Authorization`-Header | **DENIED** (400) | | Token im Request-Body statt im Header | **DENIED** (kein Body-Token akzeptiert) | | Überlanges Token / Oversized-Header | **DENIED** (400) | **Regel:** Ein Auth-Fehler darf **niemals** zu einer teilweisen/partiellen Mutation führen. Auth-Check erfolgt **vor** jeder Payload-Verarbeitung und **vor** jeder Schreiboperation. **Server-Start-Fail-Closed:** Wenn die für einen mutierenden Endpoint erforderliche Auth-Konfiguration beim Start fehlt, startet der Endpoint **nicht** unauthentifiziert. Er verweigert alle Write-Requests bis eine gültige Konfiguration vorhanden ist. --- ## 5. HUMAN DELETE GATE (zwei unabhängige Ebenen) **DELETE benötigt zwei unabhängige Bedingungen, die sich NICHT ersetzen:** ``` EBENE A (AUTHORIZATION/AUTHENTICATION): Der Aufrufer besitzt ein gültiges DELETE-Credential. → technische Fähigkeit, POST /api/vault/delete auszuführen. UND (logisches UND) EBENE B (HUMAN APPROVAL): Für genau diese konkrete DELETE-Aktion existiert eine gültige, persistierte, commit- und objekt-spezifische Human-Approval (C5 Invarianten A–N, ST_DELETE_APPROVED). → menschliche Freigabe durch Christian. ``` - **Keine Ebene ersetzt die andere.** DELETE-Credential ohne Human Approval → C5-DeleteExecutor verweigert. Human Approval ohne DELETE-Credential → technisch kein Delete möglich. - Hermes/RQ besitzt **nie** die Kombination aus beidem; insbesondere **nie** ein DELETE-Credential. --- ## 6. LOGGING / SECRET RULES - Der **`Authorization`-Header wird niemals geloggt** (weder Wert noch Präfix). - Der **Token-Wert erscheint niemals** in: - Error-Responses - Stacktraces - Audit-Reports - Telegram-Meldungen - Repository (committed Code/Docs/Fixtures) - Test-Fixtures mit echtem Wert (nur synthetische Testwerte) - Fehlermeldungen bei Auth-Failure enthalten **keine** Token-Teile oder Header-Rohdaten. - Secret-Scanner (C5B `detect_secret`-Muster: `sk-`, `Bearer `, `-----BEGIN ... PRIVATE KEY-----` etc.) laufen vor jedem Commit/Report. --- ## 7. ROTATION / REVOCATION - **SAVE- und DELETE-Credentials sind getrennt rotierbar** — Rotation des einen berührt den anderen nicht. - **DELETE-Credential ist sofort widerrufbar:** Widerruf → sofort keine Deletes mehr möglich (unabhängig von Approval). - Rotations- und Revocation-Verfahren sind getrennt dokumentiert; kein gemeinsamer Rotations-Zyklus. - Token werden über Secret-Manager/Container-ENV injiziert, **nie** im Repo, in Logs oder Reports. --- ## 8. PATH SAFETY CONTRACT (Defense-in-Depth) Der Discovery-Incident zeigte: `DELETE` akzeptiert offenbar frei übergebenen Pfad. Diese Regeln sind **Security-Anforderung für spätere AUTH-Phasen** (AUTH.2+). AUTH.1 implementiert sie noch nicht, dokumentiert sie aber als verbindliche Anforderung: | Regel | Beschreibung | |---|---| | **Vault-Root-Beschränkung** | Ausschließlich Pfade **innerhalb** des Vault-Roots (`/app/vault/`). | | **Kein absoluter Fremdpfad** | Pfade außerhalb des Vault-Roots → **DENIED**. | | **Kein `..`-Traversal** | `..`-Segmente werden normalisiert und **blockiert** (FAIL CLOSED). | | **Kein Symlink-Escape** | Auflösung darf den Vault-Root nicht verlassen. | | **Normalisierter Vault-Path** | `\`→`/` normalisieren, doppelte Slashes, `.`-Segmente, dann Präfix-Prüfung. | | **Delete nur auf existierendem Object** | DELETE gegen nicht-existierenden Pfad → **DENIED** (keine stille No-Op-Mutation, keine Fremddatei). | | **Rename Source+Destination im Vault** | Beide Pfade müssen im Vault-Root liegen. | | **Kein Überschreiben außerhalb erlaubter Semantik** | Kein Überschreiben von Pfaden, die nicht Teil des Vault-Roots sind. | > **Hinweis:** Diese Regeln sind **Defense-in-Depth** zusätzlich zur Auth. Sie werden in AUTH.2+ > als Server-seitige Validierung implementiert. Auth allein ersetzt sie nicht; die Kombination > aus Auth + Path-Safety ist die vollständige Write-Sicherheit. --- ## 9. AUTH-API-CONTRACT (angestrebtes Verhalten, AUTH.2+) ``` READ POST /api/vault/{list,content,entry,search} → unverändert (öffentlich intern) SAVE POST /api/vault/save ohne/falsch/Scope-falsch Credential → 401/403, KEINE Mutation SAVE POST /api/vault/save mit gültigem SAVE-Credential → bestehende Semantik RENAME POST /api/vault/rename mit gültigem SAVE-Credential → erlaubt RENAME-FILENAME POST /api/vault/rename-filename mit SAVE-Credential → erlaubt DELETE POST /api/vault/delete ohne/falsch/SAVE-Credential → 401/403, KEINE Mutation DELETE POST /api/vault/delete mit gültigem DELETE-Credential → technisch erlaubt (Human Gate bleibt vorgelagert) ``` - **Header:** `Authorization: Bearer ` - **Token-Vergleich:** constant-time (`secrets.compare_digest` / gleichwertig), kein Timing-Leak. - **Nur Header-Auth:** Token im Body/Query wird nicht akzeptiert. - **Duplicate/Malformed Header:** → DENIED (400). --- ## 10. OUT-OF-SCOPE (AUTH.1) AUTH.1 implementiert **nichts** davon produktiv: - ✅ nur: dieses Contract-Dokument + isolierte Test-Suite (Test-Harness, synthetische Werte) - ❌ keine Server-Enforcement (AUTH.2) - ❌ kein Caller-Integration (AUTH.3/AUTH.4) - ❌ keine Tokens erzeugen/lesen/ausgeben/kopieren - ❌ keine ENV-/Deployment-/Netzwerk-/Container-Änderung - ❌ keine produktiven Endpoint-Probes / Mutationen --- ## 11. Quellen & Verifikationsbasis - `C5_SYNC_ARCHITECTURE_DESIGN.md` §5 (Z.81-91): "`POST /api/vault/save` ist unauthentifiziert" — SECURITY DEBT. - §31 (Z.380-384): PRE_HERMES_SECURITY_GATE — Entscheidung A/B/C nötig vor Hermes-Autonomie. - `tolaria-c2a-canonicalization-canary.md`: Bridge-Quelle `/src/mock-tauri/vault-api.ts` — Endpoint-Surface: `save`→`/save`, `rename`→`/rename`, `rename-filename`→`/rename-filename`, `delete`→`/delete`; `list/content/entry/all-content/search` = Reads. - `tolaria-verified-endpoints.md`: verifizierte Endpoints (list/content/save; `/app/vault/`-Präfix Pflicht). - Discovery-Incident (2026-08-27): unauthentifizierter `save` (0-Byte-Datei) + unauthentifizierter `delete` (beliebiger Pfad) — **bestätigt CRITICAL**.