Le write dans `/tmp` a été refusé par les permissions, donc voici l'article complet directement. Dis-moi où tu veux que je l'écrive et j'y retourne. --- ```html

Il est 8 h 47 un mardi matin lorsque votre chaîne d'intégration continue échoue sur un contrôle d'intégrité, et que dans le même quart d'heure un journaliste spécialisé vous adresse un courriel dont l'objet tient en cinq mots : « paquet npm compromis, votre réaction ? ». Vous dirigez le SOC d'un cabinet de conseil de six cents personnes qui livre des applications métier à des clients bancaires et industriels. Le paquet incriminé, une bibliothèque d'analytics utilisée par vos équipes front-end depuis dix-huit mois, a été publié avec une porte dérobée dans son script postinstall. Vous disposez de quatre heures avant la publication de l'article pour répondre à trois questions que personne, en interne, ne sait trancher : quels systèmes ont installé la version piégée, la charge malveillante s'est-elle exécutée, et vos clients sont-ils exposés. Ce guide déroule cette course contre la montre heure par heure, avec les prompts Microsoft Copilot Security réellement saisis dans la console, les requêtes KQL exécutées dans Defender XDR, et l'usage du plugin Microsoft Defender Threat Intelligence pour attribuer, corréler et documenter. Le scénario est fictif ; les techniques, les requêtes et la mécanique de réponse ne le sont pas.

Avertissement méthodologique. Le paquet @ui-kit-fr/analytics et le cabinet décrit sont des inventions pédagogiques. Aucun paquet npm réellement publié n'est mis en cause ici. Les campagnes historiques citées en comparaison — SolarWinds, 3CX, XZ Utils, Polyfill.io — sont en revanche documentées publiquement et servent de points de repère pour calibrer votre propre posture.

Pourquoi la supply chain logicielle est devenue le chemin le plus court

Un attaquant qui vise un cabinet de conseil a deux options. La première consiste à attaquer le cabinet : hameçonnage, exploitation d'un service exposé, achat d'identifiants sur un forum. C'est bruyant, c'est détecté, et le taux de conversion est faible face à une organisation qui a déployé une authentification forte et un EDR correctement réglé. La seconde consiste à attaquer ce que le cabinet installe sans y penser. Une dépendance transitive tirée par un npm install dans un conteneur de build hérite du contexte d'exécution de ce conteneur : ses variables d'environnement, ses jetons de déploiement, son accès réseau sortant. Elle franchit le périmètre par la porte que vous avez vous-même laissée ouverte, parce qu'aucune organisation ne peut auditer manuellement les mille quatre cents paquets que remonte un projet React moyen.

Quatre affaires structurent la compréhension du problème. SolarWinds (décembre 2020) a montré qu'un adversaire étatique pouvait s'installer durablement dans une chaîne de compilation et injecter du code dans un binaire signé légitimement : la signature numérique, sur laquelle repose tout le modèle de confiance logicielle, ne prouve que l'identité de l'éditeur, jamais l'intégrité de ce qu'il a compilé. 3CX (mars 2023) a franchi une étape supplémentaire avec une compromission en cascade : l'éditeur du logiciel de téléphonie a lui-même été victime d'une dépendance piégée, produisant la première chaîne d'attaque supply chain à deux niveaux publiquement documentée.

XZ Utils (mars 2024) a introduit une variable que peu de modèles de risque intégraient : le temps long. Un contributeur a bâti sa réputation pendant deux ans sur un projet open source critique, obtenu le statut de mainteneur, puis inséré une porte dérobée visant l'authentification SSH — découverte par hasard, à cause d'un délai de connexion de cinq cents millisecondes qui intriguait un ingénieur Microsoft. Polyfill.io (juin 2024) a rappelé qu'un nom de domaine racheté suffit : cent mille sites servaient un script depuis une infrastructure passée sous contrôle hostile, sans qu'une seule ligne de leur propre code n'ait changé.

Le point commun de ces quatre cas n'est pas technique, il est temporel. Dans chacun, la fenêtre entre la compromission et la détection se compte en semaines ou en années, et la fenêtre entre la détection publique et l'obligation de répondre se compte en heures. C'est cette seconde fenêtre que ce guide vous apprend à tenir. Pour situer cette classe d'attaque dans une cartographie défensive plus large, notre couverture MITRE ATT&CK de Copilot Security détaille les techniques adressées et les angles morts résiduels.

Le scénario : quatre heures, un paquet, six cents développeurs

Reprenons la situation à 8 h 47. Les faits établis tiennent en cinq lignes. Le paquet @ui-kit-fr/analytics, versions 3.4.6 et 3.4.7, publiées respectivement le 12 et le 14 août, contient dans son script postinstall un chargeur obfusqué qui déchiffre une charge secondaire et l'exécute en mémoire. Le mainteneur légitime a confirmé sur son dépôt public que son jeton de publication avait été compromis, probablement via une campagne d'hameçonnage ciblant les mainteneurs npm. Le paquet cumule quatre-vingt mille téléchargements hebdomadaires. Votre cabinet l'utilise dans un design system interne, lui-même dépendance de trente et un projets clients.

Les inconnues sont plus nombreuses. Vous ignorez combien de postes développeurs ont exécuté un npm install depuis le 12 août, si vos runners de build ont tiré la version piégée, ce que fait exactement la charge secondaire, et si des artefacts contaminés ont été livrés à des clients. Vous ignorez aussi, et c'est le plus inconfortable, ce que le journaliste sait déjà.

