Zum Inhalt springen
OmniRoute source

Socket.dev / supply-chain finding attestation (Deutsch)

§1 — Installation einer MITM-Root-CA (77484.js)

Abschnitt betitelt „§1 — Installation einer MITM-Root-CA (77484.js)“

Quelldateien:

  • src/mitm/cert/install.ts — öffentliche Funktionen installCert() / uninstallCert() sowie plattformspezifische Funktionen installCertWindows/Mac/Linux.
  • src/mitm/systemCommands.ts — gemeinsam genutzte execFile- / spawn- / PowerShell-Hilfsfunktionen, die von den Installationspfaden verwendet werden.

Auslöser: Der Benutzer klickt im lokalen Dashboard unter /dashboard/cli-tools/mitm auf „MITM-Proxy aktivieren“. Die Route ist ausschließlich über Loopback erreichbar — siehe feste Regel Nr. 17 in CLAUDE.md und src/server/authz/routeGuard.ts::isLocalOnlyPath(). Ein über einen Tunnel offengelegtes JWT kann diesen Codepfad nicht auslösen.

Ausgeführte privilegierte Operationen (je Plattform):

Betriebssystem Befehl(e)
Windows certutil -addstore Root <cert> über UAC
macOS sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <cert>
Linux sudo cp <cert> <distro-trust-dir> + sudo update-ca-certificates (Debian) / sudo update-ca-trust (RHEL/SUSE)
Linux+Firefox/Chromium Aktualisierung der NSS-Datenbank pro Profil über certutil -d sql:<profile>

Dies sind dieselben Befehle, die von mitmproxy, Charles Proxy, Fiddler und Caddy verwendet werden. Dass sie in OmniRoute vorhanden sind, ist unter docs/security/STEALTH_GUIDE.md dokumentiert.

Abhilfemaßnahme in v3.8.6:

  • runElevatedPowerShell() verwendet nicht länger -EncodedCommand <base64utf16le>. Die Nutzlast mit erhöhten Rechten wird in eine temporäre .ps1-Datei pro Aufruf geschrieben (Modus 0o600, innerhalb eines privaten mkdtempSync-Verzeichnisses) und über -File referenziert. Die Datei wird in finally gelöscht. Dadurch wird der typische, vom KI-Klassifikator von Socket.dev markierte Fingerabdruck einer Base64-kodierten Rechteerhöhung über PowerShell entfernt.
  • installCertWindows enthält einen Inline-Block SECURITY-AUDITOR-NOTE:, der auf dieses Dokument verweist.

Warum wir diese Funktion beibehalten: Der MITM-Proxy ist eine dokumentierte Funktion, die von docs/security/STEALTH_GUIDE.md und docs/frameworks/MITM-PROXY.md verwendet wird. Seine Entfernung würde den Funktionsumfang der Agent-Bridge beeinträchtigen.


§2 — Import von Zed-Anmeldedaten (app/api/providers/zed/import/route.js)

Abschnitt betitelt „§2 — Import von Zed-Anmeldedaten (app/api/providers/zed/import/route.js)“

Quelldateien:

  • src/app/api/providers/zed/discover/route.ts (neu in v3.8.6)
  • src/app/api/providers/zed/import/route.ts
  • src/lib/zed-oauth/keychain-reader.ts
  • src/lib/zed-oauth/credentialFingerprint.ts (neu in v3.8.6)

Auslöser: Der Benutzer klickt auf der Seite „Providers“ des lokalen Dashboards auf „Import from Zed“. Der Endpunkt ist durch requireManagementAuth geschützt. Der Zed-Editor selbst schreibt seine Provider-API-Schlüssel unter dokumentierten Dienstnamen in den Schlüsselbund des Betriebssystems — siehe https://zed.dev/docs/ai/llm-providers.

Verhalten in v3.8.5 (das von Socket.dev beanstandete Verhalten):

POST /import ermittelte die Anmeldedaten und speicherte sie automatisch in einem einzigen Roundtrip im lokalen SQLite-Speicher. Keine Bestätigung pro Konto, kein Fingerabdruck, lediglich „N Token gefunden, alle importiert“.

Schutzmaßnahme in v3.8.6 — Bestätigung in 2 Schritten:

  1. POST /api/providers/zed/discover gibt { candidates: [{ provider, service, account, fingerprint }] } zurück. Das unverarbeitete Token wird niemals übertragen. Der Fingerabdruck ist sha256(service|account|token).slice(0,16).
  2. Das Dashboard zeigt die Kandidatenliste an, der Betreiber wählt die zu importierenden Einträge aus und sendet { confirmedAccounts: [{ service, account, fingerprint }] } an POST /api/providers/zed/import.
  3. Der Import-Endpunkt liest den Schlüsselbund erneut auf dem Server aus und filtert nach (service, account, fingerprint). Eine manipulierte oder erneut verwendete Discover-Antwort kann den Import-Endpunkt nicht dazu bringen, ein nicht zugehöriges Token zu speichern — wenn sich das aktive Token seit der Ermittlung geändert hat, stimmt der Fingerabdruck nicht mehr überein und die Anmeldedaten werden übersprungen.

