skill-vet — verificação de skill de agente

Verifique um pacote de skill de agente antes de instalá-lo — roubo, espionagem, envio oculto, comprovado com evidências de arquivo e linha. Estático, somente leitura, Python puro.

O que é skill-vet — verificação de skill de agente?

O skill-vet é uma ferramenta de segurança estática para verificar pacotes de skill de agente antes da instalação. Ele examina o código-fonte do pacote em busca de três classes principais de perigo: roubo de credenciais com exfiltração de dados, captura oculta de tela/teclado/microfone/câmera com persistência ou envio, e envio de rede oculto com payloads codificados ou endpoints não divulgados. A ferramenta é totalmente somente leitura e não executa nada — ela analisa arquivos como texto puro, sem importar, executar ou fazer shell. Ela suporta saída JSON para integração com scripts e inclui uma tabela de 30 regras que cobrem desde verificações de higiene (shell=true, eval, download-exec) até validação de frontmatter e referências quebradas. O skill-vet é ideal para estações de trabalho de desenvolvedores, pipelines de CI/CD e mercados de skills onde pacotes de fontes externas precisam ser verificados antes de serem carregados por um agente.

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

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

skill-vet — skill de agente

Verifique um pacote de skill de agente antes de instalá-lo, com um comando. Use-o sempre que uma tarefa envolver uma skill de fora desta máquina — um download do marketplace, um repositório que alguém linkou, um pacote que um cliente enviou — antes que o pacote seja instalado em qualquer lugar onde um agente o carregará.

O comando único

skill-vet vet <pasta-do-pacote-de-skill> [--json] [--strict]

(Instalado via pipx install skill-vet ou pip install skill-vet. A partir de um checkout da fonte, o mesmo comando é python3 src/skill_vet.py vet <pasta-do-pacote-de-skill> ….)

  • O argumento é a pasta raiz do pacote (aquela que contém SKILL.md). Um pacote por execução.
  • Códigos de saída: 0 veredito CLEAN ou REVIEW, 1 veredito BLOCKED (ou REVIEW com --strict), 2 erro de entrada (pasta ausente, não é uma pasta, argumentos inválidos). No modo --json, todo erro — incluindo erros de argumento — é um objeto JSON com uma chave error. Nunca um traceback.
  • Somente leitura, e não executa nada. O Vet lê o pacote como texto estático: nunca importa, executa, chama shell ou avalia nada no pacote. Sua própria fonte não importa módulos de rede ou subprocesso. Seguro para apontar para um pacote no qual você ativamente desconfia.

O modelo de perigo (o produto completo)

Um pacote é PERIGOSO apenas se fizer uma de três coisas — a regra fixa do proprietário (2026-10-30), aplicada exatamente:

  1. ROUBA — lê armazenamentos de credenciais, perfis de navegador, chaves SSH ou segredos de ambiente E envia ou copia os resultados para fora.
  2. ESPIA — captura tela, teclado, microfone, câmera ou histórico do navegador E persiste ou envia a captura, sem que a documentação divulgue a captura.
  3. ENVIA EM SEGREDO — chamadas de rede cujo payload ou destino está oculto: um payload codificado para um endpoint não divulgado, conteúdo de arquivo local enviado para um endpoint não divulgado, um envio combinado com gravações fora do pacote, ou qualquer envio de um pacote cuja documentação afirma que funciona offline.

Um padrão isolado nunca é um veredito de perigo. Cada teste precisa de sua combinação de evidências no mesmo arquivo, e a descoberta cita ambas as metades com arquivo e linha. Qualquer coisa abaixo de uma combinação é um aviso com a evidência declarada. As combinações:

Evidência em um arquivoVeredito
leitura de segredo + envio, ou leitura de segredo + cópia/movimento para um caminho externoDANGER_STEALING (BLOCKED)
captura + (envio ou persistência), tipo de captura não divulgado em SKILL.md / README.mdDANGER_SPYING (BLOCKED)
envio + payload codificado, endpoint não divulgado ou não literalDANGER_HIDDEN_SENDING (BLOCKED)
envio + leitura de arquivos fora do pacote, endpoint não divulgadoDANGER_HIDDEN_SENDING (BLOCKED)
envio + gravação fora do pacote, endpoint não divulgadoDANGER_HIDDEN_SENDING (BLOCKED)
envio + documentação afirma offline / apenas localDANGER_HIDDEN_SENDING (BLOCKED)
leitura de segredo, sem egresso no arquivoSECRET_ACCESS (WARN)
envio para um endpoint que a documentação nunca menciona, sem combinação de ocultaçãoUNDISCLOSED_NETWORK (WARN)
envio sem URL literal para verificarDYNAMIC_ENDPOINT (WARN)
payload codificado para um endpoint DIVULGADOENCODED_PAYLOAD (WARN)
captura + persistência/envio, captura divulgada na documentaçãoDISCLOSED_CAPTURE (WARN)
captura, sem persistência ou envioCAPTURE_CAPABILITY (WARN)

