Retour à tous les articles
Publié le · par Renaud Deraison

La commande commençait par npm install

Le 24 août 2026, l'équipe CTRL de Cato Networks a publié l'analyse d'une campagne qui achète des résultats Google sponsorisés sur « codex macos download », dépose les développeurs sur une page Google Sites déguisée en portail Codex d'OpenAI, et leur demande de coller dans le Terminal une commande dont la première ligne est un vrai npm install de Codex. Tout ce qui suit cette ligne est du base64. Bromure Agentic Coding n'envoie jamais personne chercher un agent de codage : la commande d'installation est une chaîne figée dans le catalogue d'images de Bromure, elle s'exécute dans une VM Linux jetable, les identifiants qui s'y trouvent sont des leurres, et avec le trafic sortant non apparié refusé, les trois requêtes du chargeur ne quittent jamais la machine.

Depuis deux ans, l'industrie construit des contrôles pour ce qu'un agent de codage installe. Cette campagne remonte d'un cran et empoisonne la façon dont vous installez l'agent de codage. Cette étape-là n'a ni registre, ni fichier de verrouillage, ni attestation de provenance. Elle a une barre de recherche, une page qui a l'air correcte, et vos propres mains sur le clavier.

Un développeur veut essayer le CLI Codex d'OpenAI sur son Mac, alors il tape codex macos download dans Google. Le premier résultat est sponsorisé, placé au-dessus de l'annonce d'OpenAI elle-même. Il mène à un portail de téléchargement propre, avec le bon logo et la bonne typographie, hébergé sur sites.google.com. La page dit : ouvrez le Terminal, collez ceci.

Il colle. La commande commence par npm install et le nom du paquet est correct.

Le 24 août, l'équipe de recherche CTRL de Cato Networks a publié l'analyse de cette campagne, reprise le jour même par Infosecurity Magazine, SiliconANGLE et Techzine. La charge finale est un voleur d'informations pour macOS. C'est la livraison qui vaut l'analyse.

Google hébergeait la page. Quelqu'un d'autre hébergeait le leurre.

Google Sites est un constructeur de sites. N'importe qui avec un compte obtient une page sur un domaine Google, et le certificat, le cadenas et la première moitié de l'URL appartiennent tous à Google. C'est cela, la confiance louée.

La page elle-même ne contient rien. Cato n'y a trouvé aucun code malveillant. Le leurre arrive dans une iframe pointée vers l'infrastructure de l'attaquant, routée, selon l'analyse de Cato, par un proxy de contenu statique de Google, si bien que même le second saut ressemble à Google allant chercher quelque chose. Techzine nomme deux des hôtes d'iframe : bright-links[.]com et swiftsaverfin[.]com.

Cette séparation achète deux choses aux opérateurs. La page visible ne change jamais, donc elle ne déclenche aucun système de réputation et n'est jamais réexaminée, et ils échangent les charges de l'autre côté de l'iframe quand bon leur semble. Cato a compté trois jeux d'infrastructure distincts, le troisième réutilisant un hôte d'iframe du premier.

Le reste se lit comme une opération de fraude publicitaire mature. Les leurres actifs vivent sous un chemin obscurci, /codexx/, tandis que /codex/ sert quelque chose d'inoffensif. Les opérateurs identifient les visiteurs, et tout ce qui n'est pas une cible macOS plausible voit du contenu bénin, ce qui est leur réponse aux chercheurs et aux bacs à sable. Les domaines tournent. Les URL de charge varient.

La première ligne était vraie

ClickFix ne vous sert pas un fichier. Il vous donne une instruction et vous laisse porter vous-même la charge de l'autre côté de la frontière. Comme le dit Techzine, « aucun fichier n'est téléchargé qu'une solution antivirus pourrait bloquer ».

La commande collée commence par une chaîne npm install d'apparence légitime pour Codex. C'est là tout le tour de passe-passe. Un développeur sur le point d'installer un CLI Node voit npm install, voit le nom du paquet qu'il a cherché, et son cerveau classe la ligne comme correcte. Le blob base64 qui suit est à un opérateur shell de distance, sur la même ligne, au-delà du pli de la boîte de copie. On ne lit pas la seconde moitié d'une commande dont la première moitié est la commande qu'on attendait.