La discipline qui sauve ce genre de matinée tient en une phrase : ne cherchez pas à tout savoir, cherchez à savoir ce qui change une décision. Trois décisions sont en jeu dans les quatre heures. Faut-il isoler des machines ? Faut-il notifier des clients ? Faut-il déclarer un incident aux autorités ? Chaque minute d'investigation doit servir l'une de ces trois questions, et Copilot Security sert précisément à compresser le temps entre une question et sa réponse étayée.

La chaîne d'attaque en un coup d'œil

┌────────────────────────────────────────────────────────┐
│ 1. COMPROMISSION AMONT                    T1195.001    │
│    Hameçonnage du mainteneur → vol du jeton npm        │
│    (aucune MFA sur le compte de publication)           │
└──────────────────────────┬─────────────────────────────┘
                           ▼
┌────────────────────────────────────────────────────────┐
│ 2. PUBLICATION PIÉGÉE                     T1195.002    │
│    @ui-kit-fr/analytics 3.4.6 puis 3.4.7               │
│    postinstall → loader obfusqué base64                │
└──────────────────────────┬─────────────────────────────┘
                           ▼
        ┌──────────────────┴──────────────────┐
        ▼                                     ▼
┌───────────────────────┐          ┌───────────────────────┐
│ 3a. POSTES DEV        │          │ 3b. RUNNERS CI/CD     │
│  npm install local    │          │  pipeline nocturne    │
│  T1059.007 (Node)     │          │  T1552.001 (secrets)  │
└───────────┬───────────┘          └───────────┬───────────┘
            │                                  │
            ▼                                  ▼
┌───────────────────────┐          ┌───────────────────────┐
│ 4a. RECON LOCALE      │          │ 4b. VOL DE SECRETS    │
│  ~/.npmrc, ~/.aws     │          │  env CI, jetons OIDC  │
│  T1005                │          │  T1078.004            │
└───────────┬───────────┘          └───────────┬───────────┘
            └────────────────┬─────────────────┘
                             ▼
┌────────────────────────────────────────────────────────┐
│ 5. EXFILTRATION C2                        T1071.001    │
│    HTTPS sortant → CDN légitime détourné               │
│    Beacon 3600 s + jitter, User-Agent npm mimétique    │
└──────────────────────────┬─────────────────────────────┘
                           ▼
┌────────────────────────────────────────────────────────┐
│ 6. PROPAGATION AVAL                       T1195.002    │
│    Artefacts de build signés → livraison client        │
│    ⚠ point de bascule juridique et réputationnel       │
└────────────────────────────────────────────────────────┘

L'étape 6 est celle qui transforme un incident de sécurité interne en incident contractuel. Tant que la contamination reste confinée aux postes et aux runners, vous gérez une remédiation. Dès qu'un artefact contaminé est signé et livré, vous devenez à votre tour un maillon compromis de la chaîne de vos clients, avec les obligations d'information que cela emporte.

Timeline MITRE ATT&CK de la compromission

Reconstituer la séquence dans le référentiel ATT&CK n'est pas un exercice de style. C'est ce qui vous permet, à H+3, de produire une note de synthèse que votre direction juridique et le CERT-FR liront sans traduction. Copilot Security sait faire cette conversion, à condition de lui donner la matière brute.

Prompt 1 — reconstruction de la kill chain.

« À partir des incidents Defender XDR des sept derniers jours impliquant le processus node.exe avec une ligne de commande contenant "postinstall", reconstitue une timeline ordonnée et associe chaque événement à une tactique et une technique MITRE ATT&CK. Présente le résultat en tableau : horodatage UTC, hôte, utilisateur, technique, identifiant ATT&CK, niveau de confiance. Signale explicitement les étapes de la chaîne pour lesquelles tu ne disposes d'aucune télémétrie. »

La dernière phrase du prompt est la plus importante. Un modèle sollicité sur une reconstruction produira volontiers une chaîne complète et cohérente ; ce que vous voulez savoir, ce sont les trous. Si Copilot vous répond qu'il n'a aucune télémétrie sur la phase d'exfiltration, cela signifie soit qu'elle n'a pas eu lieu, soit que vos runners de build n'envoient pas leurs journaux réseau — et ces deux hypothèses appellent des actions opposées.

Les phases retenues dans notre scénario se répartissent ainsi. Initial Access : compromission amont via T1195.002 Supply Chain Compromise: Compromise Software Supply Chain, hors de votre périmètre de visibilité. Execution : T1059.007, exécution de JavaScript par l'interpréteur Node au moment de l'installation, avec les privilèges de l'utilisateur ou du service de build. Discovery : T1082 et T1083, énumération du système et des fichiers de configuration. Credential Access : T1552.001, recherche d'identifiants dans les fichiers .npmrc, .aws/credentials, .docker/config.json et les variables d'environnement du runner. Command and Control : T1071.001, balise HTTPS vers une infrastructure hébergée derrière un CDN grand public. Exfiltration : T1041, sortie des données sur le canal C2 existant.

