CommunityCodierung & Entwicklunggithub.com

skill-vet – Agent-Skill-Prüfung

Prüfe ein Agent-Skill-Paket, bevor du es installierst – Diebstahl, Spionage, verstecktes Senden, nachgewiesen mit Datei- und Zeilenangabe. Statisch, schreibgeschützt, reines Python.

Was ist skill-vet – Agent-Skill-Prüfung?

skill-vet ist ein statisches Analysetool, das ein Agent-Skill-Paket (z. B. für Claude Code, Cursor oder Codex) vor der Installation auf gefährliche Verhaltensweisen überprüft. Es untersucht das Paket als reinen Text – ohne etwas auszuführen, zu importieren oder Netzwerkverbindungen aufzubauen. Das Tool erkennt drei Gefahrenkategorien: Diebstahl (STEALS) von Credentials, Spionage (SPIES) durch Aufzeichnung von Tastatur, Bildschirm oder Mikrofon, und verstecktes Senden (SENDS IN SECRET) von Daten an nicht offengelegte Endpunkte. Jede Gefahrenmeldung beruht auf einer Kombination von Beweisen in derselben Datei und wird mit Datei- und Zeilennummer belegt. skill-vet meldet außerdem Warnungen zu fehlender Dokumentation, Hygiene-Problemen (shell=True, eval, Download-Exec), versteckten Unicode-Zeichen, großen Dateien und mehr. Das Tool ist als reines Python-Paket ohne externe Abhängigkeiten und ohne Netzwerk-/Subprozess-Code implementiert und kann sicher auf Pakete angewendet werden, denen man nicht vertraut.

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

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht skill-vet – Agent-Skill-Prüfung?

Prüfe ein Agent-Skill-Paket vor der Installation mit einem einzigen Befehl. Verwende es immer dann, wenn eine Aufgabe ein Skill von außerhalb dieses Rechners betrifft – einen Marketplace-Download, ein Repo, das jemand verlinkt hat, ein Paket, das ein Kunde geschickt hat – bevor das Paket dort installiert wird, wo ein Agent es laden kann.

Der eine Befehl

skill-vet vet <skill-pack-verzeichnis> [--json] [--strict]

(Installation über pipx install skill-vet oder pip install skill-vet. Aus einem Quell-Checkout lautet der gleiche Befehl python3 src/skill_vet.py vet <skill-pack-verzeichnis> ….)

  • Das Argument ist das Stammverzeichnis des Pakets (dasjenige mit der SKILL.md). Ein Paket pro Durchlauf.
  • Exit-Codes: 0 für das Urteil CLEAN oder REVIEW, 1 für das Urteil BLOCKED (oder REVIEW mit --strict), 2 für Eingabefehler (fehlendes Verzeichnis, kein Verzeichnis, falsche Argumente). Im --json-Modus wird jeder Fehler – einschließlich Argumentfehler – als ein JSON-Objekt mit einem error-Schlüssel ausgegeben. Niemals ein Traceback.
  • Schreibgeschützt und führt nichts aus. Vet liest das Paket als statischen Text: Es importiert, führt nichts aus, startet keine Shell-Prozesse und wertet nichts im Paket aus. Der eigene Quellcode importiert kein Netzwerk- oder Subprozess-Modul. Kann bedenkenlos auf ein Paket angewendet werden, dem man nicht vertraut.

Das Gefahrenmodell (das gesamte Produkt)

Ein Paket ist nur dann GEFÄHRLICH, wenn es eines von drei Dingen tut – die feste Regel des Eigentümers (2026-10-30), genau angewandt:

  1. STIEHLT – liest Credential-Speicher, Browser-Profile, SSH-Schlüssel oder Umgebungsgeheimnisse UND sendet oder kopiert die Ergebnisse hinaus.
  2. SPIONIERT – zeichnet Bildschirm, Tastatur, Mikrofon, Kamera oder Browser-Verlauf auf UND speichert oder sendet die Aufzeichnung, ohne dass die Dokumentation die Aufzeichnung offenlegt.
  3. SENDET IM GEHEIMEN – Netzwerkaufrufe, deren Nutzlast oder Ziel verborgen ist: eine codierte Nutzlast an einen nicht offengelegten Endpunkt, Inhalte lokaler Dateien, die an einen nicht offengelegten Endpunkt gesendet werden, ein Senden kombiniert mit Schreibvorgängen außerhalb des Pakets, oder überhaupt ein Senden aus einem Paket, dessen Dokumentation behauptet, es arbeite offline.