Ein Umgebungs-Flag OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true behält das Verhalten von v3.8.5 für Betreiber bei, die ihre Automatisierung noch nicht aktualisiert haben. Es wird in v3.9 entfernt.

Warum wir dies beibehalten: Der Zed-Import ist der benutzerfreundlichste Onboarding-Pfad für Benutzer, die Zed bereits verwenden und ihre Provider-Schlüssel in OmniRoute spiegeln möchten, ohne sie erneut einzufügen.


§3 — execFile / spawn / PowerShell mit erhöhten Rechten (21843.js)

Abschnitt betitelt „§3 — execFile / spawn / PowerShell mit erhöhten Rechten (21843.js)“

Quelldateien: src/mitm/systemCommands.ts.

Grund für die Beanstandung: Der Chunk exportiert execFileWithPassword, runElevatedPowerShell und den gemeinsam verwendeten Helfer quotePowerShell erneut. Der KI-Klassifikator von Socket.dev erkennt sie als generisches „Toolkit für Host-Ausführung und Rechteerhöhung“. Innerhalb von OmniRoute werden sie ausschließlich vom MITM-Zertifikatinstallationspfad (§1) sowie von execFileWithPassword für die Ausführung von sudo-Befehlen verwendet.

Schutzmaßnahmen in v3.8.6:

  • Refaktorierung von runElevatedPowerShell (siehe §1).
  • Ein Inline-Block SECURITY-AUDITOR-NOTE: bei sowohl runElevatedPowerShell als auch execFileWithPassword dokumentiert die zugelassenen Aufrufer und die festgelegte Liste ausführbarer Dateien.
  • Der spawn()-Aufruf von execFileWithPassword enthält eine nosemgrep-Markierung mit der Positivliste ausführbarer Dateien, die der Helfer entgegennehmen darf — es gibt keinen Pfad von Benutzereingaben zu finalCommand/finalArgs.

§4 / §6 — 9router-Dienst-Supervisor (api/services/9router/{start,restart}/route.js)

Abschnitt betitelt „§4 / §6 — 9router-Dienst-Supervisor (api/services/9router/{start,restart}/route.js)“

Quelldateien:

  • src/app/api/services/9router/_lib.ts — Supervisor-Factory.
  • src/app/api/services/9router/{start,stop,restart,status,install,update,auto-start}/route.ts.
  • src/lib/services/ServiceSupervisor.ts — generisches Spawn-/Health-Poll-/Logpuffer-System.

Auslöser: Der Benutzer klickt auf der Seite für eingebettete Dienste im lokalen Dashboard auf „Install“ / „Start“.