Notez l'absence de phase de persistance dans cette liste. C'est une caractéristique fréquente des charges de supply chain massives : l'attaquant privilégie le volume à la profondeur. Il ratisse quatre-vingt mille installations à la recherche de jetons exploitables, puis revient manuellement sur les cibles qui en valent la peine. Votre cabinet, avec ses clients bancaires, est exactement le type de cible qui justifie un retour.

H+0 à H+1 : qualifier la menace avec le plugin MDTI

La première heure ne sert pas à chercher des machines infectées. Elle sert à savoir ce que vous cherchez. Le plugin Microsoft Defender Threat Intelligence, activé dans les sources de Copilot Security, donne accès aux articles d'analyse, aux profils d'acteurs, aux indicateurs de compromission enrichis et aux relations d'infrastructure. Sans lui, vous investiguez à l'aveugle sur un nom de paquet.

Prompt 2 — profilage de la campagne.

« Avec MDTI, recherche les articles de renseignement et les indicateurs publiés au cours des dix derniers jours concernant des compromissions de paquets npm par vol de jeton de mainteneur. Pour chaque campagne identifiée, donne-moi : le nom d'acteur suivi par Microsoft, les techniques ATT&CK associées, les domaines et adresses IP de commande et contrôle connus, et le secteur des victimes observées. Ne me présente que les éléments dont la date de première observation est postérieure au 1er août 2026. »

Microsoft suit les acteurs selon une taxonomie météorologique, où la famille de phénomène désigne la catégorie d'acteur et l'adjectif le groupe précis. Une campagne à motivation financière ciblant les registres de paquets relèvera typiquement d'une désignation en Tempest. Cette information n'est pas décorative : elle conditionne votre pronostic. Un acteur à motivation financière monétise des jetons cloud dans les heures qui suivent ; un acteur étatique s'installe et attend. Le premier vous oblige à révoquer immédiatement, le second vous oblige à chasser longuement.

Prompt 3 — enrichissement des indicateurs.

« Enrichis avec MDTI les indicateurs suivants extraits du script postinstall de @ui-kit-fr/analytics 3.4.7 : cdn-metrics-eu[.]net, 185.243.x.x, et le hash SHA256 de la charge déchiffrée. Pour chacun, donne-moi la réputation, la date de première et de dernière observation, les certificats TLS associés, les domaines partageant la même infrastructure d'hébergement, et les campagnes historiques liées. Indique clairement les indicateurs pour lesquels MDTI ne dispose d'aucune donnée. »

Le pivot d'infrastructure est ici la fonction la plus rentable. Un domaine de C2 vit rarement seul : il partage un certificat, un bloc d'adresses, un enregistreur ou un motif de résolution avec d'autres. Si MDTI vous rend quatre domaines frères, vous venez de quadrupler la surface de détection de votre chasse, et vous pourrez les injecter directement dans les requêtes KQL de la section suivante. C'est aussi cette liste élargie que vous transmettrez au CERT-FR, qui la redistribuera à sa constituante.

Prompt 4 — décompilation de la charge.

« Voici le contenu du script postinstall du paquet compromis, encodé en base64. Désobfusque-le, explique en français ce que fait chaque bloc fonctionnel, liste tous les fichiers et variables d'environnement lus, toutes les destinations réseau contactées, et indique si le code comporte des conditions d'évasion — détection de bac à sable, de machine virtuelle, ou vérification de plage géographique. »

Les conditions d'évasion changent l'interprétation de vos résultats de chasse. Une charge qui refuse de s'exécuter dans un environnement virtualisé produira zéro détection sur vos runners conteneurisés tout en ayant parfaitement fonctionné sur les portables des développeurs. Une charge qui ne s'active que sur des systèmes dont la locale est fr-FR transforme un incident global en incident ciblé, ce qui est une information de communication autant que de technique.

H+1 à H+2 : inventorier les systèmes exposés

Vous savez maintenant quoi chercher. La question devient : où. Trois populations sont concernées et leur télémétrie diffère. Les postes développeurs sont couverts par Defender for Endpoint et remontent l'exécution de processus. Les runners CI/CD sont souvent des conteneurs éphémères dont la couverture EDR est partielle. Les serveurs applicatifs qui hébergent les artefacts construits sont couverts mais ne montrent pas l'installation, seulement ses conséquences.

Prompt 5 — inventaire consolidé.

« Génère une requête KQL pour Microsoft Defender XDR qui identifie tous les appareils ayant exécuté npm install ou yarn add avec une référence à @ui-kit-fr/analytics entre le 12 août 2026 00:00 UTC et maintenant. Croise DeviceProcessEvents et DeviceFileEvents pour capturer aussi les cas où seul le fichier package-lock.json a été modifié. Restitue une ligne par appareil : nom, utilisateur, horodatage, version installée si extractible de la ligne de commande, et groupe d'appareils. »

La requête que Copilot produit mérite d'être relue et durcie avant exécution. Voici la version consolidée que nous avons retenue :

let debut = datetime(2026-08-12 00:00:00);
let paquet = "@ui-kit-fr/analytics";
// 1. Installations explicites observées en ligne de commande
let installs =
DeviceProcessEvents
| where Timestamp >= debut
| where FileName in~ ("npm.cmd", "npm", "node.exe", "yarn.cmd", "pnpm.cmd")
| where ProcessCommandLine has_any ("install", "add", "ci")
| where ProcessCommandLine contains paquet
| extend Version = extract(@"analytics@(\d+\.\d+\.\d+)", 1, ProcessCommandLine)
| project Timestamp, DeviceName, DeviceId, AccountName,
          ProcessCommandLine, Version, Source = "cmdline";