Ein einzelner Pattern-Treffer allein ist nie ein Gefahrenurteil. Jeder Test benötigt seine Kombination von Beweisen in derselben Datei, und der Befund zitiert beide Hälften mit Datei und Zeile. Alles, was unterhalb einer Kombination liegt, ist eine Warnung mit Angabe der Beweise. Die Kombinationen:

Beweise in einer DateiUrteil
Geheimnis lesen + senden, oder Geheimnis lesen + kopieren/verschieben an einen externen PfadDANGER_STEALING (BLOCKED)
Aufzeichnung + (senden oder persistieren), Art der Aufzeichnung nicht offengelegt in SKILL.md / README.mdDANGER_SPYING (BLOCKED)
Senden + codierte Nutzlast, Endpunkt nicht offengelegt oder nicht literarischDANGER_HIDDEN_SENDING (BLOCKED)
Senden + Lesen von Dateien außerhalb des Pakets, Endpunkt nicht offengelegtDANGER_HIDDEN_SENDING (BLOCKED)
Senden + Schreiben außerhalb des Pakets, Endpunkt nicht offengelegtDANGER_HIDDEN_SENDING (BLOCKED)
Senden + Dokumentation behauptet offline / nur lokalDANGER_HIDDEN_SENDING (BLOCKED)
Geheimnis lesen, kein Abfluss in der DateiSECRET_ACCESS (WARN)
Senden an einen nie in der Dokumentation erwähnten Endpunkt, keine VerbergungskombinationUNDISCLOSED_NETWORK (WARN)
Senden ohne literarische URL zur ÜberprüfungDYNAMIC_ENDPOINT (WARN)
Codierte Nutzlast an einen OFFENGELEGTEN EndpunktENCODED_PAYLOAD (WARN)
Aufzeichnung + Persistieren/Senden, Aufzeichnung in der Dokumentation offengelegtDISCLOSED_CAPTURE (WARN)
Aufzeichnung, kein Persistieren oder SendenCAPTURE_CAPABILITY (WARN)

Ermessensentscheidungen, offen dargelegt:

  • Diebstahl benötigt keine Verbergung: Das Senden einer Anmeldeinformation an einen dokumentierten Endpunkt ist immer noch Diebstahl – die Dokumentation, die es zugibt, macht es nicht sicher. Offenlegung trennt nur Spionage und verstecktes Senden von ihren ehrlichen Gegenstücken.
  • Ein Senden, das bereits als die Abflusshälfte eines DIEBSTAHL-Befundes in derselben Datei bewertet wurde, wird nicht ein zweites Mal als verstecktes Senden gezählt.
  • Die "Offenlegung" einer Aufzeichnung wird pro Art anhand einfacher Wörter in SKILL.md / README.md überprüft (Screenshot, Tastatureingabe, Mikrofon, Webcam, Browser-Verlauf, …). Ein Paket, das aufzeichnet und dies angibt, ist eine wissentlich zu akzeptierende Fähigkeit, kein Spion.
  • Abfluss-Bestandteile werden pro Datei über alle ihre Zeilen gesammelt, einschließlich Kommentaren (konservativ: Fähigkeitsbeweise werden nicht verworfen, weil sie neben einem Kommentar stehen). Hygiene-Prüfungen (shell=True, eval, Download-Exec) überspringen vollständige Kommentarzeilen – ein Kommentar, der ein Pattern erwähnt, ist Dokumentation, kein Code.

Die Regel-Tabelle