Bereits vorhandene Schutzmaßnahmen:

  • Alle /api/services/*-Routen sind gemäß src/server/authz/routeGuard.ts LOCAL_ONLY (feste Regel Nr. 17). Die Loopback-Prüfung erfolgt vor jeder Authentifizierungsprüfung — selbst mit einem kompromittierten JWT sind diese Routen nicht erreichbar.
  • Der DB-Datensatz von 9router wird mit status='not_installed', auto_start=0 initialisiert (siehe src/lib/db/migrations/071_services.sql:19). Der Dienst wird beim ersten Start nicht ausgeführt.
  • spawn() wird mit dem Binärdateipfad aufgerufen, den resolveSpawnArgs(apiKey, PORT) in src/lib/services/installers/ninerouter.ts zurückgibt; dabei handelt es sich um eine feste Positivliste unterstützter Binärdateien.
  • Stdout/stderr wird im Arbeitsspeicher gepuffert (Obergrenze 5 MB, siehe _lib.ts) — es erfolgt keine Speicherung auf dem Datenträger, sofern der Benutzer die Protokollierung nicht im Dashboard aktiviert.

Schutzmaßnahme in v3.8.6: keine funktionale Änderung. Das minimale Build-Profil (OMNIROUTE_BUILD_PROFILE=minimal) ersetzt src/lib/services/installers/ninerouter.ts durch einen Stub für Benutzer, die die privilegierten Pfade physisch aus dem Bundle entfernen möchten.

Warum wir dies beibehalten: 9router ist ein optionaler, lokal installierbarer Begleitdienst (vergleichbar mit einem WordPress-Plugin) — eine ausdrückliche Aktivierung ist zwingend erforderlich.


§5 — Zurückschreiben von OmniRoute-Cloud-Sync-Anmeldedaten (api/keys/[id]/route.js)

Abschnitt betitelt „§5 — Zurückschreiben von OmniRoute-Cloud-Sync-Anmeldedaten (api/keys/[id]/route.js)“

Quelldateien:

  • src/lib/cloudSync.ts — syncToCloud() / updateLocalTokens().
  • src/app/api/keys/[id]/route.ts — ruft syncKeysToCloudIfEnabled() auf.

Auslöser: isCloudEnabled() gibt true zurück (über das Dashboard festgelegt) und CLOUD_URL ist konfiguriert. Wenn beide deaktiviert sind, erfolgt kein ausgehender Netzwerkaufruf an den Cloud-Endpunkt.

Verhalten in v3.8.5 (der Fehler, den Socket.dev korrekt erkannt hat):

updateLocalTokens() überschrieb accessToken, refreshToken und providerSpecificData aus der Cloud-Antwort, wenn cloudUpdatedAt > localUpdatedAt war. Kein HMAC, keine Signatur, keine Prüfsumme. Eine falsch konfigurierte oder bösartige CLOUD_URL (oder ein MITM im Kommunikationskanal) konnte OAuth-Token des Providers unbemerkt austauschen.

Gegenmaßnahmen in v3.8.6:

  1. HMAC-Verifizierung: verifyCloudSignature(rawBody, sigHeader) prüft den Header X-Cloud-Sig (HMAC-SHA256(OMNIROUTE_CLOUD_SYNC_SECRET, rawBody)), bevor das JSON geparst wird. Wenn das Secret gesetzt ist, ist die Signatur erforderlich. Andernfalls (Legacy-Modus) wird eine Warnung protokolliert und die Antwort akzeptiert — ab v3.9 ist das Secret erforderlich.
  2. Explizite Aktivierung geheimer Felder: accessToken / refreshToken / providerSpecificData werden nur überschrieben, wenn OMNIROUTE_CLOUD_SYNC_SECRETS=true gesetzt ist. Im Standardmodus werden nur Metadaten synchronisiert, die keine Anmeldedaten enthalten (expiresAt, status, lastError*, rateLimitedUntil, updatedAt). Dies ist eine inkompatible Änderung für Benutzer, die sich auf die Remote-Synchronisierung von Token verlassen haben — sie müssen diese explizit aktivieren.

Warum wir diese Funktion beibehalten: Cloud Sync ist die einzige Möglichkeit für einen OmniRoute-Cloud-Mandanten, Team-Anmeldedaten zentral zu verwalten. Die Korrektur bildet das Bedrohungsmodell ehrlich ab: „Der Server signiert, der Client verifiziert, der Betreiber stimmt zu.“


Benutzer, die ein Socket-freundliches Artefakt benötigen, können es wie folgt erstellen:

Terminal-Fenster
OMNIROUTE_BUILD_PROFILE=minimal npm run build

Das webpack-Plugin NormalModuleReplacementPlugin ersetzt vier Module durch Stubs:

Modul Stub
src/mitm/cert/install.ts src/mitm/cert/install.stub.ts
src/lib/zed-oauth/keychain-reader.ts src/lib/zed-oauth/keychain-reader.stub.ts
src/lib/cloudSync.ts src/lib/cloudSync.stub.ts
src/lib/services/installers/ninerouter.ts src/lib/services/installers/ninerouter.stub.ts

Jeder Stub exportiert dieselbe Schnittstelle, aber jede Funktion löst zur Laufzeit einen featureDisabledError(name) aus. Routen, die vom deaktivierten Modul abhängen, geben HTTP 503 mit einer eindeutigen Meldung zurück, anstatt den sensiblen Codepfad zu aktivieren.

Das resultierende Bundle ist für die Veröffentlichung als omniroute-secure vorgesehen. Das Veröffentlichungsverfahren ist unter docs/ops/PUBLISHING_SECURE.md beschrieben.


Langfristig beabsichtigen wir, das npm-Paket in separat überprüfbare Module aufzuteilen. Das zugehörige Tracking-Issue finden Sie im v4-Meilenstein des GitHub-Issue-Trackers.


OmniRoute-Quellcode (a58000c7685f)

HagiCode

HagiCode ist ein agentischer Coding-Arbeitsplatz mit strukturierten Workflows, Multi-Agent-Ausführung und Hero-Dungeon-Ansichten.

Mit einem intelligenteren, schnelleren und unterhaltsameren agentischen Workflow wird aus Ideen nutzbare Software.

HagiCode-Hauptoberfläche im hellen Design
  • SmartStrukturierte Workflows machen aus Absichten einen umsetzbaren Weg von der Idee bis zur Auslieferung.
  • EfficientMulti-Agent-Workflows führen Recherche, Umsetzung und Prüfung parallel aus.
  • FunHero Dungeon macht lange Coding-Sitzungen anschaulich und gemeinschaftlich.
HagiCode besuchen