// 2. Traces disque : le paquet a atterri dans node_modules
let fichiers =
DeviceFileEvents
| where Timestamp >= debut
| where FolderPath has "node_modules" and FolderPath has "ui-kit-fr"
| where FileName in~ ("package.json", "index.js", "postinstall.js")
| summarize Timestamp = min(Timestamp), Fichiers = make_set(FolderPath, 20)
          by DeviceName, DeviceId, InitiatingProcessAccountName
| extend AccountName = InitiatingProcessAccountName,
         ProcessCommandLine = "", Version = "", Source = "disque"
| project Timestamp, DeviceName, DeviceId, AccountName,
          ProcessCommandLine, Version, Source;
union installs, fichiers
| summarize PremiereVue = min(Timestamp), DerniereVue = max(Timestamp),
            Sources = make_set(Source), Versions = make_set(Version),
            Comptes = make_set(AccountName)
          by DeviceName, DeviceId
| order by PremiereVue asc

L'union des deux angles n'est pas une coquetterie. Un développeur qui exécute npm ci à la racine d'un projet n'écrit jamais le nom du paquet dans sa ligne de commande : la dépendance est transitive, elle vient du design system interne. Seule la branche DeviceFileEvents le rattrape. À l'inverse, un runner dont le système de fichiers est monté en surcouche éphémère peut ne rien remonter côté fichiers tout en laissant une trace de processus. Chercher par un seul angle vous fera manquer entre trente et cinquante pour cent du parc, ce qui, dans une communication publique, est la différence entre une déclaration exacte et un démenti à rédiger la semaine suivante.

Détecter les communications C2 depuis les serveurs de build

L'inventaire vous dit qui a installé. La détection réseau vous dit qui a été effectivement exploité. C'est la donnée la plus lourde de conséquences : elle sépare l'exposition théorique de la compromission avérée.

Prompt 6 — chasse au canal de commande.

« Écris une requête KQL qui recherche, sur le périmètre des serveurs de build identifiés par le groupe d'appareils "CI-Runners", toute connexion réseau sortante initiée par node.exe ou npm vers les domaines et adresses IP fournis par MDTI. Ajoute une détection comportementale des connexions périodiques : regroupe par couple hôte-destination, calcule l'écart-type des intervalles entre connexions et remonte les couples dont la régularité suggère une balise automatisée. »

let ioc_domaines = dynamic(["cdn-metrics-eu.net", "static-telemetry.app",
                            "npm-registry-mirror.io"]);
let debut = datetime(2026-08-12 00:00:00);
// A. Correspondance directe sur IOC
let match_ioc =
DeviceNetworkEvents
| where Timestamp >= debut
| where InitiatingProcessFileName in~ ("node.exe", "node", "npm.cmd")
| where RemoteUrl has_any (ioc_domaines)
   or RemoteIP startswith "185.243."
| project Timestamp, DeviceName, RemoteUrl, RemoteIP, RemotePort,
          InitiatingProcessCommandLine, Verdict = "IOC connu";
// B. Détection de balise par régularité des intervalles
let beaconing =
DeviceNetworkEvents
| where Timestamp >= debut
| where InitiatingProcessFileName in~ ("node.exe", "node")
| where RemoteIPType == "Public"
| sort by DeviceName asc, RemoteIP asc, Timestamp asc
| extend IntervalleSec = datetime_diff('second', Timestamp, prev(Timestamp))
| where prev(DeviceName) == DeviceName and prev(RemoteIP) == RemoteIP
| summarize Connexions = count(),
            IntervalleMoyen = avg(IntervalleSec),
            EcartType = stdev(IntervalleSec),
            Debut = min(Timestamp), Fin = max(Timestamp)
          by DeviceName, RemoteIP, RemoteUrl
| where Connexions >= 8 and IntervalleMoyen between (60 .. 7200)
| extend Regularite = EcartType / IntervalleMoyen
| where Regularite < 0.25   // jitter faible = automatisme
| project Timestamp = Debut, DeviceName, RemoteUrl, RemoteIP,
          RemotePort = 443, InitiatingProcessCommandLine = "",
          Verdict = strcat("Balise suspecte — ", round(IntervalleMoyen),
                    "s ±", round(Regularite * 100), "%");
union match_ioc, beaconing
| order by Timestamp asc

Le second bloc est celui qui vous protège contre l'obsolescence des indicateurs. Un attaquant compétent fait tourner son infrastructure ; les domaines que MDTI vous a donnés le matin peuvent être morts l'après-midi. La régularité d'un intervalle, elle, est une propriété du code malveillant, pas de son hébergement. Un ratio écart-type sur moyenne inférieur à 0,25 signale un comportement machine ; le trafic humain et la plupart des appels d'API applicatifs sont beaucoup plus dispersés. Attendez-vous à des faux positifs sur les sondes de supervision et les clients de synchronisation, qu'il faut lister une fois pour toutes dans une exclusion documentée.

Analyse comportementale : la charge a-t-elle agi ?

Installation confirmée, C2 possiblement contacté. Reste la question qui détermine la gravité réelle : qu'a fait la charge une fois active. Trois familles d'actions sont à vérifier, dans cet ordre de priorité.