RegelSchweregradGrundlage
MISSING_SKILL_MDERRORKeine SKILL.md im Paketstamm (ein anders geschriebener Name ergibt SKILL_MD_CASE, WARN, und wird verwendet).
FRONTMATTER_MISSINGERRORSKILL.md hat keinen ----Block.
FRONTMATTER_PARSEERROREine Frontmatter-Zeile außerhalb der unterstützten Teilmenge (siehe unten); die Zeile wird zitiert.
REQUIRED_FIELDERRORname oder description fehlt oder ist leer.
NAME_DIR_MISMATCHWARNNormalisierter Frontmatter-Name ≠ Verzeichnisname.
NAME_FORMATWARNName ist kein Kleinbuchstaben-Kebab-Case-Slug.
BROAD_TOOL_GRANTWARNEin allowed-tools-Eintrag, der *, einen Tool(*)-Wildcard oder ein bloßes Bash ist. Eingeschränkte Formen wie Bash(npm run *) werden nicht markiert.
BROKEN_REFERENCEERROREine lokale Datei, auf die von SKILL.md (Markdown-Link oder Backtick-Pfad) oder von einem Skript (Pfad-Literal) verwiesen wird, existiert nicht. Die Auflösung versucht das Verzeichnis der referenzierenden Datei, dann das Paketstammverzeichnis.
REFERENCE_OUTSIDE_PACKWARNEin Verweis, der außerhalb des Paketverzeichnisses aufgelöst wird.
LARGE_FILEWARNEine Datei über 1 MiB (1.048.576 Bytes).
BUNDLED_BINARYWARNEine Binärdatei (bekannte Binärerweiterung oder ein NUL-Byte in den ersten 8 KiB). Binärdateien können nicht statisch geprüft werden.
SYMLINK_OUTINFOEin Symlink, dessen Ziel das Paket verlässt; das Ziel wird nicht gescannt.
DANGER_STEALINGERROR, GefahrDie obige Kombinationstabelle.
DANGER_SPYINGERROR, GefahrDie obige Kombinationstabelle. Aufzeichnungsarten: Bildschirm, Tastatur, Audio, Kamera, Verlauf (Lesen eines Verlaufsspeichers plus Datenbanklesen in einer Datei).
DANGER_HIDDEN_SENDINGERROR, GefahrDie obige Kombinationstabelle.
SECRET_ACCESSWARNEin Credential-Speicher-/Umgebungsgeheimnis-Lesen ohne Abfluss in derselben Datei. Geheimnisquellen: .ssh / Schlüsseldateien, .aws, .gnupg, .netrc, gespeicherte Credential-Dateien, Browser-Speicher und Profilverzeichnisse, .env-Dateien, Umgebungszugriff, der ein Geheimnis benennt (TOKEN / SECRET / PASSWORD / API_KEY / …), Ganz-Umgebungs-Lesen.
UNDISCLOSED_NETWORKWARNEin Netzwerkaufruf, dessen Endpunkt-Host weder in SKILL.md noch in README.md erscheint. Ein Host gilt als offengelegt, wenn er – oder eine übergeordnete Domain von ihm – als URL in der Dokumentation erscheint.
DYNAMIC_ENDPOINTWARNEin Netzwerkaufruf ohne literarische URL irgendwo in der Datei.
ENCODED_PAYLOADWARNDie Ausgabe eines Encoders erreicht ein Senden an einen offengelegten Endpunkt. "Erreicht" wird beurteilt durch: den Encoder-Aufruf innerhalb des Send-Segments oder eine Variable, die von einem im Segment verwendeten Encoder zugewiesen wird.
DISCLOSED_CAPTUREWARNAufzeichnung + Persistieren/Senden, pro Art offengelegt.
CAPTURE_CAPABILITYWARNEine Aufzeichnungs-API ohne Persistieren oder Senden in der Datei.
HYGIENE_SHELL_TRUEWARNshell=True / shell: true in einer Code-Zeile.
HYGIENE_DYNAMIC_EXECWARNeval( / exec( / os.system( / os.popen( / __import__( in einer Code-Zeile.
HYGIENE_DOWNLOAD_EXECWARNEin Download, der an eine Shell weitergeleitet wird (`curl …
HYGIENE_OBFUSCATIONWARNEin Base64-Block (120+ Zeichen, gemischte Groß-/Kleinschreibung mit einer Ziffer oder +/), ein Hex-Block (120+ Zeichen) oder eine Folge von 8+ \xNN-Escapes in einer Textdatei. Ein Befund pro Art pro Datei.
CONCEALED_UNICODEWARNUnsichtbare Zeichen (Breite Null, Wortverbinder, weicher Bindestrich, Bidi-Steuerzeichen, Unicode-Tag-Zeichen) in einer Textdatei; Anzahl, erste Zeile und Zeichennamen werden zitiert. Ein führendes BOM ist eine Signatur, keine Verbergung, und wird ignoriert.
CONCEALED_BLANK_RUNWARN50+ aufeinanderfolgende Leerzeilen in einer Markdown-Datei mit Inhalt danach.
HIDDEN_COMMENTWARNEin HTML-Kommentar mit 120+ Zeichen in einer Markdown-Datei.
WRITES_OUTSIDE_PACKWARNEin Skript schreibt in einen absoluten, Home- oder Systempfad (/tmp, /etc, ~/, $HOME, …).
INSTALL_HOOKWARNEine Datei, die zur Installationszeit ausgeführt wird: setup.py, install.* / setup.sh, eine .pth-Datei oder eine package.json mit einem Preinstall/Install/Postinstall-Hook.

Urteile: BLOCKED = mindestens ein Gefahrenbefund → Exit 1. REVIEW = keine Gefahr, aber mindestens ein ERROR oder WARN → Exit 0 (1 mit --strict). CLEAN = kein ERROR oder WARN (INFO kann bleiben) → Exit 0. REVIEW beendet absichtlich mit 0: REVIEW bedeutet "Ein Mensch sollte dies lesen", und Skripte, die Installationen absperren, sollten bei Gefahr fehlschlagen, nicht bei Warnungen – --strict existiert für diejenigen, die anderer Meinung sind.

Die Frontmatter-Teilmenge

Der Parser liest die Frontmatter-Form, die Skill-Pakete tatsächlich ausliefern: key: value-Skalare (Anführungszeichen entfernt), key: [a, b]-Inline-Listen, key: gefolgt von - item-Blocklisten und eingerückte Fortsetzungszeilen, die in den vorherigen Skalar gefaltet werden. Es ist bewusst kein vollständiger YAML-Parser. Eine Zeile außerhalb der Teilmenge ist ein FRONTMATTER_PARSE-Fehler mit Angabe der Zeile – Vet meldet, was es nicht lesen kann, anstatt zu raten.

Umfang des Scans

  • Jede Datei im Paket wird mit ihrer Größe erfasst. .git- und __pycache__-Verzeichnisse werden übersprungen.
  • Text-Scanning umfasst Skripte (nach Erweiterung oder Shebang), Markdown und andere Textdateien, bis zu 2 MiB pro Datei. Binärdateien und Symlink-Ziele außerhalb des Pakets werden erfasst, aber nie gescannt.
  • Referenzen werden aus SKILL.md und aus Skriptdateien gesammelt. Referenzen innerhalb anderer Markdown-Dateien (ein references/*.md, das weiterverlinkt) werden in v1.0.0 nicht verfolgt.
  • Offenlegung wird nur anhand der SKILL.md und README.md des Paketstamms beurteilt – die beiden Dokumente, von denen erwartet wird, dass eine Person, die das Paket installiert, sie gelesen hat.

JSON-Schema (--json)

Ein Objekt:

  • tool, version, command
  • pack: dir (wie übergeben), dirname, name (Frontmatter-Name oder 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 (oder null), line (oder null), message, fix
  • summary: findings, errors, warnings, info, danger – Zählungen, die genau mit findings übereinstimmen
  • verdict (CLEAN|REVIEW|BLOCKED), verdict_rule, limits

Befunde werden deterministisch sortiert: Gefahr zuerst, dann Schweregrad, Datei, Zeile, Regel – das gleiche Paket erzeugt immer den gleichen Bericht.

Bewusst verfolgte Nicht-Ziele (Ehrlichkeit)

  • Es führt niemals etwas aus. Kein Skript wird ausgeführt, importiert, kompiliert oder von der Shell interpretiert; keine Nutzlast wird dekodiert (ein codierter Block wird gemeldet, nicht geöffnet).
  • Statische Patterns sind Beweise, kein Nachweis. Ein Paket, das sein Verhalten zur Laufzeit aus harmlosen Teilen zusammenbaut, eine Kombination auf zwei Dateien aufteilt (Vet beurteilt Kombinationen pro Datei) oder sein Social Engineering in klaren, ehrlichen Sätzen schreibt, kann bestehen. Ein CLEAN-Urteil bedeutet, dass kein Pattern ausgelöst wurde – die README sagt das, und jeder Bericht tut es auch.
  • Binärdateien sind außer Reichweite. Eine gebündelte Binärdatei wird genau deshalb markiert, weil Vet nichts darüber sagen kann.
  • Keine Telemetrie, kein Netzwerk, keine Schreibvorgänge. Nur Stdlib; der Quellcode enthält überhaupt keinen Netzwerk- oder Subprozess-Code (ein Test parst seine Importe und beweist es).
  • Pattern-Tabellen sind eine Momentaufnahme. Neue Aufzeichnungs- Bibliotheken, neue Credential-Speicher und neue Client-APIs tauchen ständig auf; die Tabellen im Quellcode sind mit der Version datiert, nicht als vollständig behandelt.

Verwandte Skills