# Nexus – Security Spot Check

> **Historische Evidenz:** Diese Datei hält den Stand vom 2026-07-26 fest. Der
> v0.2.60-Stabilitätsslice entfernte die ungenutzte CSRF-Tokenroute, ergänzte
> Browser-Origin-Prüfungen für Refresh/Logout und ersetzte den einfachen CI-Grep
> durch checksum-gepinntes Full-History-Gitleaks. Aktuelle Abnahmegrenzen stehen
> in `docs/audits/2026-07-31/stability-v0.2.60/IMPLEMENTATION_AND_ACCEPTANCE.md`.

**Datum:** 2026-07-26
**Commit:** `3bc7622977f4a6c2f2e98ab4aa856a2e45c3cf49`
**Vertraulichkeit:** Intern
**Scope:** Statische, risikoorientierte Prüfung von Authentifizierung,
Autorisierung, Bridge-Identität, Proxyweiterleitung und Credential-Lifecycle.

> Dies ist kein vollständiger Security Scan und kein Penetrationstest. Die
> Befunde sind codebasiert und müssen nach der Korrektur in einer realistischen
> Proxy-/Containerumgebung negativ getestet werden.

## Executive Summary

Zwei Zugriffskontrollbefunde blockieren eine verantwortbare
Produktionsfreigabe:

- Die API verlangt nicht global Authentifizierung. Mehrere Controller sind
  dadurch standardmäßig öffentlich, darunter ein mutierender Agent-Endpunkt.
- Die Agent-Bridge akzeptiert eine bekannte, vom Client gesetzte
  `X-Agent-Id` als ausreichenden Identitätsnachweis, während Nginx diesen Header
  öffentlich weiterleitet.

Beide Probleme sind strukturell. Einzelne zusätzliche `[Authorize]`-Attribute
reichen nicht als dauerhafte Lösung; die sichere Voreinstellung muss
„authenticated by default“ lauten.

## SEC-001 – Fehlende globale Authorization Policy

**Schweregrad:** P0 / kritisch
**Konfidenz:** Hoch
**Betroffene Grenze:** Öffentliches `/api/v1` -> Controller

### Evidenz

- `backend/Extensions/ServiceCollectionExtensions.cs` registriert
  `services.AddAuthorization()` ohne Fallback Policy.
- `backend/Program.cs` mappt sämtliche Controller.
- Mehrere Controller besitzen weder ein klassenweites `[Authorize]` noch
  vollständige methodenspezifische Attribute.
- `backend/Controllers/AgentsController.cs` stellt
  `POST /api/v1/agents/{id}/command` nur unter Rate Limiting bereit; die Methode
  ruft den Agent Runtime Chat auf und schreibt einen Activity-Eintrag.
- `frontend/nginx.conf` leitet `/api/` an das Backend weiter.
- `README.md` behauptet gleichzeitig, alle `/api/v1`-Operationsrouten
  benötigten ein Access Token. Implementierung und dokumentierter Vertrag
  widersprechen sich.

### Auswirkung

Nicht authentifizierte Aufrufer können abhängig vom jeweiligen Controller
Betriebsdaten lesen. Im schwerwiegendsten verifizierten Fall kann ein Aufrufer
einem Agenten einen Command übermitteln und damit Laufzeit- und
Ressourcennutzung auslösen.

### Korrektur

1. Eine globale Fallback Policy einführen, die einen authentifizierten Principal
   verlangt.
2. Ausschließlich wirklich öffentliche Endpunkte explizit mit
   `[AllowAnonymous]` markieren, zum Beispiel Health und die notwendigen
   Login-/Refresh-Routen.
3. Für mutierende oder sensitive Endpunkte zusätzlich Rollen-/Policy-Prüfungen
   definieren.
4. Eine Controller-Inventur durchführen und jeden Endpunkt als public, owner,
   admin, agent-service oder internal klassifizieren.
5. Negative Integrationstests hinzufügen: ohne Token muss jeder nicht
   freigegebene Endpunkt `401` oder `403` liefern.

## SEC-002 – Caller-controlled `X-Agent-Id` gilt als Authentifizierung