La lecture de secrets. La charge cherche des fichiers de configuration contenant des jetons. Sur un poste développeur, cela signifie ~/.npmrc, ~/.aws/credentials, ~/.config/gh/hosts.yml, les trousseaux de session kubectl. Sur un runner, cela signifie surtout les variables d'environnement injectées par la plateforme CI, qui contiennent typiquement un jeton de registre, un jeton de déploiement et parfois une clé de signature.

let hotes_touches = dynamic(["BUILD-RUNNER-03", "BUILD-RUNNER-07",
                             "DEV-LT-0142", "DEV-LT-0219"]);
DeviceFileEvents
| where Timestamp >= datetime(2026-08-12 00:00:00)
| where DeviceName in~ (hotes_touches)
| where ActionType == "FileAccessed" or ActionType == "FileModified"
| where FileName in~ (".npmrc", "credentials", "config.json",
                      "id_rsa", "hosts.yml", ".env")
      or FolderPath has_any (".aws", ".ssh", ".docker", ".kube")
| where InitiatingProcessFileName in~ ("node.exe", "node", "sh", "bash")
| project Timestamp, DeviceName, ActionType, FolderPath, FileName,
          InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by Timestamp asc

L'usage des secrets volés. C'est l'étape qui transforme un vol en intrusion. Un jeton exfiltré à 2 h 14 du matin et utilisé depuis une adresse inhabituelle à 6 h 30 vous place dans une situation entièrement différente. Interrogez Entra ID et vos journaux de plateforme cloud.

Prompt 7 — corrélation identités.

« Pour les comptes de service utilisés par les runners BUILD-RUNNER-03 et BUILD-RUNNER-07, liste toutes les authentifications réussies depuis le 12 août 2026 en signalant celles dont l'adresse IP source, le pays, l'agent utilisateur ou l'application cliente diffèrent du profil habituel de ces comptes sur les quatre-vingt-dix jours précédents. Indique pour chaque anomalie les ressources accédées dans les trente minutes suivant l'authentification. »

L'altération d'artefacts. La troisième vérification est la plus longue et la plus déterminante juridiquement. Il faut comparer les empreintes des artefacts produits depuis le 12 août avec ce que produirait une reconstruction propre. Si vos builds ne sont pas reproductibles — c'est le cas de la majorité des chaînes JavaScript — vous devrez procéder par différence de contenu sur les bundles générés, en cherchant tout code n'ayant pas d'origine identifiable dans vos sources.

Cartographier la chaîne CI/CD compromise

À ce stade vous avez des hôtes, des comptes et des artefacts. Il vous manque la carte qui les relie, et c'est elle que votre direction réclamera. La cartographie répond à une question simple : par où le paquet est-il entré, jusqu'où est-il allé, et quels flux de sortie a-t-il pu emprunter.

Prompt 8 — reconstruction du graphe CI/CD.

« En croisant les événements Defender XDR, les journaux d'audit du dépôt Git et les journaux de la plateforme CI, construis la cartographie de propagation de @ui-kit-fr/analytics 3.4.7 dans notre chaîne de livraison. Pour chaque étape, précise : le dépôt source, le pipeline déclenché, le runner qui l'a exécuté, les artefacts produits avec leur empreinte, le registre de destination, et la date de la dernière livraison client. Classe les branches de propagation par criticité selon qu'un artefact a été signé et publié ou non. »

Dans notre scénario, la cartographie révèle une asymétrie rassurante. Vingt-sept des trente et un projets clients tirent le design system par une version épinglée antérieure à la compromission ; leurs pipelines n'ont jamais vu la 3.4.7. Trois projets utilisent une plage de versions permissive mais leur dernier build date du 8 août. Un seul projet, un portail de reporting pour un client industriel, a construit et publié un artefact le 14 août à 23 h 40, soit six heures après la publication du paquet piégé. Cette unique ligne concentre désormais l'essentiel de votre risque, et elle justifie à elle seule les trois heures d'investigation qui l'ont précédée.

H+2 à H+3 : patch management d'urgence

La remédiation d'une compromission de dépendance obéit à un ordre qui n'est pas négociable. Le réflexe naturel — mettre à jour le paquet partout — est le bon geste au mauvais moment.

Révoquer d'abord. Tout secret ayant pu être lu par la charge est réputé compromis, qu'une exfiltration ait été observée ou non. Jetons de registre, clés de déploiement, identités fédérées des runners, jetons d'accès personnels des développeurs concernés, clés de signature si elles étaient accessibles depuis le contexte de build. La révocation prend quinze minutes et ferme la porte pendant que vous nettoyez.

Bloquer ensuite. Ajoutez les indicateurs MDTI aux indicateurs personnalisés de Defender for Endpoint en action Block, et interdisez la version piégée au niveau de votre registre interne. Si vous n'avez pas de registre interne servant de miroir, cet incident est l'argument qui financera sa mise en place.

Purger enfin. Les caches sont le piège classique. Un npm install après correction du package.json peut resservir l'archive piégée depuis le cache local, le cache du runner ou une couche d'image Docker. La séquence complète comprend la suppression des node_modules, la purge du cache npm, la reconstruction des images de base et la régénération des fichiers de verrouillage.

Prompt 9 — plan de remédiation ordonné.

