Files
nexus/docs/SECURITY_SPOT_CHECK_2026-07-26.md
T
AzuTear cd8c78d165
CI - Build & Test / Backend (.NET) (push) Successful in 45s
CI - Build & Test / Backend integration (PostgreSQL/Toxiproxy) (push) Failing after 1m0s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m49s
CI - Build & Test / Security Check (push) Successful in 7s
CI - Build & Test / Deploy Nexus (push) Has been skipped
feat(stability): unify readiness and recovery
2026-08-01 01:21:33 +02:00

155 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.