Julgamentos, declarados abertamente:

  • Roubo não precisa de ocultação: enviar uma credencial para um endpoint documentado ainda é roubo — a documentação admitir isso não o torna seguro. A divulgação apenas separa espionagem e envio oculto de suas contrapartes honestas.
  • Um envio já julgado como a metade de egresso de uma descoberta de ROUBO no mesmo arquivo não é contado uma segunda vez como envio oculto.
  • A "divulgação" de captura é verificada por tipo contra palavras simples em SKILL.md / README.md (screenshot, keystroke, microphone, webcam, browser history, …). Um pacote que captura e diz isso é uma capacidade a ser aceita conscientemente, não um espião.
  • Os ingredientes de egresso são coletados por arquivo em todas as suas linhas, incluindo comentários (conservador: a evidência de capacidade não é descartada porque está perto de um comentário). As verificações de higiene (shell=True, eval, download-exec) pulam comentários de linha completa — um comentário mencionando um padrão é documentação, não código.

A tabela de regras

RegraGravidadeBase
MISSING_SKILL_MDERRORNenhum SKILL.md na raiz do pacote (um nome com caixa diferente gera SKILL_MD_CASE, WARN, e é usado).
FRONTMATTER_MISSINGERRORSKILL.md não tem bloco ---.
FRONTMATTER_PARSEERRORUma linha de frontmatter fora do subconjunto suportado (veja abaixo); a linha é citada.
REQUIRED_FIELDERRORname ou description ausente ou vazio.
NAME_DIR_MISMATCHWARNNome do frontmatter normalizado ≠ nome da pasta.
NAME_FORMATWARNO nome não é um slug kebab-case minúsculo.
BROAD_TOOL_GRANTWARNUma entrada allowed-tools que é *, um curinga Tool(*) ou um Bash simples. Formas com escopo como Bash(npm run *) não são sinalizadas.
BROKEN_REFERENCEERRORUm arquivo local referenciado de SKILL.md (link markdown ou caminho entre crases) ou de um script (literal de caminho) não existe. A resolução tenta a pasta do arquivo de referência, depois a raiz do pacote.
REFERENCE_OUTSIDE_PACKWARNUma referência resolvendo fora da pasta do pacote.
LARGE_FILEWARNUm arquivo acima de 1 MiB (1.048.576 bytes).
BUNDLED_BINARYWARNUm arquivo binário (extensão binária conhecida ou um byte NUL nos primeiros 8 KiB). Binários não podem ser verificados estaticamente.
SYMLINK_OUTINFOUm link simbólico cujo destino sai do pacote; o destino não é escaneado.
DANGER_STEALINGERROR, dangerA tabela de combinação acima.
DANGER_SPYINGERROR, dangerA tabela de combinação acima. Tipos de captura: tela, teclado, áudio, câmera, histórico (uma leitura de armazenamento de histórico mais uma leitura de banco de dados em um arquivo).
DANGER_HIDDEN_SENDINGERROR, dangerA tabela de combinação acima.
SECRET_ACCESSWARNUma leitura de armazenamento de credenciais / segredo de ambiente sem egresso no mesmo arquivo. Fontes de segredo: .ssh / arquivos de chave, .aws, .gnupg, .netrc, arquivos de credenciais armazenadas, armazenamentos de navegador e pastas de perfil, arquivos .env, acesso de ambiente nomeando um segredo (TOKEN / SECRET / PASSWORD / API_KEY / …), leituras de ambiente inteiro.
UNDISCLOSED_NETWORKWARNUma chamada de rede cujo host do endpoint não aparece nem em SKILL.md nem em README.md. Um host conta como divulgado quando ele — ou um domínio pai dele — aparece como uma URL na documentação.
DYNAMIC_ENDPOINTWARNUma chamada de rede sem URL literal em nenhum lugar do arquivo.
ENCODED_PAYLOADWARNA saída de um codificador atinge um envio para um endpoint divulgado. "Atinge" é julgado por: a chamada do codificador dentro do segmento de chamada do envio, ou uma variável atribuída de um codificador usada no segmento.
DISCLOSED_CAPTUREWARNCaptura + persistência/envio, divulgado por tipo.
CAPTURE_CAPABILITYWARNUma API de captura sem persistência ou envio no arquivo.
HYGIENE_SHELL_TRUEWARNshell=True / shell: true em uma linha de código.
HYGIENE_DYNAMIC_EXECWARNeval( / exec( / os.system( / os.popen( / __import__( em uma linha de código.
HYGIENE_DOWNLOAD_EXECWARNUm download canalizado para um shell (`curl …
HYGIENE_OBFUSCATIONWARNUm blob base64 (120+ caracteres, maiúsculas e minúsculas misturadas com um dígito ou +/), um blob hex (120+ caracteres) ou uma sequência de 8+ escapes \xNN, em um arquivo de texto. Uma descoberta por tipo por arquivo.
CONCEALED_UNICODEWARNCaracteres invisíveis (largura zero, juntador de palavras, hífen suave, controles bidirecionais, caracteres de tag Unicode) em um arquivo de texto; contagem, primeira linha e nomes de caracteres citados. Um BOM inicial é uma assinatura, não ocultação, e é ignorado.
CONCEALED_BLANK_RUNWARN50+ linhas em branco consecutivas em um arquivo markdown com conteúdo após elas.
HIDDEN_COMMENTWARNUm comentário HTML de 120+ caracteres em um arquivo markdown.
WRITES_OUTSIDE_PACKWARNUm script grava em um caminho absoluto, home ou do sistema (/tmp, /etc, ~/, $HOME, …).
INSTALL_HOOKWARNUm arquivo que é executado no momento da instalação: setup.py, install.* / setup.sh, um arquivo .pth, ou um package.json com um hook preinstall/install/postinstall.

Vereditos: BLOCKED = pelo menos uma descoberta de perigo → saída 1. REVIEW = nenhum perigo, mas pelo menos um ERROR ou WARN → saída 0 (1 com --strict). CLEAN = nenhum ERROR ou WARN (INFO pode permanecer) → saída 0. REVIEW sai 0 de propósito: REVIEW significa "um humano deve ler isso", e scripts que bloqueiam instalações devem falhar em perigo, não em avisos — --strict existe para quem discorda.

O subconjunto de frontmatter

O analisador lê a forma de frontmatter que os pacotes de skill realmente enviam: escalares chave: valor (aspas removidas), chave: [a, b] listas inline, chave: seguido por - item listas em bloco e linhas de continuação indentadas dobradas no escalar anterior. Ele é deliberadamente não um analisador YAML completo. Uma linha fora do subconjunto é um erro FRONTMATTER_PARSE com a linha citada — o vet relata o que não pode ler em vez de adivinhar.

Escopo da varredura

  • Cada arquivo no pacote é inventariado com seu tamanho. Diretórios .git e __pycache__ são pulados.
  • A varredura de texto cobre scripts (por extensão ou shebang), markdown e outros arquivos de texto, até 2 MiB por arquivo. Arquivos binários e alvos de link simbólico fora do pacote são inventariados, nunca escaneados.
  • Referências são coletadas de SKILL.md e de arquivos de script. Referências dentro de outros arquivos markdown (um references/*.md linkando adiante) não são seguidas no v1.0.0.
  • A divulgação é julgada contra o SKILL.md e README.md da raiz do pacote apenas — os dois documentos que uma pessoa instalando o pacote deve ter lido.

Esquema JSON (--json)

Um objeto:

  • tool, version, command
  • pack: dir (como passado), dirname, name (nome do 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 — contagens que recontam exatamente contra findings
  • verdict (CLEAN|REVIEW|BLOCKED), verdict_rule, limits

As descobertas são ordenadas deterministicamente: perigo primeiro, depois gravidade, arquivo, linha, regra — o mesmo pacote sempre produz o mesmo relatório.

Não-objetivos deliberados (honestidade)

  • Nunca executa nada. Nenhum script é executado, importado, compilado ou analisado por shell; nenhum payload é decodificado (um blob codificado é relatado, não aberto).
  • Padrões estáticos são evidência, não prova. Um pacote que monta seu comportamento em tempo de execução a partir de peças inofensivas, divide uma combinação entre dois arquivos (o vet julga combinações por arquivo) ou escreve sua engenharia social em frases simples e honestas pode passar. Um veredito CLEAN significa que nenhum padrão disparou — o README diz isso, e todo relatório também.
  • Binários estão fora de alcance. Um binário empacotado é sinalizado precisamente porque o vet não pode dizer nada sobre ele.
  • Sem telemetria, sem rede, sem gravações. Apenas stdlib; a fonte não contém código de rede ou subprocesso (um teste analisa suas importações e prova isso).
  • Tabelas de padrões são uma foto instantânea. Novas bibliotecas de captura, novos armazenamentos de credenciais e novas APIs de cliente aparecem constantemente; as tabelas na fonte são datadas pela versão, não tratadas como completas.

Habilidades Relacionadas