**Schweregrad:** P0 / kritisch
**Konfidenz:** Hoch
**Betroffene Grenze:** Öffentliches `/api/bridge` -> Agent-Service-Identität

### Evidenz

- `GatewayBridgeController.TryResolveAgentAsync` akzeptiert eine
  `X-Agent-Id`, sobald sie in der bekannten Actor-ID-Menge enthalten ist.
- Ein API-Key oder ein kryptografisch authentifizierter Service Principal ist
  in diesem Pfad nicht erforderlich.
- `frontend/nginx.conf` übernimmt `X-Agent-Id` direkt aus dem eingehenden
  Client-Header und leitet `/api/bridge/` weiter.
- Die Bridge bietet lesende und mutierende Task-/Activity-/Handoff-Commands.
- Bestehende Tests behandeln eine bekannte `X-Agent-Id` bewusst als
  erfolgreichen Authentifizierungsfall.

### Auswirkung

Wer eine gültige Agent-ID kennt oder errät, kann sich gegenüber der Bridge als
dieser Agent ausgeben. Das gefährdet Task-Board-Integrität, Delegationen,
Activity-Audit-Trails und die Verlässlichkeit der Agentenidentität.

### Korrektur

1. Einen bekannten Identitätsheader niemals allein als Authentifizierung
   akzeptieren.
2. Service-Traffic über mindestens einen starken Nachweis absichern:
   rotierbarer Service-Key mit konstanter Zeitprüfung, mTLS, signiertes
   Gateway-Token oder eine private Netzwerkgrenze mit authentifizierendem
   Proxy.
3. Am äußeren Proxy eingehende `X-Agent-Id` entfernen. Der vertrauenswürdige
   Proxy darf sie erst nach erfolgreicher Authentifizierung neu setzen.
4. `X-Agent-Id` nur als Actor-Attribut innerhalb eines bereits
   authentifizierten Service-Contexts verwenden.
5. Replay-, falsche-ID-, fehlender-Key- und Proxy-Bypass-Tests ergänzen.

## SEC-003 – Temporäres Owner-Passwort im Prozess-Log

**Schweregrad:** P2 / mittel
**Konfidenz:** Hoch
**Betroffene Grenze:** Bootstrap -> Log-Aggregation / Betreiberzugriff

### Evidenz

Beim ersten Seed wird ein generiertes temporäres Owner-Passwort einmalig in
stderr ausgegeben. Obwohl das Passwort nicht in Git gespeichert wird, können
Container-, CI- oder zentrale Logs den Wert länger aufbewahren als vorgesehen.

### Korrektur

- Passwort über einen expliziten One-Time-Secret-Kanal bereitstellen oder einen
  zeitlich eng begrenzten Reset-Link verwenden.
- Wenn Logging vorerst bleibt: Zugriff, Aufbewahrung und automatische
  Redaction verbindlich konfigurieren.
- Erstanmeldung zum sofortigen Passwortwechsel zwingen und Seed-Nutzung
  auditieren.

## Positive Kontrollen

- JWT-Schlüssel müssen mindestens 32 Byte lang sein.
- Issuer, Audience, Signatur und Laufzeit werden geprüft; Clock Skew ist klein.
- Refresh Tokens werden rotiert und gehasht persistiert.
- Sichere Cookie- und CSRF-Bausteine sind vorhanden.
- Auth- und Agent-Routen besitzen Rate-Limiting-Policies.
- Nginx setzt CSP, Frame-, MIME-, Referrer- und Permissions-Header.
- CI enthält eine einfache Suche nach versehentlich eingecheckten Secrets.

## Freigabekriterien

Eine Security-Freigabe ist erst möglich, wenn:

- beide P0-Pfade korrigiert sind,
- eine vollständige Endpoint-Policy-Matrix dokumentiert ist,
- negative Auth- und Bridge-Integrationstests in .NET 10 grün sind,
- der Test über dieselbe Nginx-/Traefik-Grenze wie Produktion erfolgt,
- unbekannte, bekannte-aber-nicht-authentifizierte und manipulierte
  Agent-Identitäten zuverlässig abgewiesen werden.
