skill-vet — Compétence d'agent

Analysez une compétence d'agent avant de l'installer — vol, espionnage, envoi caché, avec preuves fichier et ligne. Statique, en lecture seule, pur Python.

Qu'est-ce que skill-vet — Compétence d'agent ?

skill-vet est un outil de sécurité statique conçu pour analyser une compétence d'agent (skill pack) avant de l'installer, en détectant trois grands types de comportements dangereux : le vol de secrets (credentials, clés SSH, variables d'environnement), l'espionnage (capture d'écran, clavier, micro, caméra, historique de navigation) et l'envoi caché de données (payload encodé vers un endpoint non divulgué, envoi combiné à des lectures/écritures hors du pack). Il fonctionne comme un outil de ligne de commande unique `skill-vet vet <dossier>` qui lit le pack de manière statique, sans jamais exécuter, importer ou exécuter quoi que ce soit. Il utilise une table de règles combinatoires : un seul motif ne suffit pas, il faut la preuve d'une combinaison dans le même fichier (par exemple, une lecture de secret + un envoi réseau). Le verdict final est CLEAN (aucun problème), REVIEW (au moins un avertissement, nécessite une lecture humaine) ou BLOCKED (danger détecté, sortie de code 1). Il prend en charge un mode JSON pour une intégration automatisée et contient des contrôles d'hygiène (shell=True, eval, download-exec, obfuscation, unicode caché). Il est écrit en pur Python, sans dépendances réseau ni sous-processus, et ne produit pas de télémétrie.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jasveerai88/skill-vet/tree/HEAD

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Que fait skill-vet — Compétence d'agent ?

Analysez une compétence d'agent avant de l'installer, avec une seule commande. Utilisez-la chaque fois qu'une tâche implique une compétence provenant de l'extérieur de cette machine — un téléchargement depuis un marché, un dépôt lié par quelqu'un, un pack envoyé par un client — avant que le pack ne soit installé là où un agent le chargera.

La commande unique

skill-vet vet <dossier-du-pack> [--json] [--strict]

(Installé via pipx install skill-vet ou pip install skill-vet. Depuis une extraction source, la même commande est python3 src/skill_vet.py vet <dossier-du-pack> ….)

  • L'argument est le dossier racine du pack (celui contenant SKILL.md). Un pack par exécution.
  • Codes de sortie : 0 verdict PROPRE ou REVISION, 1 verdict BLOQUE (ou REVISION avec --strict), 2 erreur d'entrée (dossier manquant, pas un dossier, mauvais arguments). En mode --json, chaque erreur — y compris les erreurs d'argument — est un objet JSON avec une clé error. Jamais de traceback.
  • Lecture seule, et n'exécute rien. Vet lit le pack en tant que texte statique : il n'importe jamais, n'exécute jamais, ne lance jamais de shell ni n'évalue quoi que ce soit dans le pack. Son propre source n'importe aucun module réseau ou sous-processus. Sûr de pointer vers un pack que vous ne faites pas confiance.

Le modèle de danger (la totalité du produit)

Un pack est DANGEREUX seulement s'il fait une de ces trois choses — la règle permanente du propriétaire (30/10/2026), appliquée exactement :

  1. VOLE — lit les magasins de credentials, les profils de navigateur, les clés SSH ou les secrets d'environnement ET envoie ou copie les résultats à l'extérieur.
  2. ESPIONNE — capture écran, clavier, microphone, caméra ou historique de navigateur ET persiste ou envoie la capture, sans que les documents ne divulguent la capture.
  3. ENVOIE EN SECRET — appels réseau dont le contenu ou la destination est cachée : un payload encodé vers un endpoint non divulgué, le contenu d'un fichier local envoyé vers un endpoint non divulgué, un envoi combiné à des écritures hors du pack, ou tout envoi d'un pack dont les documents prétendent qu'il fonctionne hors ligne.

Un seul motif n'est jamais un verdict de danger. Chaque test a besoin de sa combinaison de preuves dans le même fichier, et la conclusion cite les deux moitiés avec fichier et ligne. Tout ce qui n'est pas une combinaison est un avertissement avec les preuves énoncées. Les combinaisons :

Preuves dans un même fichierVerdict
lecture de secret + envoi, ou lecture de secret + copie/déplacement vers un chemin extérieurDANGER_STEALING (BLOQUE)
capture + (envoi ou persistance), type de capture non divulgué dans SKILL.md / README.mdDANGER_SPYING (BLOQUE)
envoi + payload encodé, endpoint non divulgué ou non littéralDANGER_HIDDEN_SENDING (BLOQUE)
envoi + lecture de fichiers hors du pack, endpoint non divulguéDANGER_HIDDEN_SENDING (BLOQUE)
envoi + écriture hors du pack, endpoint non divulguéDANGER_HIDDEN_SENDING (BLOQUE)
envoi + documents prétendent hors ligne / local uniquementDANGER_HIDDEN_SENDING (BLOQUE)
lecture de secret, pas d'envoi dans le fichierSECRET_ACCESS (AVERTISSEMENT)
envoi vers un endpoint que les documents ne mentionnent jamais, sans combinaison de dissimulationUNDISCLOSED_NETWORK (AVERTISSEMENT)
envoi sans URL littérale à vérifierDYNAMIC_ENDPOINT (AVERTISSEMENT)
payload encodé vers un endpoint DIVULGUEENCODED_PAYLOAD (AVERTISSEMENT)
capture + persistance/envoi, capture divulguée dans les documentsDISCLOSED_CAPTURE (AVERTISSEMENT)
capture, sans persistance ni envoiCAPTURE_CAPABILITY (AVERTISSEMENT)

Jugements, énoncés ouvertement :

  • Le vol n'a pas besoin de dissimulation : envoyer un credential vers un endpoint documenté reste du vol — le fait que les documents l'admettent ne le rend pas sûr. La divulgation ne sépare l'espionnage et l'envoi caché de leurs équivalents honnêtes.
  • Un envoi déjà jugé comme la moitié de sortie d'une découverte VOL dans le même fichier n'est pas compté une deuxième fois comme envoi caché.
  • La "divulgation" de capture est vérifiée par type par rapport à des mots simples dans SKILL.md / README.md (capture d'écran, frappe, microphone, webcam, historique de navigateur, …). Un pack qui capture et le dit est une capacité à accepter en connaissance de cause, pas un espion.
  • Les éléments de sortie (egress) sont collectés par fichier sur toutes ses lignes, y compris les commentaires (conservateur : la preuve de capacité n'est pas écartée parce qu'elle se trouve près d'un commentaire). Les vérifications d'hygiène (shell=True, eval, téléchargement-exécution) ignorent les lignes de commentaire complet — un commentaire mentionnant un motif est de la documentation, pas du code.

La table des règles

RègleSévéritéBase
MISSING_SKILL_MDERREURAbsence de SKILL.md à la racine du pack (un nom avec une casse différente génère SKILL_MD_CASE, AVERTISSEMENT, et est utilisé).
FRONTMATTER_MISSINGERREURSKILL.md n'a pas de bloc ---.
FRONTMATTER_PARSEERREURUne ligne de frontmatter en dehors du sous-ensemble pris en charge (voir ci-dessous) ; la ligne est citée.
REQUIRED_FIELDERREURname ou description manquant ou vide.
NAME_DIR_MISMATCHAVERTISSEMENTNom de frontmatter normalisé ≠ nom de dossier.
NAME_FORMATAVERTISSEMENTLe nom n'est pas une chaîne kebab-case en minuscules.
BROAD_TOOL_GRANTAVERTISSEMENTUne entrée allowed-tools qui est *, un joker Tool(*) ou un simple Bash. Les formes restreintes comme Bash(npm run *) ne sont pas signalées.
BROKEN_REFERENCEERREURUn fichier local référencé depuis SKILL.md (lien markdown ou chemin entouré de backticks) ou depuis un script (chemin littéral) n'existe pas. La résolution essaie le dossier du fichier référent, puis la racine du pack.
REFERENCE_OUTSIDE_PACKAVERTISSEMENTUne référence qui se résout en dehors du dossier du pack.
LARGE_FILEAVERTISSEMENTUn fichier de plus de 1 Mio (1 048 576 octets).
BUNDLED_BINARYAVERTISSEMENTUn fichier binaire (extension binaire connue, ou un octet NUL dans les 8 premiers Kio). Les binaires ne peuvent pas être analysés statiquement.
SYMLINK_OUTINFOUn lien symbolique dont la cible quitte le pack ; la cible n'est pas scannée.
DANGER_STEALINGERREUR, dangerLe tableau de combinaisons ci-dessus.
DANGER_SPYINGERREUR, dangerLe tableau de combinaisons ci-dessus. Types de capture : écran, clavier, audio, caméra, historique (une lecture de magasin d'historique plus une lecture de base de données dans un même fichier).
DANGER_HIDDEN_SENDINGERREUR, dangerLe tableau de combinaisons ci-dessus.
SECRET_ACCESSAVERTISSEMENTUne lecture de magasin de credentials / secret d'environnement sans envoi dans le même fichier. Sources de secrets : .ssh / fichiers de clés, .aws, .gnupg, .netrc, fichiers de credentials stockés, magasins et dossiers de profil de navigateur, fichiers .env, accès à l'environnement nommant un secret (TOKEN / SECRET / PASSWORD / API_KEY / …), lectures de tout l'environnement.
UNDISCLOSED_NETWORKAVERTISSEMENTUn appel réseau dont l'hôte de l'endpoint n'apparaît ni dans SKILL.md ni dans README.md. Un hôte est considéré comme divulgué quand lui — ou un domaine parent de lui — apparaît comme URL dans les documents.
DYNAMIC_ENDPOINTAVERTISSEMENTUn appel réseau sans URL littérale nulle part dans le fichier.
ENCODED_PAYLOADAVERTISSEMENTLa sortie d'un encodeur atteint un envoi vers un endpoint divulgué. "Atteint" est jugé par : l'appel à l'encodeur dans le segment d'appel de l'envoi, ou une variable assignée depuis un encodeur utilisée dans le segment.
DISCLOSED_CAPTUREAVERTISSEMENTCapture + persistance/envoi, divulguée par type.
CAPTURE_CAPABILITYAVERTISSEMENTUne API de capture sans persistance ni envoi dans le fichier.
HYGIENE_SHELL_TRUEAVERTISSEMENTshell=True / shell: true sur une ligne de code.
HYGIENE_DYNAMIC_EXECAVERTISSEMENTeval( / exec( / os.system( / os.popen( / __import__( sur une ligne de code.
HYGIENE_DOWNLOAD_EXECAVERTISSEMENTUn téléchargement redirigé vers un shell (`curl …
HYGIENE_OBFUSCATIONAVERTISSEMENTUn blob base64 (120+ caractères, mélange de casse avec un chiffre ou +/), un blob hex (120+ caractères), ou une série de 8+ séquences d'échappement \xNN, dans un fichier texte. Une constatation par type par fichier.
CONCEALED_UNICODEAVERTISSEMENTCaractères invisibles (taille nulle, jointure de mots, trait d'union souple, contrôles bidi, caractères de balise Unicode) dans un fichier texte ; nombre, première ligne et noms de caractères cités. Un BOM en tête de fichier est une signature, pas une dissimulation, et est ignoré.
CONCEALED_BLANK_RUNAVERTISSEMENT50+ lignes vides consécutives dans un fichier markdown avec du contenu après elles.
HIDDEN_COMMENTAVERTISSEMENTUn commentaire HTML de 120+ caractères dans un fichier markdown.
WRITES_OUTSIDE_PACKAVERTISSEMENTUn script écrit sur un chemin absolu, home ou système (/tmp, /etc, ~/, $HOME, …).
INSTALL_HOOKAVERTISSEMENTUn fichier qui s'exécute au moment de l'installation : setup.py, install.* / setup.sh, un fichier .pth, ou un package.json avec un hook preinstall/install/postinstall.

Verdicts : BLOQUE = au moins une constatation de danger → sortie 1. REVISION = pas de danger, mais au moins une ERREUR ou un AVERTISSEMENT → sortie 0 (1 avec --strict). PROPRE = aucune ERREUR ni AVERTISSEMENT (INFO peut subsister) → sortie 0. REVISION sort avec 0 intentionnellement : REVISION signifie "un humain devrait lire ceci", et les scripts qui bloquent les installations doivent échouer sur le danger, pas sur les avertissements — --strict existe pour ceux qui pensent le contraire.

Le sous-ensemble de frontmatter

L'analyseur lit la forme de frontmatter que les packs de compétences livrent réellement : cle: valeur scalaires (guillemets retirés), cle: [a, b] listes en ligne, cle: suivi de - item listes en bloc, et les lignes de continuation indentées repliées dans le scalaire précédent. Il n'est délibérément pas un analyseur YAML complet. Une ligne en dehors du sous-ensemble est une erreur FRONTMATTER_PARSE avec la ligne citée — vet signale ce qu'il ne peut pas lire plutôt que de deviner.

Portée de l'analyse

  • Chaque fichier dans le pack est inventorié avec sa taille. Les répertoires .git et __pycache__ sont ignorés.
  • L'analyse de texte couvre les scripts (par extension ou shebang), le markdown et autres fichiers texte, jusqu'à 2 Mio par fichier. Les fichiers binaires et les cibles de liens symboliques hors du pack sont inventoriés, jamais analysés.
  • Les références sont collectées à partir de SKILL.md et des fichiers de script. Les références à l'intérieur d'autres fichiers markdown (un lien references/*.md pointant plus loin) ne sont pas suivies dans v1.0.0.
  • La divulgation est jugée d'après le SKILL.md et le README.md de la racine du pack uniquement — les deux documents qu'une personne installant le pack est censée avoir lus.

Schéma JSON (--json)

Un objet :

  • tool, version, command
  • pack: dir (tel que passé), dirname, name (nom de frontmatter ou null), skill_file
  • files[]: path, bytes, kind (script|markdown|text|binary|other), binary, scanned, symlink_out
  • findings[]: rule, severity (ERROR|WARN|INFO), danger (bool), file (ou null), line (ou null), message, fix
  • summary: findings, errors, warnings, info, danger — des comptes qui correspondent exactement à findings
  • verdict (CLEAN|REVIEW|BLOCKED), verdict_rule, limits

Les constatations sont triées de manière déterministe : danger d'abord, puis sévérité, fichier, ligne, règle — le même pack produit toujours le même rapport.

Objectifs délibérément non visés (honnêteté)

  • Il n'exécute jamais rien. Aucun script n'est exécuté, importé, compilé, ni analysé par le shell ; aucun payload n'est décodé (un blob encodé est signalé, pas ouvert).
  • Les motifs statiques sont des preuves, pas une certitude. Un pack qui assemble son comportement à l'exécution à partir de pièces anodines, qui répartit une combinaison sur deux fichiers (vet juge les combinaisons par fichier), ou qui écrit son ingénierie sociale en phrases simples et honnêtes peut passer. Un verdict PROPRE signifie qu'aucun motif ne s'est déclenché — le README le dit, et chaque rapport aussi.
  • Les binaires sont hors de portée. Un binaire intégré est signalé précisément parce que vet ne peut rien en dire.
  • Pas de télémétrie, pas de réseau, pas d'écritures. Stdlib uniquement ; le source ne contient aucun code réseau ou sous-processus (un test analyse ses imports et le prouve).
  • Les tables de motifs sont un instantané. De nouvelles bibliothèques de capture, de nouveaux magasins de credentials et de nouvelles API client apparaissent constamment ; les tables dans le source sont datées par la version, pas considérées comme complètes.

Skills associés