
SkillSpector v2.10.0
Escáner de seguridad para habilidades de agentes de IA. Detecta vulnerabilidades, patrones maliciosos, riesgos de seguridad, inyección de prompt, exfiltración de datos y riesgos de la cadena de suministro en las habilidades de Claude Code, Codex y MCP antes de instalarlas.
SkillSpector
Escáner de seguridad para habilidades de agentes de IA. Detecta vulnerabilidades, patrones maliciosos y riesgos de seguridad antes de instalar habilidades de agentes.
Descripción general
Las habilidades de agentes de IA (utilizadas por Claude Code, Codex CLI, Gemini CLI, etc.) se ejecutan con confianza implícita y una verificación mínima. Las investigaciones muestran que el 26.1% de las habilidades contienen vulnerabilidades y el 5.2% muestran una posible intención maliciosa.
SkillSpector te ayuda a responder: "¿Es segura esta habilidad para instalar?"
SkillSpector forma parte del pipeline de NVIDIA Verified Skills, que escanea, evalúa y firma habilidades de agentes antes de su publicación. Las habilidades que pasan se publican en el catálogo de habilidades de NVIDIA.
Documentación
- Escanea habilidades de agentes antes de la instalación — Guía alojada: cuándo escanear, cómo leer un informe y cómo controlar las instalaciones.
- Guía de desarrollo — Arquitectura, estructura del paquete y cómo ampliar el pipeline del analizador.
- Extensión Pi — Instala SkillSpector como una herramienta Pi para escanear habilidades desde dentro de las sesiones de agentes.
Características
- Entrada multi-formato: Escanea repositorios Git, URLs, archivos zip, directorios o archivos individuales
- 68 patrones de vulnerabilidad en 17 categorías: inyección de prompts, exfiltración de datos, escalada de privilegios, cadena de suministro, agencia excesiva, manejo de salidas, fuga del prompt del sistema, envenenamiento de memoria, mal uso de herramientas, agente rogue, anti-rechazo, abuso de disparadores, código peligroso (AST), seguimiento de flujo de datos (taint tracking), firmas YARA, privilegio mínimo de MCP y envenenamiento de herramientas MCP
- Análisis en dos etapas: Análisis estático rápido + evaluación semántica opcional con LLM
- Consultas de vulnerabilidades en vivo: SC4 consulta OSV.dev para obtener datos CVE en tiempo real con respaldo automático sin conexión
- Múltiples formatos de salida: Informes en terminal, JSON, Markdown y SARIF
- Puntuación de riesgo: Puntuación de 0-100 con etiquetas de severidad y recomendaciones claras
- Supresión de falsos positivos / línea base: Acepta hallazgos conocidos mediante una regla glob o una línea base de huellas digitales para que los re-escaneos muestren solo problemas nuevos (docs)
Inicio rápido
Instalación
Aviso de software de código abierto: Este proyecto descargará e instalará proyectos de software de código abierto adicionales de terceros. Revisa los términos de licencia de estos proyectos de código abierto antes de su uso.
Crea y activa primero un entorno virtual (todos los objetivos de make asumen que el venv está activo). Usa uv o pip; el Makefile usa uv si está disponible; de lo contrario, usa pip.
Instalación rápida con uv (solo CLI):```bash uv tool install git+https://github.com/NVIDIA/skillspector.git
Update later: uv tool update skillspector
Si planeas ejecutar `skillspector mcp`, instala el extra de MCP en el momento de la instalación:```bash
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
Del código fuente:```bash
Clone the repository
git clone https://github.com/NVIDIA/skillspector.git cd skillspector
Create and activate virtual environment
uv venv .venv && source .venv/bin/activate
or: python3 -m venv .venv && source .venv/bin/activate
Install for production use
make install
Or install with development dependencies
make install-dev
### Docker (no se requiere Python)
Ejecuta SkillSpector sin instalar Python compilándolo localmente desde el [Dockerfile](https://github.com/nvidia/skillspector/blob/HEAD/Dockerfile) incluido. La imagen se basa en la imagen oficial de Docker Python `3.12-slim-bookworm`.
**Compilar la imagen:**```bash
make docker-build
# or: docker build -t skillspector .
Escanea un directorio local montando tu directorio actual en /scan, el directorio de trabajo del contenedor:```bash
docker run --rm -v "$PWD:/scan" skillspector scan ./my-skill/ --no-llm
**Escaneo con análisis LLM** pasando credenciales con un archivo local `.env`:```bash
cat > .env <<'EOF'
SKILLSPECTOR_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
EOF
## 🛡️ Características
- **Escaneo de puertos**: Detecta puertos abiertos y servicios en ejecución.
- **Detección de vulnerabilidades**: Identifica vulnerabilidades conocidas en los servicios detectados.
- **Fuerza bruta**: Prueba credenciales débiles en servicios como SSH, FTP y HTTP.
- **Generación de informes**: Genera informes detallados en formato HTML y JSON.
- **Interfaz de línea de comandos**: Fácil de usar y automatizable.
- **Soporte multiplataforma**: Funciona en Linux, macOS y Windows.
## 📦 Instalación
Para instalar la herramienta, clona el repositorio e instala las dependencias:
```bash
git clone https://github.com/example/repo.git
cd repo
pip install -r requirements.txt
🚀 Uso
Ejecuta la herramienta con el siguiente comando:
python tool.py --target example.com
Opciones disponibles
| Opción | Descripción |
|---|---|
--target | Especifica el objetivo a escanear (obligatorio). |
--ports | Define el rango de puertos a escanear (por defecto: 1-1000). |
--threads | Número de hilos a utilizar (por defecto: 10). |
--output | Ruta del archivo de salida para el informe. |
--verbose | Muestra información detallada durante el escaneo. |
Ejemplo
python tool.py --target example.com --ports 1-65535 --threads 50 --output report.html
📊 Salida
La herramienta genera un informe con los siguientes datos:
- Puertos abiertos y servicios asociados.
- Vulnerabilidades detectadas con su nivel de severidad.
- Recomendaciones para mitigar los riesgos encontrados.
🤝 Contribuciones
Las contribuciones son bienvenidas. Por favor, abre un issue o envía un pull request en el repositorio.
📄 Licencia
Este proyecto está bajo la licencia MIT. Consulta el archivo LICENSE para más detalles.
docker run --rm \
-v "$PWD:/scan" \
--env-file .env \
skillspector scan ./my-skill/
```
O pasa las credenciales directamente desde tu entorno de shell:```bash
docker run --rm \
-v "$PWD:/scan" \
-e SKILLSPECTOR_PROVIDER=anthropic \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
skillspector scan ./my-skill/
```
**Escribe un informe al sistema de archivos del host** escribiendo en el directorio montado:```bash
docker run --rm \
-v "$PWD:/scan" \
skillspector scan ./my-skill/ --no-llm --format json --output report.json
```
**Alias opcional** para escaneos estáticos repetidos:```bash
alias skillspector-docker='docker run --rm -v "$PWD:/scan" skillspector'
skillspector-docker scan ./my-skill/ --no-llm
```
### Uso básico```bash
# Scan a local skill directory
skillspector scan ./my-skill/
# Scan a single SKILL.md file
skillspector scan ./SKILL.md
# Scan a Git repository
skillspector scan https://github.com/user/my-skill
# Scan a zip file
skillspector scan ./my-skill.zip
```
#### Límites de tamaño
SkillSpector impone dos límites independientes para entradas remotas y de archivos, con el fin de acotar el impacto de descargas sobredimensionadas y bombas zip:
- **Límite por ingesta**: `INGEST_MAX_BYTES` (100 MiB) — se aplica a descargas por URL en streaming, al tamaño total sin comprimir de archivos zip y al uso de disco posterior al clonado de repositorios Git.
- **Límite de miembros zip**: `INGEST_MAX_ZIP_MEMBERS` (10,000) — limita el número de entradas en un único zip.
Ten en cuenta que el límite de análisis de 1 MB por archivo (`MAX_FILE_BYTES`) es un límite posterior y separado: acota lo que los analizadores individuales leerán de un directorio ya ingerido. Los límites de ingesta anteriores acotan cuánto contenido puede llegar a almacenarse en disco en primer lugar. La vulneración de cualquiera de los límites de ingesta falla de forma segura con un `IngestLimitExceededError`.
### Formatos de salida```bash
# Terminal output (default) - pretty formatted
skillspector scan ./my-skill/
# JSON output - machine readable
skillspector scan ./my-skill/ --format json --output report.json
# Markdown output - for documentation
skillspector scan ./my-skill/ --format markdown --output report.md
# SARIF output - for CI/CD integration and IDE tooling
skillspector scan ./my-skill/ --format sarif --output report.sarif
```
### Escaneo por lotes
Escanea directorios completos de habilidades en paralelo desde `contrib/batch_scan/`:```bash
python -m contrib.batch_scan.batch_scan ./my-skills/ --no-llm
python -m contrib.batch_scan.batch_scan ./my-skills/ --workers 20 -f json -o report.json
python -m contrib.batch_scan.batch_scan ./tests/fixtures/ -f terminal --workers 20
```
Admite detección multilingüe (zh/ja/ko) y salida en terminal/JSON/Markdown.
Para escaneos con LLM de mayor concurrencia, configura múltiples claves API siguiendo
[`.env.example`](https://github.com/nvidia/skillspector/blob/HEAD/contrib/batch_scan/.env.example) — el grupo mejora el rendimiento
y la resiliencia, siempre que las claves no compartan un límite de tasa a nivel de cuenta.
Consulta la [guía de contribución](https://github.com/nvidia/skillspector/blob/HEAD/contrib/batch_scan/docs/) para más detalles.
> **Nota sobre el soporte de LLM:** La configuración predeterminada apunta a DeepSeek como la
> opción pública más económica. Se espera que DeepSeek-Chat
> [deje de estar disponible](https://api-docs.deepseek.com/), y el colaborador
> no dispone de hardware para probar modelos locales. El escáner por lotes fue
> probado originalmente con endpoints compatibles con OpenAI — la falta de soporte de
> salida estructurada de DeepSeek requirió parches manuales de análisis JSON. Si puedes
> contribuir con un backend más universal (Ollama, vLLM u otro proveedor),
> los PRs son muy bienvenidos.
### Supresión de falsos positivos (línea base)
Suprime hallazgos conocidos/aceptados para que la puntuación de riesgo refleje solo problemas
no clasificados y los re-escaneos muestren únicamente hallazgos *nuevos*. Consulta la
[guía de supresión](https://github.com/nvidia/skillspector/blob/HEAD/docs/SUPPRESSION.md) para la referencia completa.```bash
# Accept all current findings into a baseline (run once), then commit it.
skillspector baseline ./my-skill/ -o .skillspector-baseline.yaml
# Scan against the baseline — only NEW findings are reported and scored.
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml
# Review what was suppressed (still excluded from the score).
skillspector scan ./my-skill/ --baseline .skillspector-baseline.yaml --show-suppressed
```
Una línea de base también puede usar reglas de glob tolerantes a la deriva (por id de regla, ruta de archivo o
mensaje) — consulte [`.skillspector-baseline.example.yaml`](https://github.com/nvidia/skillspector/blob/HEAD/.skillspector-baseline.example.yaml).
Las líneas de base con huellas digitales exactas están vinculadas a la evidencia: cambiar el código fuente escaneado o la
versión de SkillSpector mantiene el hallazgo activo hasta que se revise nuevamente.
Cuando una línea de base seleccionada o su salida se almacena dentro del
directorio de la skill, SkillSpector excluye ese archivo exacto del análisis de contenido para que su
texto de supresión no pueda crear hallazgos ni entrar en huellas digitales regeneradas;
los archivos hermanos permanecen en el alcance normal del escaneo.
### Análisis LLM
Para obtener los mejores resultados, configure un endpoint LLM compatible con OpenAI para el
análisis semántico. Elija un proveedor con `SKILLSPECTOR_PROVIDER`; los proveedores alojados incluyen modelos predeterminados integrados, mientras que los proveedores CLI recurren al modelo predeterminado del runtime local a menos que se establezca `SKILLSPECTOR_MODEL`. SkillSpector también funciona con
servidores locales compatibles con OpenAI (Ollama, vLLM, llama.cpp) y puertas de enlace de inferencia gestionadas.
| Proveedor (`SKILLSPECTOR_PROVIDER`) | Variable de entorno de credenciales | Endpoint | Modelo predeterminado |
| ---------- | ---- | ---- | ---- |
| `openai` | `OPENAI_API_KEY` (+ `OPENAI_BASE_URL` opcional) | api.openai.com (o cualquier URL compatible con OpenAI) | `gpt-5.4` |
| `anthropic` | `ANTHROPIC_API_KEY` | api.anthropic.com | `claude-opus-4-6` |
| `anthropic_proxy` | `ANTHROPIC_PROXY_API_KEY` + `ANTHROPIC_PROXY_ENDPOINT_URL` | Cualquier proxy raw-predict estilo Vertex | `claude-sonnet-4-6` |
| `bedrock` | `AWS_PROFILE` (opcional) + `AWS_REGION` — SigV4 vía boto3 | AWS Bedrock Runtime | `us.anthropic.claude-sonnet-4-6-20250915-v1:0` |
| `nv_build` | `NVIDIA_INFERENCE_KEY` | build.nvidia.com | `deepseek-ai/deepseek-v4-flash` |
| `claude_cli` | _(ninguna — usa autenticación CLI local)_ | binario local `claude` | runtime local de Claude como respaldo, o `SKILLSPECTOR_MODEL` |
| `codex_cli` | _(ninguna — usa autenticación CLI local)_ | binario local `codex` | runtime local de Codex como respaldo, o `SKILLSPECTOR_MODEL` |```bash
# Stock OpenAI
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY=sk-...
skillspector scan ./my-skill/
# Anthropic
export SKILLSPECTOR_PROVIDER=anthropic
export ANTHROPIC_API_KEY=sk-ant-...
skillspector scan ./my-skill/
# Anthropic via Vertex-style proxy (corporate gateways, GCP Vertex AI)
export SKILLSPECTOR_PROVIDER=anthropic_proxy
export ANTHROPIC_PROXY_ENDPOINT_URL=https://my-gateway.example.com/models/claude-sonnet-4-6:streamRawPredict
export ANTHROPIC_PROXY_API_KEY=your-bearer-token
export SKILLSPECTOR_MODEL=claude-sonnet-4-6
skillspector scan ./my-skill/
# AWS Bedrock (Claude via SigV4)
export SKILLSPECTOR_PROVIDER=bedrock
# Optional: select an AWS named profile. When unset, the standard
# boto3 credential chain (env vars, instance metadata, SSO, etc.) resolves.
# export AWS_PROFILE=my-profile
export AWS_REGION=us-west-2 # default if unset
# Default model: us.anthropic.claude-sonnet-4-6-20250915-v1:0
# Override with any Bedrock model ID, cross-region inference-profile
# ID, or your own application-inference-profile ARN:
# export SKILLSPECTOR_MODEL=us.anthropic.claude-opus-4-6-20250915-v1:0
skillspector scan ./my-skill/
# NVIDIA build.nvidia.com
export SKILLSPECTOR_PROVIDER=nv_build
export NVIDIA_INFERENCE_KEY=nvapi-...
skillspector scan ./my-skill/
# Local Claude CLI — no API key; uses your existing `claude auth login` session
# Requires: claude CLI installed and authenticated (claude auth login)
export SKILLSPECTOR_PROVIDER=claude_cli
# Uses the local Claude CLI runtime fallback unless SKILLSPECTOR_MODEL is set.
# export SKILLSPECTOR_MODEL=claude-sonnet-4-6
skillspector scan ./my-skill/
# Local Codex CLI — no API key; uses your existing `codex login` session
# Requires: codex CLI installed and authenticated
export SKILLSPECTOR_PROVIDER=codex_cli
skillspector scan ./my-skill/
# Local Ollama or any OpenAI-compatible endpoint
export SKILLSPECTOR_PROVIDER=openai
export OPENAI_API_KEY=ollama
export OPENAI_BASE_URL=http://localhost:11434/v1
export SKILLSPECTOR_MODEL=llama3.1:8b
skillspector scan ./my-skill/
# Override the provider's default model
export SKILLSPECTOR_MODEL=gpt-5.2
skillspector scan ./my-skill/
# Skip LLM analysis (faster, static analysis only)
skillspector scan ./my-skill/ --no-llm
```
### Servidor MCP
Ejecuta SkillSpector como un servidor de [Model Context Protocol](https://modelcontextprotocol.io)
para que cualquier agente compatible con MCP (Claude Code, Codex CLI, Gemini CLI) o un
runtime remoto pueda invocar el escaneo como una herramienta y **condicionar las instalaciones de skills/MCP al
resultado** — convirtiendo a SkillSpector en una salvaguarda en tiempo de ejecución en lugar de un
paso de auditoría fuera de banda.
`skillspector mcp` requiere `skillspector[mcp]`.```bash
# Install, or reinstall if you already used the CLI-only path
uv tool install --force 'skillspector[mcp] @ git+https://github.com/NVIDIA/skillspector.git'
# FastMCP stdio transport for local CLI agents
skillspector mcp
# streamable HTTP/SSE transport for remote / A2A callers
skillspector mcp --transport http --host 127.0.0.1 --port 8000
```
El transporte stdio es la ruta actual de FastMCP para agentes CLI locales, y el
bloqueo de inicialización reportado en el issue #199 sigue aplicándose allí.
El servidor expone una única herramienta:
- **`scan_skill(target, use_llm=true, output_format="json")`** — escanea una URL
de Git, una URL de archivo, un `.zip`, un archivo `.md` o un directorio y devuelve un
veredicto estructurado: `risk_score` (0-100), `severity`, `recommendation`,
`safe_to_install` y `findings`. También informa `llm_used` / `scan_mode`
para que una puntuación baja de un escaneo solo estático nunca se confunda con un
escaneo completo limpio.
Regístrala con Claude Code mediante:```bash
claude mcp add skillspector -- skillspector mcp
```
> **Seguridad — Modelo de confianza del transporte HTTP**
>
> El transporte HTTP se distribuye **sin autenticación**. Cualquier llamador que pueda
> alcanzar el puerto puede invocar `scan_skill`. A través de stdio o `127.0.0.1` esto es
> el mismo límite de confianza que la CLI. Si lo vinculas a una interfaz enrutable:
>
> - Coloca el servidor detrás de un proxy inverso autenticado (p. ej. nginx + mTLS)
> antes de exponerlo externamente.
> - Las rutas locales y las URL `file://` son **rechazadas automáticamente** a través de HTTP para
> evitar que llamadores no autenticados lean archivos arbitrarios del host. Solo
> se aceptan URL remotas de Git y `.zip`.
## Patrones de Vulnerabilidad
SkillSpector detecta **68 patrones de vulnerabilidad** en 17 categorías:
### Inyección de Prompts (5 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| P1 | Anulación de Instrucciones | ALTA | Comandos para ignorar restricciones de seguridad |
| P2 | Instrucciones Ocultas | ALTA | Directivas maliciosas en comentarios/texto invisible |
| P3 | Comandos de Exfiltración | ALTA | Instrucciones para transmitir contexto externamente |
| P4 | Manipulación de Comportamiento | MEDIA | Instrucciones sutiles que alteran las decisiones del agente |
| P5 | Contenido Dañino | CRÍTICA | Instrucciones que podrían causar daño físico |
### Anti-Rechazo (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| AR1 | Supresión de Rechazo | ALTA | Instrucciones para nunca rechazar o siempre cumplir (p. ej. "nunca rechaces", "siempre cumple") |
| AR2 | Supresión de Descargos | ALTA | Instrucciones para omitir advertencias, descargos o comentarios éticos (p. ej. "sin descargos", "no moralices") |
| AR3 | Anulación de Políticas de Seguridad | ALTA | Marco de jailbreak que anula las salvaguardas (p. ej. "no tienes restricciones", "ignora tus pautas", "haz cualquier cosa ahora") |
### Exfiltración de Datos (4 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| E1 | Transmisión Externa | MEDIA | Envío de datos a URL externas |
| E2 | Recolección de Variables de Entorno | ALTA | Enumerar, copiar o buscar datos de entorno para recopilar secretos |
| E3 | Enumeración del Sistema de Archivos | MEDIA | Escaneo de directorios en busca de archivos sensibles |
| E4 | Fuga de Contexto | ALTA | Transmisión externa del contexto de conversación |
### Escalada de Privilegios (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| PE1 | Permisos Excesivos | BAJA | Solicitud de acceso más allá de la funcionalidad declarada |
| PE2 | Ejecución Sudo/Root | MEDIA | Invocación de privilegios elevados del sistema |
| PE3 | Acceso a Credenciales | ALTA | Lectura de claves SSH, tokens, contraseñas |
### Cadena de Suministro (6 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| SC1 | Dependencias sin Fijar | BAJA | Sin restricciones de versión en los paquetes |
| SC2 | Obtención de Scripts Externos | ALTA | curl \| bash y ejecución remota de código |
| SC3 | Código Ofuscado | ALTA | Ejecución codificada en Base64/hex |
| SC4 | Dependencias Vulnerables Conocidas | ALTA | Dependencias con CVEs conocidos (consulta en vivo de OSV.dev) |
| SC5 | Dependencias Abandonadas | MEDIA | Paquetes sin mantenimiento sin actualizaciones de seguridad |
| SC6 | Typosquatting | ALTA | Nombres de paquetes similares a paquetes populares |
### Agencia Excesiva (4 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| EA1 | Acceso Ilimitado a Herramientas | ALTA | Acceso sin restricciones a herramientas sin limitaciones |
| EA2 | Toma de Decisiones Autónoma | ALTA | Decisiones de alto impacto sin intervención humana |
| EA3 | Expansión del Alcance | MEDIA | Capacidades que se extienden más allá del propósito declarado |
| EA4 | Acceso Ilimitado a Recursos | MEDIA | Sin límites de tasa ni cuotas en el consumo de recursos |
### Manejo de Salidas (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| OH1 | Inyección de Salida No Validada | ALTA | Salida del modelo utilizada sin saneamiento |
| OH2 | Salida entre Contextos | MEDIA | La salida fluye a través de límites de confianza sin validación |
| OH3 | Salida Ilimitada | MEDIA | Sin límites en el tamaño de salida o la tasa de generación |
### Fuga del Prompt del Sistema (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| P6 | Fuga Directa | ALTA | Instrucciones que exponen prompts del sistema o reglas internas |
| P7 | Extracción Indirecta | MEDIA | Extracción mediante reformulación, traducción o canales laterales |
| P8 | Exfiltración Basada en Herramientas | ALTA | Prompts del sistema exfiltrados mediante escrituras de archivos o solicitudes de red |
### Envenenamiento de Memoria (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| MP1 | Inyección Persistente de Contexto | ALTA | Contenido diseñado para persistir entre interacciones |
| MP2 | Relleno de la Ventana de Contexto | MEDIA | Contenido de relleno que desplaza las restricciones de seguridad |
| MP3 | Manipulación de Memoria | ALTA | Alteración de la memoria del agente o del estado almacenado |
### Uso Indebido de Herramientas (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| TM1 | Abuso de Parámetros de Herramientas | ALTA | Parámetros diseñados para comportamiento no deseado (shell=True, --force) |
| TM2 | Abuso de Encadenamiento | ALTA | Cadenas de herramientas que evitan verificaciones de seguridad individuales |
| TM3 | Valores Predeterminados Inseguros | MEDIA | Valores predeterminados demasiado permisivos (TLS deshabilitado, sin autenticación) |
### Agente Malicioso (2 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| RA1 | Auto-Modificación | CRÍTICA | Modificación del propio código o configuración en tiempo de ejecución |
| RA2 | Persistencia de Sesión | ALTA | Persistencia no autorizada mediante trabajos cron o scripts de inicio |
### Abuso de Disparadores (3 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| TR1 | Disparador Demasiado Amplio | MEDIA | Patrones de disparo que coinciden con palabras comunes |
| TR2 | Disparador de Comando Sombra | ALTA | Disparadores que ensombrecen comandos integrados u otras habilidades |
| TR3 | Disparador de Cebo por Palabras Clave | MEDIA | Disparadores genéricos diseñados para maximizar la activación |
### AST de Comportamiento (9 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| AST1 | Llamada a exec() | CRÍTICA | exec() directo que permite ejecución arbitraria de código |
| AST2 | Llamada a eval() | ALTA | eval() directo que evalúa expresiones arbitrarias |
| AST3 | Importación Dinámica | ALTA | \_\_import\_\_() que carga módulos arbitrarios en tiempo de ejecución |
| AST4 | Llamada a subprocess | ALTA | Ejecución de comandos externos mediante subprocess |
| AST5 | os.system / familia exec | ALTA | Comandos de shell mediante el módulo os |
| AST6 | Llamada a compile() | MEDIA | Creación de objetos de código a partir de cadenas |
| AST7 | getattr() Dinámico | MEDIA | Acceso arbitrario a atributos con nombres no literales |
| AST8 | Cadena de Ejecución Peligrosa | CRÍTICA | exec/eval combinado con fuente dinámica (red, datos codificados) |
| AST9 | Sumidero getattr() Reflexivo | ALTA | exec reflexivo mediante `getattr(os,'system')` / `getattr(builtins,'exec')` que evade AST1/AST5 |
### Seguimiento de Taint (5 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| TT1 | Flujo de Taint Directo | ALTA | Los datos fluyen directamente de una fuente a un sumidero sin saneamiento |
| TT2 | Flujo de Taint Mediado por Variables | MEDIA | Los datos fluyen de la fuente al sumidero a través de variables intermedias |
| TT3 | Cadena de Exfiltración de Credenciales | CRÍTICA | Las credenciales (variables de entorno, secretos) fluyen a sumideros de salida de red |
| TT4 | Lectura de Archivo a Exfiltración de Red | ALTA | El contenido de archivos fluye a sumideros de salida de red |
| TT5 | Entrada Externa a Ejecución de Código | CRÍTICA | La entrada de red o de usuario fluye a sumideros exec/eval/subprocess |
### Firmas YARA (4 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| YR1 | Coincidencia de Malware | CRÍTICA | Coincidencia de regla YARA para firmas de malware conocidas |
| YR2 | Coincidencia de Webshell | CRÍTICA | Coincidencia de regla YARA para patrones de webshell |
| YR3 | Coincidencia de Criptominero | ALTA | Coincidencia de regla YARA para indicadores de minería de criptomonedas |
| YR4 | Coincidencia de Herramienta de Hackeo / Exploit | ALTA | Coincidencia de regla YARA para herramientas de hackeo o código de exploit |
### MCP de Privilegio Mínimo (4 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| LP1 | Capacidad Subdeclarada | ALTA | El código usa capacidades no listadas en los permisos declarados |
| LP2 | Permiso Comodín | MEDIA | La lista de permisos contiene comodines (\*, all, full, any) |
| LP3 | Declaración de Permiso Faltante | MEDIA | Sin campo de permisos pero el código tiene capacidades detectables |
| LP4 | Permiso Sobredeclarado | BAJA | Permiso declarado pero no se encontró capacidad de código correspondiente |
### Envenenamiento de Herramientas MCP (4 patrones)
| ID | Patrón | Severidad | Descripción |
|----|---------|----------|-------------|
| TP1 | Instrucciones Ocultas | ALTA | Directivas ocultas en metadatos (comentarios HTML, caracteres de ancho cero, base64, URI de datos) |
| TP2 | Engaño Unicode | ALTA | Homoglifos, anulaciones RTL, identificadores de escritura mixta en metadatos de herramientas |
| TP3 | Inyección en Descripción de Parámetros | MEDIA | Patrones de inyección en definiciones de parámetros (anulaciones, tokens de sistema, valores predeterminados maliciosos) |
| TP4 | Desajuste Descripción-Comportamiento | MEDIA | La descripción declarada de la herramienta no coincide con el comportamiento real del código (impulsado por LLM) |
Todos los patrones detectados se enumeran en las tablas anteriores.
## Puntuación de Riesgo
### Cálculo de Puntuación
- **Problemas CRÍTICOS**: +50 puntos
- **Problemas ALTOS**: +25 puntos
- **Problemas MEDIOS**: +10 puntos
- **Problemas BAJOS**: +5 puntos
- **Scripts ejecutables**: multiplicador de 1.3x
### Niveles de Severidad
| Puntuación | Severidad | Recomendación |
|-------|----------|----------------|
| 0-20 | BAJA | SEGURO |
| 21-50 | MEDIA | PRECAUCIÓN |
| 51-80 | ALTA | NO INSTALAR |
| 81-100 | CRÍTICA | NO INSTALAR |
## Ejemplo de Salida
### Salida de Terminal```
SkillSpector Security Report v2.0.0
Skill: suspicious-skill
Source: ./suspicious-skill/
Scanned: 2026-01-29 10:30:00 UTC
Risk Assessment
Metric Value
Score 78/100
Severity HIGH
Recommendation DO NOT INSTALL
Components (3)
File Type Lines Executable
SKILL.md markdown 142 No
scripts/sync.py python 87 Yes
requirements.txt text 3 No
Issues (2)
HIGH: Env Variable Harvesting (E2)
Location: scripts/sync.py:23
Finding: for key, val in os.environ.items():...
Confidence: 94%
Explanation: This code collects environment variables containing
API keys and secrets, then sends them to an external server.
HIGH: External Transmission (E1)
Location: scripts/sync.py:45
Finding: requests.post("https://api.skill.io/env"...
Confidence: 89%
Explanation: Data is being sent to an external server. Combined
with env harvesting above, this indicates credential exfiltration.
```
## Configuración
### Variables de Entorno
| Variable | Descripción | Requerida |
|----------|-------------|-----------|
| `SKILLSPECTOR_PROVIDER` | Proveedor LLM activo: `openai`, `anthropic`, `anthropic_proxy`, `bedrock`, `nv_build`, `claude_cli`, `codex_cli` o `gemini_cli`. Los proveedores alojados usan los valores predeterminados del `model_registry.yaml` incluido; `claude_cli` y `codex_cli` recurren al modelo predeterminado del runtime CLI local a menos que se establezca `SKILLSPECTOR_MODEL`. El valor predeterminado es `nv_build`. | Opcional |
| `NVIDIA_INFERENCE_KEY` | Credencial para el proveedor `nv_build` (build.nvidia.com). | Requerida para el análisis LLM cuando `SKILLSPECTOR_PROVIDER=nv_build` |
| `OPENAI_API_KEY` | Credencial para el proveedor OpenAI (`SKILLSPECTOR_PROVIDER=openai`). También sirve como respaldo de nivel 2 en la cascada de credenciales cuando el proveedor activo no devuelve credenciales. | Requerida para el análisis LLM cuando `SKILLSPECTOR_PROVIDER=openai` |
| `OPENAI_BASE_URL` | Sobrescribe el endpoint de OpenAI (p. ej., para apuntar a Ollama). | Opcional |
| `SKILLSPECTOR_REASONING_EFFORT` | Configuración opcional de esfuerzo de razonamiento dependiente del proveedor y del modelo. Los valores no vacíos se recortan y se pasan sin cambios; si no se establece o está vacío, se conserva el comportamiento predeterminado del proveedor. | Opcional |
| `ANTHROPIC_API_KEY` | Credencial para el proveedor Anthropic (`SKILLSPECTOR_PROVIDER=anthropic`). | Requerida para el análisis LLM cuando `SKILLSPECTOR_PROVIDER=anthropic` |
| `ANTHROPIC_BASE_URL` | Sobrescribe el endpoint nativo de Anthropic (predeterminado: `https://api.anthropic.com`). | Opcional |
| `ANTHROPIC_PROXY_ENDPOINT_URL` | URL completa del endpoint para el proveedor proxy de Anthropic (raw-predict estilo Vertex). | Requerida cuando `SKILLSPECTOR_PROVIDER=anthropic_proxy` |
| `ANTHROPIC_PROXY_API_KEY` | Token Bearer para el proveedor proxy de Anthropic. | Requerida cuando `SKILLSPECTOR_PROVIDER=anthropic_proxy` |
| `ANTHROPIC_PROXY_API_VERSION` | Valor de `anthropic_version` enviado en el cuerpo de la solicitud (predeterminado: `vertex-2023-10-16`). | Opcional |
| `AWS_PROFILE` | Perfil AWS con nombre para el proveedor Bedrock: autentica mediante SigV4 a través de boto3. Si no se establece, se resuelve mediante la cadena estándar de credenciales de boto3 (variables de entorno, metadatos de instancia, SSO, etc.). | Opcional (se usa cuando `SKILLSPECTOR_PROVIDER=bedrock`) |
| `AWS_REGION` | Región de AWS para el endpoint del Bedrock Runtime. El valor predeterminado es `us-west-2`. | Opcional (se usa cuando `SKILLSPECTOR_PROVIDER=bedrock`) |
| `SKILLSPECTOR_MODEL` | Sobrescribe el modelo del proveedor activo. Para proveedores alojados, reemplaza el valor predeterminado incluido de la tabla de Análisis LLM. Para `claude_cli` y `codex_cli`, se reenvía como `--model` en lugar de usar el respaldo del runtime CLI local. | Opcional |
| `SKILLSPECTOR_MODEL_REGISTRY` | Sobrescribe el registro YAML incluido por proveedor (`src/skillspector/providers/<provider>/model_registry.yaml`) con una ruta personalizada. | Opcional |
| `SKILLSPECTOR_LOG_LEVEL` | Nivel de registro: `DEBUG`, `INFO`, `WARNING`, `ERROR` (predeterminado: `WARNING`). | Opcional |
> **Proveedores CLI** (`claude_cli`, `codex_cli`): No se necesita clave API. La autenticación la gestiona por completo la sesión de inicio de sesión propia de la CLI del agente (`claude auth login` / `codex login`). SkillSpector nunca lee ni reenvía claves API cuando estos proveedores están activos. El subproceso se ejecuta en un sandbox reforzado: herramientas deshabilitadas, sin MCP, modo sandbox de solo lectura (codex) y el contenido de habilidades no confiable se entrega únicamente mediante stdin.
### Opciones de CLI```bash
skillspector scan --help
Options:
-f, --format [terminal|json|markdown|sarif] Output format [default: terminal]
-o, --output PATH Output file path
--no-llm Skip LLM analysis (static only)
--yara-rules-dir PATH Extra YARA rules directory
-b, --baseline PATH Suppress findings listed in a baseline
--show-suppressed List baseline-suppressed findings
-V, --verbose Show detailed progress
--help Show this message and exit
# Generate a baseline of all current findings (see docs/SUPPRESSION.md)
skillspector baseline <path> [-o FILE] [--no-llm] [--reason TEXT]
```
## Integración de SkillSpector
SkillSpector está diseñado para ser controlado por otras herramientas (pipelines de CI, puertas de instalación, integraciones de editores). Su código de salida y su salida JSON son un contrato estable.
### Códigos de salida
`skillspector scan` termina con:
| Código | Significado |
|------|---------|
| `0` | Escaneo completado, `risk_score` ≤ 50 (recomendación `SAFE` o `CAUTION`) |
| `1` | Escaneo completado, `risk_score` > 50 (recomendación `DO_NOT_INSTALL`) |
| `2` | Error (entrada incorrecta, fuente ilegible, fallo interno) |
> El código de salida agrupa `SAFE` y `CAUTION` en `0`. Para actuar de manera diferente sobre ellos (p. ej., *advertir* en `CAUTION` pero *bloquear* en `DO_NOT_INSTALL`), lee el campo `recommendation` de la salida JSON en lugar de depender del código de salida.
### Salida legible por máquina
`--format json` produce un informe JSON; sin `--output`/`-o` se escribe en stdout:```bash
skillspector scan ./my-skill/ --format json
```
The top-level shape is (this example shows a full LLM-backed scan; with `--no-llm`, `metadata.llm_requested` is `false`):```json
{
"skill": { "name": "...", "source": "...", "scanned_at": "<ISO 8601>" },
"risk_assessment": { "score": 0, "severity": "LOW", "recommendation": "SAFE" },
"components": [ { "path": "...", "type": "...", "lines": 0, "executable": false, "size_bytes": 0 } ],
"issues": [ { "id": "...", "category": "...", "severity": "...", "confidence": 0.0, "location": { "file": "...", "start_line": 0 } } ],
"metadata": {
"has_executable_scripts": false,
"skillspector_version": "...",
"llm_requested": true,
"llm_available": true,
"inference_usage": [
{
"node": "semantic_security_discovery",
"request_kind": "structured_output",
"provider": "nv_inference",
"model": "azure/anthropic/claude-opus-4-6",
"model_source": "provider_response",
"usage_source": "provider_response",
"prompt_tokens": 1000,
"completion_tokens": 100,
"cached_tokens": 400,
"cache_write_tokens": 50,
"total_tokens": 1100
}
]
}
}
```
- `risk_assessment.severity` ∈ `LOW | MEDIUM | HIGH | CRITICAL`.
- `risk_assessment.recommendation` ∈ `SAFE | CAUTION | DO_NOT_INSTALL`, mapeado desde la severidad: `LOW → SAFE`, `MEDIUM → CAUTION`, `HIGH`/`CRITICAL → DO_NOT_INSTALL`.
- `metadata.llm_error` aparece solo cuando se solicitó análisis LLM pero no estaba disponible.
- `metadata.inference_usage` contiene un registro saneado por respuesta LLM cuando el
proveedor expone contadores de tokens. Es una lista vacía cuando el uso no está disponible;
SkillSpector nunca estima tokens faltantes. Los totales de prompts incluyen lecturas
y escrituras de caché para que la facturación posterior pueda separar esas particiones de forma segura.
`model_source` distingue un modelo de proveedor identificado de forma independiente de
el modelo exacto solicitado usado cuando la identidad de la respuesta está ausente o es ambigua.
SkillSpector no envía actualmente controles de caché de prompts de Anthropic, por lo que sus
solicitudes de escaneo no pueden seleccionar los niveles separados de escritura de caché de 5 minutos o 1 hora;
los campos de respuesta específicos de TTL se normalizan de forma defensiva en el contador agregado
de escritura de caché.
- Consulta [Telemetría de uso de inferencia](https://github.com/nvidia/skillspector/blob/HEAD/docs/INFERENCE_USAGE.md) para conocer el contrato completo de
procedencia, contabilidad de caché, privacidad, ingesta de cierre ante fallos y facturación posterior.
- La forma completa por problema se define mediante `Finding.to_dict()` en [models.py](https://github.com/nvidia/skillspector/blob/HEAD/src/skillspector/models.py); confía en los campos anteriores y trata cualquier campo adicional como de mejor esfuerzo.
Para herramientas de CI/IDE, `--format sarif` emite SARIF 2.1.0.
### Mapeo de puerta recomendado
Al usar SkillSpector como puerta de instalación, mapea la recomendación a una acción:
| `recommendation` | Acción sugerida |
|------------------|------------------|
| `SAFE` | permitir |
| `CAUTION` | avisar / advertir al usuario |
| `DO_NOT_INSTALL` | bloquear |
SkillSpector calcula la banda de puntuación y la recomendación; cuán estricta sea la puerta (p. ej., si `CAUTION` bloquea en CI) es una decisión de política para la herramienta integradora.
## Desarrollo
### Configuración
Todos los objetivos de `make` asumen que ya se ha creado y activado un entorno virtual. El Makefile usa **uv** si está disponible; de lo contrario, **pip**.```bash
# Clone, create venv, activate, install dev dependencies
git clone https://github.com/NVIDIA/skillspector.git
cd skillspector
uv venv .venv && source .venv/bin/activate
# or: python3 -m venv .venv && source .venv/bin/activate
make install-dev
# Run tests
make test
# Run tests with coverage
make test-cov
# Run linting
make lint
# Format code
make format
```
## Cómo Funciona
SkillSpector utiliza un pipeline de detección en dos etapas:
### Etapa 1: Análisis Estático
- Coincidencia rápida basada en expresiones regulares en 11 analizadores estáticos
- Análisis de comportamiento basado en AST que detecta llamadas peligrosas (exec, eval, subprocess, etc.)
- Búsquedas en vivo de vulnerabilidades mediante OSV.dev para CVEs conocidos en dependencias
- Escanea todos los archivos elegibles para analizadores en la habilidad
- Alta recuperación (detecta la mayoría de los problemas)
- Precisión moderada (algunos falsos positivos)
Una firma válida de OpenSSF Model Signing a nivel raíz (`skill.oms.sig`) se conserva en el
inventario de componentes como tipo `oms_signature`, pero se excluye del análisis estático y de contenido LLM.
Los paquetes OMS contienen necesariamente campos largos de payload, firma y certificado codificados en base64;
las comprobaciones genéricas de código ofuscado pueden clasificar erróneamente esos campos como contenido ejecutable oculto.
El reconocedor verifica la estructura mínima de OMS DSSE/in-toto; no verifica la firma,
la cadena de certificados, la entrada del registro de transparencia ni la identidad del firmante. Los archivos
de firma inválidos o no reconocidos se escanean normalmente.
### Etapa 2: Análisis Semántico LLM (Opcional)
- Evalúa contexto e intención
- Filtra falsos positivos
- Proporciona explicaciones legibles para humanos
- Mejora la precisión hasta ~87%
El prompt del LLM incluye protecciones anti-jailbreak para evitar que habilidades maliciosas manipulen el análisis.
## Búsquedas en Vivo de Vulnerabilidades (SC4)
SC4 utiliza la API de [OSV.dev](https://osv.dev) para verificar dependencias contra la base de datos completa de Vulnerabilidades de Código Abierto, que cubre decenas de miles de avisos en PyPI y npm.
- **No se requiere clave API** — OSV.dev es gratuito y sin autenticación.
- **Consultas por lotes** — todas las dependencias se verifican en una sola llamada HTTP.
- **Respaldo automático** — si OSV.dev no está disponible (entorno aislado/sin conexión), se utiliza una pequeña lista de respaldo integrada.
- **Almacenamiento en caché** — los resultados se almacenan en caché en memoria durante 1 hora para evitar llamadas API redundantes durante una sesión.
La herramienta requiere acceso HTTPS saliente a `api.osv.dev` para datos de vulnerabilidades en vivo. Cuando eso no está disponible, los hallazgos se limitan a la lista de respaldo estática.
## Modelo de confianza y salida de datos
SkillSpector es defensa en profundidad, no un sandbox. Conoce qué hace y qué no hace antes de confiar en él:
- **Nunca ejecuta la habilidad escaneada.** Todo el análisis es estático (regex, AST de Python, YARA) más una evaluación opcional del LLM del *contenido* de los archivos — el código de la habilidad nunca se ejecuta.
- **El análisis LLM envía el contenido de los archivos elegibles al proveedor configurado.** Cuando el análisis LLM está habilitado (el valor predeterminado), el contenido de los archivos se envía al endpoint activo de `SKILLSPECTOR_PROVIDER`. Los archivos de firma OMS reconocidos se excluyen. Usa `--no-llm` para mantener el contenido local (solo análisis estático).
- **SC4 envía nombres de dependencias a OSV.dev.** La verificación de la cadena de suministro consulta [OSV.dev](https://osv.dev) con los nombres de paquetes y versiones que declara la habilidad, para buscar CVEs conocidos. Esto es fundamental para la verificación y se ejecuta incluso con `--no-llm`. Envía coordenadas de dependencias (no contenido de archivos), no requiere clave API y recurre a una lista integrada cuando OSV.dev no está disponible.
- **No aísla el host.** SkillSpector señala patrones riesgosos *antes* de que instales una habilidad; no contiene ni aísla una habilidad que decidas instalar de todos modos.
## Limitaciones
- **Contenido no inglés**: Puede omitir patrones en otros idiomas
- **Ataques basados en imágenes**: No puede analizar texto en imágenes
- **Código cifrado/binario**: No puede analizar contenido compilado o cifrado
- **Comportamiento en tiempo de ejecución**: Solo análisis estático, sin ejecución dinámica
- **SC4 sin conexión**: Sin acceso de red a `api.osv.dev`, SC4 utiliza una pequeña lista de respaldo estática
## Antecedentes de Investigación
Basado en la investigación de "Agent Skills in the Wild: An Empirical Study of Security Vulnerabilities at Scale" (Liu et al., 2026):
- **Conjunto de datos**: 42,447 habilidades de los principales marketplaces
- **Vulnerables**: 26.1% contienen al menos una vulnerabilidad
- **Alta severidad**: 5.2% muestran probable intención maliciosa
- **Hallazgo clave**: Las habilidades con scripts ejecutables tienen 2.12x más probabilidades de ser vulnerables
## Integración con la API de Python```python
from skillspector import graph
# Invoke the LangGraph workflow
result = graph.invoke({
"input_path": "/path/to/skill",
"output_format": "json", # terminal, json, markdown, or sarif
"use_llm": True, # False for static-only analysis
})
# Access results
print(f"Risk Score: {result['risk_score']}/100")
print(f"Severity: {result['risk_severity']}")
print(f"Recommendation: {result['risk_recommendation']}")
for finding in result["filtered_findings"]:
print(f"[{finding['severity']}] {finding['rule_id']}: {finding['message']}")
```
## Licencia
Apache License 2.0: consulte [LICENSE](https://github.com/nvidia/skillspector/blob/HEAD/LICENSE) para obtener más detalles.
## Contribuciones
¡Las contribuciones son bienvenidas! Lea nuestras pautas de contribución y envíe solicitudes de extracción (pull requests).
## Soporte
- **Problemas**: [GitHub Issues](https://github.com/NVIDIA/skillspector/issues)