Décodé, il va chercher un script distant et le passe à zsh. Trois étapes suivent.

L'étape une est un script shell rembourré de code mort et de variables inutilisées, enveloppant un blob encodé qui finit remis à eval. Le rembourrage existe pour déjouer la correspondance de motifs et pour faire abandonner l'humain qui parcourt le fichier.

L'étape deux émet une balise vers l'attaquant avec un paramètre event=pasted avant de faire quoi que ce soit d'autre. C'est un accusé de réception. Quelqu'un, à l'autre bout, mesure le taux de collage de ses pages d'atterrissage, comme un marketeur mesure des conversions.

L'étape trois télécharge le binaire dans /tmp/helper, exécute xattr -c pour retirer l'attribut de quarantaine que macOS attache à tout ce qui est arrivé du réseau, ce qui supprime l'avertissement de Gatekeeper, le marque exécutable, et le lance. Le binaire est un Mach-O universel, il tourne donc aussi bien sur Intel que sur Apple Silicon.

Cato note que les opérateurs développent encore le chargeur. Les échantillons plus anciens utilisaient du base64 avec compression ; les plus récents utilisent des conteneurs gzip chiffrés en AES dont la clé est réassemblée à partir de variables dispersées dans le script.

Pour la charge finale, Cato relie le cadre de livraison à Atomic macOS Stealer : la structure de l'URL du chargeur, la forme de la requête de télémétrie, le chemin de préparation /tmp/helper, la suppression de xattr, les URL de charge sur le thème de la mise à jour. Ils qualifient le recoupement de fort et cohérent et s'arrêtent avant de nommer le binaire, ce qui est le bon choix et mérite d'être conservé quand on le répète.

Livraison : tout ce que la victime voitcodex macos downloadrésultat sponsorisé, placéau-dessus du lien d'OpenAIsites.google.comsosie du portail Codex,aucun code malveillant propreiframe : le vrai leurrebright-links[.]comswiftsaverfin[.]com« Terminal :collez ceci »aucun fichierLa seule ligne que le développeur litnpm install ... codex ...; base64 -d ... | zshExécution : trois étapes, trois requêtes sortantes1 · chargeurscript shell rembourré decode mort et de vars inutileseval "$blob"2 · accusé de réceptionbalise de télémétrie?event=pastedla métrique de conversion3 · charge utile/tmp/helperxattr -c ; chmod +xMach-O universel
La chaîne, de la barre de recherche au binaire en exécution. Aucun exploit nulle part : une annonce sponsorisée, une page hébergée par Google qui ne contient rien, une iframe qui contient tout, et un humain qui porte la charge de l'autre côté de la frontière en la collant. La seule commande que la victime voit jamais commence par une vraie ligne npm install pour Codex ; le base64 qui suit va chercher l'étape une. La balise event=pasted de l'étape deux est l'accusé de réception de l'opérateur lui-même.

L'étape en amont des scanners

Alignez les contrôles que l'industrie a passé deux ans à construire pour les agents de codage. L'analyse de réputation des registres. Les fichiers de verrouillage et les empreintes d'intégrité. La provenance de build et l'attestation. Les SBOM. Les délais minimaux sur les nouvelles versions de paquets. L'analyse statique du code généré. Tous fonctionnent, et tous partent de la même hypothèse : le développeur a déjà une chaîne d'outils qui marche, et le risque est en aval, dans ce qu'il en fait.

Cette campagne se situe en amont de tout cela. La contrefaçon ici, c'est l'agent lui-même, et il arrive avant tout registre, avant tout fichier de verrouillage, dans une commande que le développeur tape de ses propres mains dans son propre terminal. Un scanner n'a aucun artefact à noter, parce que l'artefact est une phrase sur une page web.

Le ciblage est l'autre moitié de l'économie. Quelqu'un qui enchérit sur codex macos download achète la machine d'une personne qui est, à cet instant précis, en train de mettre en place un agent de codage : une machine qui, dans l'heure, contiendra un jeton d'API, une clé SSH, un fichier ~/.aws/credentials et un PAT GitHub, autant de choses qu'un voleur d'informations sait trouver. Le moment de l'installation est le moment le moins cher pour être là.