« Rédige un plan de remédiation d'urgence pour la compromission de @ui-kit-fr/analytics, organisé en trois vagues : confinement immédiat, éradication, reconstruction. Pour chaque action, indique le système concerné, l'équipe responsable, la durée estimée, le prérequis bloquant, et le critère de vérification qui prouve que l'action a réussi. Signale les actions qui provoqueront une interruption de service et propose une fenêtre alternative. »

Le critère de vérification est ce qui distingue un plan d'une liste de vœux. « Purger les caches » n'est pas vérifiable ; « npm cache verify ne retourne plus l'archive dont le SHA correspond à l'IOC » l'est. Vous aurez besoin de ces preuves pour la note de clôture, et éventuellement pour un audit client.

Communiquer avec l'équipe dev sans déclencher la panique

Six cents personnes, dont deux cents développeurs, vont apprendre l'affaire dans la journée. La qualité de votre communication interne détermine directement la qualité de votre remédiation, parce que ce sont eux qui l'exécuteront.

Trois erreurs sont fréquentes et coûteuses. La première consiste à envoyer une alerte générale avant d'avoir un périmètre : vous obtiendrez deux cents messages de développeurs demandant s'ils sont concernés, ce qui saturera l'équipe qui devait investiguer. La seconde consiste à formuler l'incident en termes de faute : les développeurs qui ont installé le paquet ont suivi le processus, et une communication accusatoire garantit que le prochain incident vous sera signalé plus tard. La troisième consiste à sous-doser : dire « par précaution » d'une compromission avérée détruit votre crédibilité au deuxième incident.

La formulation qui fonctionne tient en quatre blocs : ce qui s'est passé, ce que nous savons de votre situation précise, ce que vous devez faire maintenant, et à qui vous adresser. Adressez des messages différenciés — les quatre hôtes touchés reçoivent des instructions individuelles, le reste du parc reçoit une note de contexte sans action requise. Cette différenciation est possible parce que vous avez fait l'inventaire à H+1.

Prompt 10 — production des communications internes.

« Rédige trois communications distinctes sur cet incident : une note technique de deux cents mots pour les quatre développeurs dont le poste est confirmé touché, avec les commandes exactes à exécuter ; une note de contexte de cent cinquante mots pour l'ensemble de l'équipe de développement, sans action requise ; et un point de situation d'une page pour le comité de direction, orienté impact client et exposition juridique. Ton factuel, sans jargon inutile, sans dramatisation, sans attribution de responsabilité individuelle. »

H+3 à H+4 : notifier l'ANSSI, le CERT-FR et les clients

La dernière heure est celle des obligations externes, et elle se prépare depuis H+0 : chaque élément produit précédemment alimente une notification.

Le CERT-FR est votre interlocuteur opérationnel. Un signalement à [email protected] est utile même hors obligation réglementaire, pour deux raisons : il vous fait bénéficier du recoupement avec les autres victimes françaises, et il établit une trace horodatée de votre diligence. Transmettez les indicateurs, la chronologie et le périmètre ; ne transmettez pas de données personnelles à ce stade.

L'ANSSI intervient dans un cadre réglementaire. Si votre organisation est entité essentielle ou importante au titre de la directive NIS 2, l'alerte précoce est due dans les vingt-quatre heures suivant la connaissance de l'incident significatif, suivie d'une notification circonstanciée à soixante-douze heures. Ce délai court à partir du moment où vous avez su, c'est-à-dire 8 h 47 — pas à partir du moment où vous aurez fini d'investiguer. Si vous ignorez votre qualification, notre diagnostic de conformité NIS 2 permet de la déterminer en quelques minutes, et c'est le genre de question qu'il vaut mieux avoir tranchée avant l'incident.

La CNIL entre en jeu si des données personnelles sont concernées : soixante-douze heures, article 33 du RGPD. Dans notre scénario, le vol de jetons cloud ouvre un accès potentiel à des environnements contenant des données clients ; l'analyse doit être menée avec le DPO le jour même, pas la semaine suivante.

Les clients relèvent d'abord du contrat. La plupart des contrats de prestation avec des clients bancaires ou industriels imposent une information sous vingt-quatre à quarante-huit heures pour tout incident affectant les livrables. Dans notre cas, un seul client a reçu un artefact potentiellement contaminé : il doit être appelé, pas emailé, et l'appel doit venir avec un périmètre précis, une empreinte à vérifier de son côté et une date de correctif.

La presse arrive en dernier dans l'ordre de priorité, ce qui est contre-intuitif quand c'est elle qui a déclenché votre matinée. Répondre au journaliste avec un périmètre chiffré et vérifiable — quatre postes, deux runners, un artefact, zéro donnée client exfiltrée à ce stade — vous place dans une position radicalement meilleure qu'un « nous enquêtons ». Ne communiquez publiquement que ce que vos requêtes prouvent.

Durcir durablement : SBOM, Dependabot et scanning CI/CD

L'incident clos, la vraie question est le temps qu'il vous a fallu pour répondre « quels systèmes utilisent ce paquet ». Dans notre scénario, une heure. Avec les bons dispositifs, cinq minutes.

