Socket.dev / supply-chain finding attestation (Français)
§1 — Installation de l’autorité de certification racine pour l’interception MITM (77484.js)
Section intitulée « §1 — Installation de l’autorité de certification racine pour l’interception MITM (77484.js) »Fichiers sources :
src/mitm/cert/install.ts— fonctions publiquesinstallCert()/uninstallCert(), et fonctions propres à chaque plateformeinstallCertWindows/Mac/Linux.src/mitm/systemCommands.ts— utilitaires partagésexecFile/spawn/ PowerShell utilisés par les chemins d’installation.
Déclencheur : l’utilisateur clique sur « Activer le proxy MITM » dans le tableau de bord local à l’adresse
/dashboard/cli-tools/mitm. Cette route est accessible uniquement via l’interface de bouclage — voir la règle stricte no 17 dans
CLAUDE.md et src/server/authz/routeGuard.ts::isLocalOnlyPath(). Un
JWT divulgué par l’intermédiaire d’un tunnel ne peut pas déclencher ce chemin de code.
Opérations privilégiées effectuées (par plateforme) :
| SE | Commande(s) |
|---|---|
| Windows | certutil -addstore Root <cert> via 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 | mise à jour de la base de données NSS de chaque profil via certutil -d sql:<profile> |
Il s’agit des mêmes commandes que celles utilisées par mitmproxy, Charles Proxy, Fiddler et
Caddy. Leur présence dans OmniRoute est documentée dans
docs/security/STEALTH_GUIDE.md.
Mesures d’atténuation de la v3.8.6 :
runElevatedPowerShell()n’utilise plus-EncodedCommand <base64utf16le>. La charge utile élevée est écrite dans un fichier temporaire.ps1propre à chaque appel (mode 0o600, à l’intérieur d’un répertoire privémkdtempSync) et référencée via-File. Le fichier est supprimé dansfinally. Cela élimine la signature classique d’élévation via PowerShell avec encodage en base64 signalée par le classificateur d’IA de Socket.dev.installCertWindowscontient un bloc intégréSECURITY-AUDITOR-NOTE:renvoyant vers le présent document.
Pourquoi nous le conservons : le proxy MITM est une fonctionnalité documentée utilisée par
docs/security/STEALTH_GUIDE.md et docs/frameworks/MITM-PROXY.md. Sa suppression
compromettrait l’ensemble des fonctionnalités de passerelle pour agents.
§2 — Importation des identifiants Zed (app/api/providers/zed/import/route.js)
Section intitulée « §2 — Importation des identifiants Zed (app/api/providers/zed/import/route.js) »Fichiers sources :
src/app/api/providers/zed/discover/route.ts(nouveau dans v3.8.6)src/app/api/providers/zed/import/route.tssrc/lib/zed-oauth/keychain-reader.tssrc/lib/zed-oauth/credentialFingerprint.ts(nouveau dans v3.8.6)
Déclencheur : l’utilisateur clique sur « Importer depuis Zed » dans la page
Fournisseurs du tableau de bord local. L’accès au point de terminaison est
contrôlé par requireManagementAuth. L’éditeur Zed lui-même enregistre les
clés API de ses fournisseurs dans le trousseau du système d’exploitation sous
des noms de services documentés — voir https://zed.dev/docs/ai/llm-providers.
Comportement de v3.8.5 (celui signalé par Socket.dev) :
POST /import détectait les identifiants et les enregistrait automatiquement
dans le stockage SQLite local en un seul aller-retour. Aucune confirmation
pour chaque compte, aucune empreinte, seulement « N jetons trouvés, tous
importés ».
Mesure d’atténuation de v3.8.6 — confirmation en 2 étapes :
POST /api/providers/zed/discoverrenvoie{ candidates: [{ provider, service, account, fingerprint }] }. Le jeton brut n’est jamais transmis. L’empreinte estsha256(service|account|token).slice(0,16).- Le tableau de bord affiche la liste des candidats, l’opérateur sélectionne
ceux à importer, puis envoie
{ confirmedAccounts: [{ service, account, fingerprint }] }àPOST /api/providers/zed/import. - Le point de terminaison d’importation relit le trousseau sur le serveur
et effectue un filtrage selon
(service, account, fingerprint). Une réponse de détection falsifiée ou rejouée ne peut pas amener le point de terminaison d’importation à enregistrer un jeton sans rapport — si le jeton actif a changé depuis la détection, l’empreinte ne correspond plus et l’identifiant est ignoré.
Une variable d’environnement OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=true
préserve le comportement de v3.8.5 pour les opérateurs qui n’ont pas encore
mis à jour leur automatisation. Elle sera supprimée dans v3.9.
Pourquoi nous le conservons : l’importation depuis Zed constitue le parcours d’intégration le plus convivial pour les utilisateurs qui emploient déjà Zed et souhaitent répliquer leurs clés de fournisseurs dans OmniRoute sans avoir à les coller de nouveau.
§3 — execFile / spawn / PowerShell avec élévation de privilèges (21843.js)
Section intitulée « §3 — execFile / spawn / PowerShell avec élévation de privilèges (21843.js) »Fichiers sources : src/mitm/systemCommands.ts.
Pourquoi cela a été signalé : le fragment réexporte
execFileWithPassword, runElevatedPowerShell et la fonction utilitaire
partagée quotePowerShell. Le classificateur d’IA de Socket.dev les considère
comme une boîte à outils générique d’« exécution sur l’hôte + élévation de
privilèges ». Dans OmniRoute, ils sont utilisés uniquement par le parcours
d’installation du certificat MITM (§1) et par execFileWithPassword pour
l’exécution de commandes sudo.
Mesure d’atténuation de v3.8.6 :
- Refactorisation de
runElevatedPowerShell(voir §1). - Un bloc
SECURITY-AUDITOR-NOTE:intégré à la fois dansrunElevatedPowerShelletexecFileWithPassworddocumente les appelants autorisés et la liste fixe des exécutables. - L’appel
spawn()deexecFileWithPasswordcomporte un marqueurnosemgrepavec la liste des exécutables que la fonction utilitaire est autorisée à recevoir — il n’existe aucun chemin entre les entrées utilisateur etfinalCommand/finalArgs.
§4 / §6 — Superviseur du service 9router (api/services/9router/{start,restart}/route.js)
Section intitulée « §4 / §6 — Superviseur du service 9router (api/services/9router/{start,restart}/route.js) »Fichiers sources :
src/app/api/services/9router/_lib.ts— fabrique du superviseur.src/app/api/services/9router/{start,stop,restart,status,install,update,auto-start}/route.ts.src/lib/services/ServiceSupervisor.ts— gestion générique du lancement, interrogation de l’état de santé et tampon de journaux.
Déclencheur : l’utilisateur clique sur « Installer » / « Démarrer » sur la page des services intégrés du tableau de bord local.
Protections déjà en place :
- Toutes les routes
/api/services/*sont LOCAL_ONLY conformément àsrc/server/authz/routeGuard.ts(règle stricte nº 17). La restriction à l’interface de bouclage intervient avant toute vérification d’authentification — un JWT divulgué ne permet pas d’y accéder. - La ligne de 9router dans la base de données est initialisée avec
status='not_installed', auto_start=0(voirsrc/lib/db/migrations/071_services.sql:19). Le service ne démarre pas lors du premier lancement. spawn()est appelé avec le chemin du binaire renvoyé parresolveSpawnArgs(apiKey, PORT)danssrc/lib/services/installers/ninerouter.ts, qui repose sur une liste fixe de binaires pris en charge.- Les sorties standard et d’erreur sont mises en mémoire tampon (limite de
5 Mo, voir
_lib.ts) — aucune écriture sur disque n’a lieu sauf si l’utilisateur active la journalisation depuis le tableau de bord.
Mesure d’atténuation de v3.8.6 : aucune modification fonctionnelle. Le
profil de compilation minimal (OMNIROUTE_BUILD_PROFILE=minimal) remplace
src/lib/services/installers/ninerouter.ts par un module factice pour les
utilisateurs qui souhaitent que les chemins privilégiés soient physiquement
retirés du paquet.
Pourquoi nous le conservons : 9router est un service compagnon facultatif pouvant être installé localement (à la manière d’une extension WordPress) — activation strictement volontaire.
§5 — Réécriture des identifiants OmniRoute Cloud Sync (api/keys/[id]/route.js)
Section intitulée « §5 — Réécriture des identifiants OmniRoute Cloud Sync (api/keys/[id]/route.js) »Fichiers sources :
src/lib/cloudSync.ts—syncToCloud()/updateLocalTokens().src/app/api/keys/[id]/route.ts— appellesyncKeysToCloudIfEnabled().
Déclencheur : isCloudEnabled() renvoie true (configuré depuis le tableau de bord) et
CLOUD_URL est configurée. Lorsque les deux sont désactivés, aucun appel réseau sortant
vers le point de terminaison Cloud n’est effectué.
Comportement de la v3.8.5 (le bug correctement détecté par Socket.dev) :
updateLocalTokens() remplaçait accessToken, refreshToken et
providerSpecificData à partir de la réponse Cloud lorsque
cloudUpdatedAt > localUpdatedAt. Aucun HMAC, aucune signature, aucune somme de contrôle. Une
CLOUD_URL mal configurée ou hostile (ou une attaque MITM sur le canal) pouvait remplacer
silencieusement les jetons OAuth des fournisseurs.
Mesures correctives de la v3.8.6 :
- Vérification HMAC :
verifyCloudSignature(rawBody, sigHeader)vérifie l’en-têteX-Cloud-Sig(HMAC-SHA256(OMNIROUTE_CLOUD_SYNC_SECRET, rawBody)) avant d’analyser le JSON. Si le secret est défini, la signature est obligatoire. Dans le cas contraire (mode hérité), un avertissement est journalisé et la réponse est acceptée — le secret deviendra obligatoire dans la v3.9. - Activation explicite des champs secrets :
accessToken/refreshToken/providerSpecificDatasont remplacés uniquement lorsqueOMNIROUTE_CLOUD_SYNC_SECRETS=true. Le mode par défaut synchronise uniquement les métadonnées qui ne sont pas des identifiants (expiresAt,status,lastError*,rateLimitedUntil,updatedAt). Il s’agit d’un changement incompatible pour les utilisateurs qui dépendaient de la synchronisation distante des jetons — ils doivent l’activer explicitement.
Pourquoi nous le conservons : Cloud Sync est le seul moyen permettant à un locataire OmniRoute Cloud de centraliser les identifiants de l’équipe. Le correctif rend le modèle de menace explicite : « le serveur signe, le client vérifie, l’opérateur choisit de l’activer ».
Profil de build : minimal
Section intitulée « Profil de build : minimal »Pour les utilisateurs qui ont besoin d’un artefact compatible avec Socket, effectuez le build avec :
OMNIROUTE_BUILD_PROFILE=minimal npm run buildLe NormalModuleReplacementPlugin de webpack redirige quatre modules vers des stubs :
| Module | 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 |
Chaque stub exporte la même interface, mais toutes les fonctions lèvent une
featureDisabledError(name) lors de l’exécution. Les routes qui dépendent du module désactivé
renvoient une réponse HTTP 503 accompagnée d’un message clair au lieu d’activer le
chemin de code sensible.
Le bundle obtenu est destiné à être publié sous le nom omniroute-secure. Consultez
docs/ops/PUBLISHING_SECURE.md pour connaître la procédure de publication.
Séparation du plugin (prévue pour la v4)
Section intitulée « Séparation du plugin (prévue pour la v4) »À long terme, nous prévoyons de scinder le package npm en modules pouvant être audités séparément. Consultez le jalon v4 dans le système de suivi des issues GitHub pour accéder à l’issue de suivi.
HagiCode
HagiCode est un espace de développement agentique qui associe workflows structurés, exécution multi-agent et vues Hero Dungeon.
Transformez vos idées en logiciels utiles grâce à un workflow agentique plus intelligent, rapide et agréable.

- SmartDes workflows structurés transforment une intention en parcours exécutable, de l’idée à la livraison.
- EfficientLes workflows multi-agents font avancer recherche, réalisation et revue en parallèle.
- FunHero Dungeon rend les longues sessions de code plus visuelles et collaboratives.