Nous avons déjà couvert l'inverse : avec FakeGit et AgentBaiting, c'est l'agent qui cherche et qui tend à l'humain les étapes d'installation. Ici, c'est l'humain qui cherche. Les deux marchent parce que découvrir-puis-coller est la façon dont les logiciels s'installent, et qu'aucun scanner ne se tient à l'une ou l'autre extrémité de cette boucle.

D'où vient la commande d'installation

Bromure Agentic Coding n'a pas de telle boucle, et la raison tient à l'origine de l'agent.

Vous n'allez pas chercher un agent de codage. Codex est un interrupteur dans le panneau Agents d'un profil, à côté de Claude Code et de Grok Build. Activez-le, choisissez son mode d'authentification, et l'agent est là à la session suivante, tournant dans un onglet kitty à l'intérieur de la VM du profil.

Derrière cet interrupteur, il y a une chaîne figée. Bromure provisionne son image de base depuis son propre catalogue, et l'entrée pour Codex tient en une ligne :

npx --yes @socketsecurity/cli npm install -g --silent @openai/codex

Claude Code est @anthropic-ai/claude-code sur le même modèle, Kimi Code est @moonshot-ai/kimi-code. Les noms de paquets sont compilés dans l'application, pas découverts. Le registre est registry.npmjs.org, pas l'hôte qu'une iframe désigne. L'installation passe par le CLI socket.dev, et la requête sort par le proxy MITM de l'hôte, où s'appliquent les politiques Supply Chain du profil : le délai de deux jours actif par défaut, plus les recherches OSV, le filtrage socket.dev ou Delpi, et le retrait des scripts d'installation que vous pouvez activer.

Ce chemin n'a ni résultat de recherche, ni page à usurper. Le canal que l'attaquant a payé pour empoisonner est absent du flux de travail, et absent n'est pas un contrôle qu'il faut penser à opérer.

L'installer comme d'habitudequi nomme l'artefact ?celui qui a gagné l'enchère pubqui le sert ?une iframe sur une page sosiequ'est-ce qui s'exécute ?tout ce qui suit la première ligneoù ?votre Mac, votre compte, à côté de~/.ssh · ~/.aws · ~/.git-credentialsGatekeeper réduit au silence par xattr -cQuatre questions ouvertes, un inconnu y répond.L'activer dans un profil Bromurequi nomme l'artefact ?@openai/codex, du catalogue d'imagesqui le sert ?registry.npmjs.org, via le proxy hôtequ'est-ce qui s'exécute ?une commande compilée, aucun texte libreoù ?une VM Linux jetable, construite avantla recherche — aucune clé dedans,identifiants leurres, sortie contrôléeMêmes questions, répondues avant d'être posées.
Deux façons d'acquérir un agent de codage. À gauche, l'étape d'acquisition est une barre de recherche et un bouton copier : le nom de l'artefact, l'hôte qui le sert et la commande qui l'installe sont tous choisis par celui qui a gagné l'enchère publicitaire, et le résultat s'exécute sur le Mac qui détient les clés du développeur. À droite, le nom de l'artefact est compilé dans l'application, le registre est fixe, la requête est filtrée au proxy de l'hôte, et l'installation tourne dans une VM jetable construite avant que tout cela ne commence.

Maintenant, collez-la quand même

L'architecture doit survivre au jour où quelqu'un l'ignore. Prenez la campagne, donnez-lui la victoire, et faites-la traverser un profil : quelqu'un trouve le faux portail, copie la commande, et la colle dans le terminal où il fait son travail d'agent, qui dans Bromure Agentic Coding est un onglet kitty à l'intérieur de la VM.

Le binaire ne s'exécute pas. Un Mach-O universel est un exécutable macOS. L'invité est Ubuntu. xattr n'est pas une commande Linux, et /tmp/helper est un chemin sur un disque système qui existe pour être jeté. Ressources → Stockage vous donne Effacer le dossier personnel… pour /home/ubuntu et Réinitialiser à la base… pour recloner le disque système de l'espace de travail depuis l'image de base partagée, en lecture seule.