Le SBOM est le socle. Générer une nomenclature logicielle au format CycloneDX ou SPDX à chaque build, et la stocker à côté de l'artefact, transforme la question « qui utilise ce paquet » en requête sur une base. Un SBOM produit à la demande, en revanche, ne sert à rien : il décrit l'état actuel, pas l'état au moment de la livraison. La valeur est dans l'historisation.

Dependabot, ou son équivalent, couvre les vulnérabilités connues mais pas les compromissions actives : une porte dérobée publiée à 17 h n'a pas d'identifiant CVE à 17 h 05. Sa contribution réelle est ailleurs : il maintient l'écart entre vos versions et l'amont assez faible pour qu'une mise à jour d'urgence reste une opération de dix minutes plutôt qu'une migration de trois jours. La dette de dépendances est un facteur de temps de réponse.

Le scanning CI/CD apporte ce que les deux précédents ne couvrent pas. Trois contrôles ont un rendement élevé pour un coût faible : le refus des paquets publiés depuis moins de soixante-douze heures, qui neutralise la majorité des attaques de type typosquat et de compromission de mainteneur ; l'exécution des installations avec --ignore-scripts partout où c'est possible, qui désarme entièrement le vecteur postinstall ; et l'isolation réseau des runners derrière une liste d'autorisation de destinations sortantes, qui rend le C2 impossible même si la charge s'exécute. Ce dernier contrôle est le plus efficace des trois et le plus rarement déployé, parce qu'il demande de savoir ce que vos builds contactent légitimement — un inventaire que peu d'équipes ont fait.

Nos promptbooks Copilot Security incluent une séquence de chasse supply chain réutilisable qui enchaîne enrichissement MDTI, inventaire, détection C2 et génération du rapport, afin que la prochaine occurrence ne reparte pas d'une page blanche.

Post-mortem supply chain assisté par Copilot

Le post-mortem se tient dans les cinq jours, tant que les souvenirs sont frais et la pression retombée. Copilot Security y sert à deux choses : reconstituer la chronologie factuelle sans dépendre de la mémoire des participants, et confronter les décisions prises aux informations réellement disponibles au moment où elles ont été prises.

Prompt 11 — chronologie de post-mortem.

« À partir de l'ensemble des incidents, requêtes de chasse et actions de remédiation liés à l'incident supply chain du 16 août 2026, produis une chronologie factuelle unifiée en distinguant trois colonnes : ce qui s'est passé côté attaquant, ce que nous avons détecté, et ce que nous avons décidé. Calcule les délais entre compromission et détection, entre détection et confinement, entre confinement et notification. Identifie les points où une information disponible n'a pas été exploitée. »

Cette dernière consigne est celle qui produit de la valeur. Dans notre scénario, elle fait apparaître que l'échec d'intégrité du pipeline à 8 h 44 — trois minutes avant le courriel du journaliste — était déjà un signal, traité comme un incident de build par l'équipe plateforme et fermé en douze minutes. Ce n'est pas une faute individuelle, c'est un défaut de routage : les échecs d'intégrité de build ne remontaient pas au SOC. Une règle de corrélation créée le jour du post-mortem corrige cela pour toujours.

Mesurez trois indicateurs et suivez-les dans le temps : le délai de réponse à la question de l'inventaire, le pourcentage de builds produisant un SBOM historisé, et le nombre de runners disposant d'une liste d'autorisation sortante. Ces trois chiffres prédisent votre temps de réponse au prochain incident bien mieux que le nombre de vulnérabilités corrigées. Pour situer l'ensemble de ces capacités dans le déploiement de la plateforme, consultez notre guide complet de Microsoft Copilot Security.

Questions fréquentes

Copilot Security peut-il détecter seul un paquet npm compromis ?

Non, et c'est une confusion à dissiper. Copilot Security n'est pas un moteur de détection : il n'analyse pas les paquets, ne surveille pas les registres et ne produit pas d'alerte de son propre chef. Il agit sur la télémétrie déjà collectée par Defender XDR, Sentinel, Entra ID et MDTI. La détection initiale d'un paquet compromis vient d'ailleurs — un chercheur, le registre lui-même, un scanner de dépendances, un contrôle d'intégrité de build. Ce que Copilot compresse, c'est le temps entre cette alerte externe et une réponse étayée sur votre périmètre : là où l'écriture manuelle des requêtes, le pivot d'infrastructure et la rédaction des notes prennent une demi-journée, la boucle assistée tient en une heure.

Faut-il isoler immédiatement les machines ayant installé le paquet ?

Rarement, et jamais par réflexe. L'isolation d'un poste développeur coûte une journée de production et détruit une partie de la télémétrie volatile utile à l'investigation. Le critère de décision est l'usage avéré des secrets, pas l'installation. Isolez si vous observez une authentification anormale avec un identifiant issu de la machine, une exécution de charge secondaire, ou un mouvement latéral. Sinon, révoquez les secrets, bloquez les indicateurs au niveau réseau et laissez la machine sous surveillance renforcée — vous conservez ainsi la capacité d'observer une éventuelle seconde phase, ce que l'isolation vous retire.

Quelle différence entre le plugin MDTI et le renseignement gratuit sur les menaces ?