Les trois requêtes ne sortent pas. Chaque étape de cette chaîne a besoin du réseau : l'URL décodée en base64 qui tire l'étape une, la balise event=pasted, et le téléchargement de la charge. Garde-fous → Connexions sortantes est une table de règles à la pf : action, protocole (tcp, udp, web, any), hôte ou CIDR, ports, et pour web une liste de méthodes HTTP, évaluées de haut en bas, première correspondance gagnante, avec Trafic non apparié réglé sur Autoriser ou Refuser. Réglez-le sur Refuser et listez les hôtes dont votre travail a besoin. bright-links.com n'en fait pas partie. Bromure applique la table côté hôte, dans le commutateur virtuel et le proxy, si bien que rien de ce que l'invité fait à son propre environnement ne change la réponse.

L'étape deux est celle sur laquelle il vaut la peine de s'arrêter. event=pasted est la métrique de conversion de l'opérateur, le ping qui lui dit qu'une page d'atterrissage fonctionne, et à quel point. Quand cette requête meurt à l'hôte, il ne reçoit pas un rapport d'infection échouée. Il reçoit du silence, ce qui se lit comme une impression publicitaire qui n'a jamais converti.

Le vol rapporte des espaces réservés. Un voleur de la classe d'Atomic vise les données de navigateur, les portefeuilles et, sur une machine de développement, les identifiants. Dans un profil Bromure, les vraies valeurs n'entrent jamais dans la VM. Les clés d'API génériques sont de faux brm_… exportés en variables d'environnement et échangés sur le fil par le proxy de l'hôte. Le kubeconfig est synthétique, avec des certificats client jetables. Les requêtes AWS sont resignées côté hôte, de sorte que tout ce qui contourne le proxy reçoit InvalidSignatureException. ~/.docker/config.json contient un faux blob base64. Les clés SSH privées ne sont pas là à lire : elles n'y ont jamais été. Activez Exiger une approbation à l'usage par identifiant et chaque échange devient une boîte de dialogue côté hôte avec une autorisation bornée dans le temps : cinq minutes, une heure, le reste de la session. Un profil partage au plus huit dossiers que vous avez choisis, si bien que le reste du Mac n'est pas à un parcours de répertoire de distance.

La corrélation est déjà sur votre écran. La conclusion de Cato elle-même est qu'aucune étape prise isolément n'expose cette campagne ; la détection a demandé de corréler ensemble la livraison par recherche sponsorisée, le contenu web embarqué, l'exécution dans le Terminal et l'activité sortante. C'est un problème difficile quand vos preuves sont réparties entre un navigateur, un shell et une sonde réseau. Dans un profil, c'est une seule fenêtre : le Journal de sécurité (Fenêtre → Journal de sécurité…) est une table chronologique unique, côté hôte, des verdicts de paquets, des décisions du pare-feu, des échanges d'identifiants et des détections d'injection de prompt. Le code invité ne peut pas la modifier, parce que le code invité ne peut pas l'atteindre.

Activez-le

Le délai est actif par défaut à deux jours. Les autres couches sont des réglages, et elles valent deux minutes : Garde-fous → Connexions sortantes, avec Trafic non apparié sur Refuser et une liste d'autorisation pour les hôtes dont votre travail a besoin. Supply Chain → Vérification de vulnérabilités OSV, plus le filtrage socket.dev ou Delpi si vous avez une clé, et le retrait des scripts d'installation. Identifiants → Exiger une approbation à l'usage sur tout ce qui peut dépenser de l'argent ou détruire des données. Puis laissez la fenêtre du Journal de sécurité ouverte sur un second écran pendant une semaine et voyez à qui parlent vos builds.

Les résultats de recherche sponsorisés vont continuer d'être la porte d'entrée, et les constructeurs de sites sur des domaines de confiance vont continuer d'héberger le perron. Google fera tomber ces pages et trois autres monteront, parce que l'économie, c'est quelques dollars par clic contre un poste de développement avec des identifiants cloud dessus. Installez Bromure Agentic Coding, activez vos agents depuis l'éditeur de profil plutôt que depuis une page de téléchargement, et laissez la prochaine commande collée atterrir dans une machine construite pour être jetée.