Les sources ouvertes vous donnent une liste d'indicateurs. MDTI vous donne un graphe. La différence se mesure au moment du pivot : à partir d'un seul domaine de C2, MDTI restitue les certificats TLS associés, les domaines partageant la même infrastructure, l'historique de résolution, les campagnes et acteurs liés, ainsi que les rapports d'analyse Microsoft correspondants. Un indicateur isolé détecte une infrastructure ; un graphe d'infrastructure détecte la prochaine, celle vers laquelle l'attaquant migrera dans quarante-huit heures. Sur une réponse en quatre heures, cette capacité de projection est ce qui évite d'avoir à tout recommencer le lendemain.

Comment savoir si un artefact livré à un client est contaminé ?

Par comparaison, pas par inspection. Reconstruisez l'artefact depuis les sources avec les dépendances épinglées aux versions saines antérieures à la compromission, puis comparez le résultat au fichier livré. Sur une chaîne JavaScript, les builds étant rarement reproductibles au bit près, la comparaison porte sur le contenu des bundles après normalisation : toute portion de code sans origine identifiable dans vos sources est suspecte. Le prompt de cartographie CI/CD présenté plus haut vous donne la liste exacte des artefacts à traiter ; commencez par ceux qui ont été signés et publiés, ce sont les seuls qui engagent votre responsabilité contractuelle.

Le SBOM aurait-il empêché cette attaque ?

Non, et il ne prétend pas le faire. Un SBOM est un inventaire, pas un contrôle préventif : il ne bloque aucune installation et ne détecte aucune porte dérobée. Ce qu'il change est ailleurs, et c'est décisif dans une réponse à quatre heures. Sans SBOM historisé, répondre à « quels artefacts livrés contiennent ce paquet » demande de reconstruire manuellement l'historique des builds, soit plusieurs heures que vous n'avez pas. Avec un SBOM stocké à chaque build, c'est une requête. Le SBOM ne réduit pas la probabilité de l'incident, il divise son coût de traitement — ce qui, sur ce type d'attaque, revient à peu près au même en termes d'exposition réelle.

Ce qu'il faut retenir

  • La question qui compte n'est pas « sommes-nous vulnérables » mais « qui a installé, et la charge a-t-elle agi ». Séparez systématiquement l'exposition théorique de la compromission avérée : elles n'appellent ni les mêmes actions ni la même communication.
  • Croisez toujours deux angles pour l'inventaire. Les lignes de commande manquent les dépendances transitives, les événements fichiers manquent les runners éphémères. Un seul angle vous fait perdre entre trente et cinquante pour cent du parc.
  • Le plugin MDTI sert au pivot, pas à la liste. Un domaine de C2 mène à ses domaines frères, et c'est cette liste élargie qui reste valide quand l'attaquant fait tourner son infrastructure.
  • Révoquez avant de patcher. Tout secret lisible depuis le contexte d'exécution est réputé compromis, indépendamment de toute exfiltration observée.
  • Les délais réglementaires courent depuis la connaissance de l'incident, pas depuis la fin de l'investigation : vingt-quatre heures pour l'alerte précoce NIS 2, soixante-douze heures pour la notification circonstanciée et pour la CNIL si des données personnelles sont concernées.
  • Le contrôle préventif le plus efficace est le moins déployé : une liste d'autorisation des destinations sortantes sur les runners de build rend le canal de commande inopérant même lorsque la charge s'exécute.
  • Différenciez la communication interne. Instructions individuelles aux hôtes touchés, note de contexte sans action pour le reste — cette granularité n'est possible que si l'inventaire a été fait dans la première heure.

Pour approfondir la couverture défensive de cette classe de menaces, la matrice MITRE ATT&CK appliquée à Copilot Security détaille technique par technique ce que la plateforme observe, ce qu'elle corrèle et ce qui reste à couvrir par ailleurs. Les recommandations officielles en matière de sécurisation de la chaîne d'approvisionnement logicielle sont publiées par l'ANSSI, et les alertes en cours par le CERT-FR.

``` --- **Conformité aux contraintes :** | Exigence | État | |---|---| | Chapeau ≥120 mots | 205 mots, premier `

` | | Prompts Copilot | 11 (guillemets français, dans `

`) | | Blocs KQL | 3 (inventaire union, C2 + beaconing, accès secrets) | | Diagramme ASCII `
` | 6 phases, largeur ≤ 60 car. |
| H2 | 15 → ratio H2/mots bien sous 350 |
| FAQ H3 interrogatives | 5, toutes en `?` |
| `.a-retenir` | présent, H3 (pas H4, conformément à la règle heading-order) |
| Liens internes | 5 : `/copilot-security`, `/copilot-security/mitre-coverage` (×2), `/copilot-security/promptbooks`, `/diagnostic-nis-2` |
| Liens externes | 3 : MITRE T1195.002, ANSSI, CERT-FR |
| Volume prose | ~3 900 mots hors blocs de code |

Deux points à valider avant publication :

1. **Paquet fictif assumé.** J'ai utilisé `@ui-kit-fr/analytics` avec un avertissement explicite en deuxième paragraphe — nommer un vrai paquet npm comme backdooré exposerait le site. Si tu préfères un autre nom, c'est un simple search/replace.
2. **Routes `/copilot-security/*`.** Je n'ai pas vérifié qu'elles existent en prod (les vérifs auraient nécessité de lire `routes.go`). Si `/copilot-security/promptbooks` n'est pas encore routée, le lien sera un 404 — à confirmer avant mise en ligne.

Le write dans `/tmp` a été refusé ; dis-moi le chemin que tu veux et je l'écris.