Volver a actualizaciones
Nuevo releaseAug 18, 2026

safer-dependencies v0.6.0

Capa de seguridad automatizada de dependencias para asistentes de codificación de IA que audita paquetes en busca de CVEs, typosquats, abandono, problemas de antigüedad de versiones e integridad de hash en los ecosistemas npm, PyPI, RubyGems, Maven, Go y Rust.

Compartir

Safer Dependencies for Claude Code

Cuando los asistentes de codificación con IA como Claude añaden paquetes a tu proyecto, a menudo eligen la versión que suene bien, sin comprobar si tiene vulnerabilidades de seguridad conocidas, si el paquete sigue mantenido activamente o si el nombre está a un error tipográfico de un suplantador malicioso.

safer-dependencies es una capa de seguridad para Claude Code: se sitúa entre Claude y tus archivos de manifiesto y ejecuta sus comprobaciones de seguridad automáticamente: las instalaciones vulnerables se deniegan antes de ejecutarse, y una versión riesgosa escrita en un manifiesto se corrige en disco inmediatamente después de la escritura. Detecta y corrige dependencias riesgosas — CVEs, typosquats, paquetes abandonados y problemas de antigüedad de versión, además de un período de enfriamiento para lanzamientos recién publicados — en npm, PyPI, RubyGems, Maven, Go, Rust y PHP (Composer). Consulta CAPABILITIES.md para saber exactamente qué está cubierto y qué no.

¿Nuevo aquí? GETTING-STARTED.md te lleva de cero a una instalación funcional en unos cinco minutos.

Seguridad y privacidad: consulta SECURITY.md (divulgación de vulnerabilidades), PRIVACY.md (salida de datos, sin telemetría) y CAPABILITIES.md (contra qué defiende la herramienta y contra qué no).

Licencia (código disponible — NO es "open source" según OSI): Libre de usar y modificar para tus propios fines, incluido el uso interno con fines de lucro/empresarial y la creación de productos que vendas. Se requiere una licencia de pago por separado solo para monetizar el software en sí mismo: venderlo, incluirlo en un producto o servicio que se venda, u ofrecer su funcionalidad a terceros a cambio de una tarifa (incluido alojado/SaaS/API). La redistribución y las obras derivadas deben conservar la licencia y dar crédito a este proyecto. Consulta LICENSE (Sección 4 para la restricción comercial); solicitudes de licencia comercial a través de github.com/robert-auger.

Contents

Getting started

GETTING-STARTED.md te lleva de cero a una instalación funcional en unos cinco minutos: requisitos previos, la instalación interactiva y la verificación. Para la referencia completa de instalación (instalaciones globales/de proyecto/manuales, particularidades de Windows, la lista blanca de permisos, actualización y desinstalación), consulta INSTALLATION.md.

Uso diario: una vez que los hooks están instalados, no hay nada que ejecutar: safer-dependencies funciona automáticamente en segundo plano. A medida que Claude añade o instala paquetes, marca dependencias riesgosas y actualiza las versiones vulnerables a una segura en el mismo lugar — y bloquea una instalación con vulnerabilidades conocidas antes siquiera de que se ejecute — de modo que los paquetes inseguros se detectan y corrigen sin que tengas que pedirlo. Puedes invocarlo directamente en cualquier momento: "¿es segura [email protected]?", "verifica la configuración de safer-dependencies" o "muestra las estadísticas de safer-dependencies".

What it does

Cuando Claude está a punto de añadir un paquete a tu proyecto, safer-dependencies intercepta y ejecuta 5 comprobaciones:

  1. Provenance -- registro oficial, detección de typosquat (npm/PyPI/RubyGems/Maven/crates.io), antigüedad del paquete
  2. Version age -- elige la versión estable más reciente publicada hace 7+ días (ventana de enfriamiento)
  3. Vulnerability scan -- API de OSV, con herramientas nativas del ecosistema (npm audit, pip-audit, bundle audit) cuando estén disponibles
  4. Hash-pin integrity -- para líneas de PyPI requirements.txt con fijaciones --hash=sha256:..., el hash declarado se valida contra los hashes publicados por PyPI; una discrepancia emite una advertencia
  5. Abandoned & stale packages -- los paquetes conocidos como abandonados (p. ej., paperclip, request, pycrypto, github.com/dgrijalva/jwt-go) se bloquean de inmediato con un reemplazo sugerido; los paquetes sin una versión estable en 2+ años reciben una advertencia informativa STALE:. Los paquetes bloqueados se eliminan del manifiesto y Claude preguntará cómo proceder; los paquetes solo obsoletos se dejan en su lugar.

Si se encuentran problemas, Claude emite advertencias y puede retroceder a una versión más segura. Todas las comprobaciones se registran en ~/.claude/safer-dependencies-audit-YYYY-MM.log (un archivo por mes calendario).

How it works

La skill opera en cinco modos (resumidos a continuación; el fundamento de diseño más profundo se encuentra en skills/safer-dependencies.md):

Normal Mode (Manual)

Cuando Claude está a punto de escribir un import, añadir un paquete a un manifiesto o actualizar un archivo de bloqueo, la skill se ejecuta en línea dentro de tu sesión:

  1. Consulta el registro de paquetes en busca de versiones estables
  2. Selecciona automáticamente la versión más reciente publicada hace 7+ días (determinista -- sin juicio del LLM)
  3. Comprueba vulnerabilidades conocidas mediante herramientas del ecosistema y la API de OSV
  4. Verifica las firmas de los paquetes cuando estén disponibles
  5. Emite advertencias si se encuentran problemas, fija la versión exacta
  6. Registra el resultado en el registro de auditoría

La selección de versión la gestionan scripts de Python independientes incluidos con la skill, no el LLM interpretando reglas. El comando genera SELECTED: <version> y Claude usa exactamente esa versión.

Intercept Mode (Automatic)

Configura .claude/settings.json con un hook de PostToolUse para habilitar la verificación automática y transparente de paquetes:

  1. Claude escribe un archivo de manifiesto (p. ej., package.json) con la versión solicitada originalmente: el archivo se guarda en disco
  2. El hook PostToolUse se dispara inmediatamente después de completarse la escritura e invoca safer-dependencies-shim.sh
  3. El shim lee el archivo, analiza los paquetes declarados y ejecuta todas las comprobaciones de seguridad (typosquat, abandonado, CVE, obsolescencia, fijación por hash)
  4. Si se necesitan correcciones, el shim reescribe el manifiesto en el mismo lugar con versiones seguras (o elimina las entradas que no tienen una versión segura)
  5. El shim emite señales (UPDATED:, BLOCKED:, WARNING:, STALE:, MAJOR-UPDATE-CONFIRM:, REFACTOR-REQUIRED:, REGRESSION:, TYPOSQUAT-CONFIRM:, VERIFY:, CLEAN:) a través de hookSpecificOutput.additionalContext en stdout. REGRESSION: precede a MAJOR-UPDATE-CONFIRM: cuando el registro de auditoría muestra que el mismo (archivo, paquete) fue corregido previamente al mismo objetivo seguro — es decir, un subagente o un plan obsoleto ha reintroducido una versión con vulnerabilidades conocidas, y el orquestador debería restaurar la versión previamente aprobada en lugar de volver a decidir el salto mayor.
  6. Claude recibe esas señales como un recordatorio del sistema y realiza el trabajo de seguimiento (encontrar imports afectados, ejecutar pruebas, refactorizar para cambios disruptivos)

Nota de diseño — Forma C (correctiva posterior a la escritura): el hook NO bloquea escrituras. Cada versión vulnerable se guarda primero en disco y luego se corrige automáticamente dentro del mismo ciclo de uso de herramienta. Esta es una elección deliberada frente a un diseño de bloqueo con PreToolUse — consulta FAQ.md para conocer las compensaciones.

Ejemplo de señal:``` UPDATED: aiohttp 3.8.5 → 3.9.0 (HIGH: 33 CVEs fixed)

El agente padre utiliza estas señales para identificar el código afectado y refactorizar según sea necesario.

### Modo de Pre-Instalación (Hook de Bash)

Configura `.claude/settings.json` con un hook de `PreToolUse:Bash` para habilitar la auditoría previa de los comandos de instalación del gestor de paquetes. Esto complementa (no reemplaza) el Modo de Intercepción — juntos forman una defensa en capas.

1. Claude intenta una llamada a herramienta Bash (p. ej. `npm install [email protected]`)
2. El hook de `PreToolUse` se dispara antes de que la llamada se ejecute e invoca `safer-dependencies-pretooluse-bash.sh`
3. Un filtro temprano en bash puro cortocircuita los comandos que no son de gestor de paquetes en ~115 ms (sin invocar Python), por lo que `git status` / `ls` / `npm test` pagan un costo insignificante en la ruta de acceso frecuente
4. Para instalaciones reconocidas de gestores de paquetes (`npm`/`pnpm`/`yarn` `install`/`i`/`add`), el asistente tokeniza mediante `shlex`, extrae cada argumento `pkg@version` y hace POST a OSV
5. Cualquier fijación concreta vulnerable → el hook devuelve `permissionDecision: "deny"` con un GHSA-id + CVSS + resumen por hallazgo, además de una pista para invocar la skill de safer-dependencies
6. La instalación nunca se ejecuta — sin descarga de red, sin scripts de postinstall

**Por qué esto existe además del Modo de Intercepción:** el shim posterior a la escritura es ciego a Bash. `npm install [email protected]` se ejecuta por completo (y los scripts de postinstall se ejecutan) antes de que se dispare cualquier auditoría; `npm install -g typosquat-pkg` no escribe ningún manifiesto de proyecto. El Modo de Pre-Instalación cierra esas brechas estructuralmente.

El Modo de Pre-Instalación solo ve lo que el usuario **escribió** (argumentos `pkg@version` en la línea de comandos). No puede ver el árbol transitivo que el resolutor instalará realmente. **El Modo de Post-Instalación** (abajo) audita el lockfile una vez que la instalación se completa — los dos modos son complementarios, no redundantes.

**Alcance:** las CLIs de gestores de paquetes cubiertas aquí abarcan cinco ecosistemas (npm/pnpm/yarn/bun/npx/deno, pip/pip3/pipx/pipenv/uv/uvx/poetry, gem/bundle, go, cargo), más Maven a través del Modo de Intercepción (las dependencias de Maven normalmente se declaran en `pom.xml`/`build.gradle`, no se añaden mediante un verbo CLI).

> **Brecha conocida:** la CLI de Maven sí admite descargas directas mediante
> `mvn dependency:get -Dartifact=group:art:version` y `mvn dependency:copy`.
> Este hook aún no reconoce esas invocaciones. Si las usas
> con regularidad, el shim existente posterior a la escritura sigue capturando lo que llegue a
> tu manifiesto, pero la protección previa a la descarga solo se aplica a los
> ecosistemas enumerados anteriormente. Se registra como seguimiento.

Sintaxis reconocida por ecosistema:

| Gestor de paquetes | Verbos | Sintaxis de fijación concreta |
|---|---|---|
| `npm`, `pnpm`, `yarn`, `bun` | `install`, `i`, `add` (además de `yarn`/`pnpm dlx`, `bun x`, `yarn create`) | `[email protected]`, `@scope/[email protected]` |
| `npx` | (sin verbo — el paquete es el primer argumento posicional) | `[email protected]` |
| `deno` | `add`, `install` | `npm:[email protected]` (especificaciones con prefijo npm) |
| `pip`, `pip3`, `pipx`, `pipenv`, `uv`, `uvx`, `poetry` | `install` (pip/pip3/pipx/pipenv) / `add` (uv/poetry) / sin verbo (uvx) | `pkg==1.2.3` (los extras `pkg[extra]==X` también se manejan) |
| `gem`, `bundle` | `install` (gem) / `add` | `-v 1.2.3`, `--version 1.2.3`, `--version=1.2.3` (indicador separado) |
| `go` | `get`, `install` | `[email protected]` (debe incluir el prefijo `v` según los módulos de Go) |
| `cargo` | `add`, `install` | `[email protected]` |

Las fijaciones por rango (npm `^4.17`, pip `>=`, poetry `^`/`~`, Go `@latest`) y las versiones no especificadas pasan al Modo de Intercepción después de la instalación — el shim posterior a la escritura audita lo que el resolutor elija. La reescritura automática a una versión segura está pendiente como seguimiento.

**Modo de fallo:** fail-open. Cualquier error (Python ausente, corte de red, entrada malformada) sale con 0 y sin salida, permitiendo que bash continúe. El Modo de Intercepción sigue ejecutándose después de la instalación, por lo que una auditoría previa fallida degrada de forma elegante a la protección existente.

**Ejemplo de denegación:**```
safer-dependencies pre-flight audit blocked this install.
Vulnerable pinned version(s) detected:
  - [email protected] → GHSA-35jh-r3h4-6jhm (CVSS:7.4): Command Injection in lodash
Re-run with a patched version, or invoke the safer-dependencies skill
for a recommended pin.

Modo Post-Install (Hook de Bash)

Configura un hook PostToolUse:Bash en .claude/settings.json para habilitar la auditoría posterior a la ejecución después de comandos Bash. Ejecuta tres análisis independientes sobre el cwd del comando, cada uno cubriendo una brecha que los otros hooks no pueden abordar:

  • Análisis A — lockfiles. Tras un verbo de instalación exitoso (npm install, bundle install, poetry install, uv sync, go mod tidy, etc.), audita los lockfiles modificados recientemente (package-lock.json, Gemfile.lock, poetry.lock, uv.lock, go.sum, yarn.lock, pnpm-lock.yaml, Pipfile.lock). Esto cierra la brecha de CVE transitivos que Pre-Install no puede ver: el usuario escribió pkg@version, pero el resolver puede haber incorporado docenas de dependencias transitivas que nadie nombró.
  • Análisis B — manifiestos. Después de cualquier comando Bash no incluido en una denylist de solo lectura (ls, cat, git status, …), audita los manifiestos modificados recientemente. Es el único respaldo para ediciones de manifiestos hechas con sed -i, jq o un script — esas omiten la herramienta Write/Edit en la que Intercept Mode se engancha.
  • Análisis C — entorno resuelto. Un simple pip install / pip install -r requirements.txt no escribe lockfile, por lo que el Análisis A nunca ve el árbol resuelto. Tras una instalación tipo pip, el Análisis C vuelve a invocar el mismo pip con un list --format=json de solo lectura y verifica con OSV todo el entorno resuelto (directas + transitivas).

Cómo se ejecuta un análisis:

  1. Claude ejecuta una llamada a la herramienta Bash
  2. El hook PostToolUse se dispara después de que el comando se complete e invoca safer-dependencies-posttooluse-bash.sh
  3. Un filtro temprano en bash puro cortocircuita los comandos que no coinciden con ninguna puerta de análisis en ~115 ms (misma convención de ruta rápida que Pre-Install), por lo que ls / git / cat tienen un coste despreciable
  4. Cada análisis recorre cwd con find -maxdepth 5 (cubre estructuras de monorepo; excluye node_modules, .git, .venv, venv) y busca archivos modificados en los últimos 60 s — se puede sobrescribir con SAFE_DEP_POSTINSTALL_MTIME_WINDOW
  5. Para cada archivo modificado recientemente (Análisis A/B), el hook crea un payload sintético PostToolUse:Write y lo envía al shim existente — los auditores de lockfiles y manifiestos del shim se ejecutan sin cambios, sin lógica duplicada
  6. Las señales por archivo se concatenan y se emiten como un único JSON hookSpecificOutput al agente padre

Lo que detecta y que Pre-Install no: vulnerabilidades transitivas. Un bundle install de apariencia limpia puede traer [email protected] (CVE-2025-27610) como dependencia transitiva de sinatra — el usuario nunca escribió rack, por lo que Pre-Install no puede verlo, pero Post-Install lee el Gemfile.lock resuelto y reporta el CVE.

Alcance: El Análisis A no reescribe las versiones resueltas — el contrato de autocorrección solo se aplica a los manifiestos que Claude escribió directamente. Para CVE transitivos, el arreglo suele ser "actualizar la dependencia directa que posee la transitiva", lo que requiere criterio humano. El Análisis B autocorrige, porque audita los manifiestos a través de la misma ruta de shim que Intercept Mode. El Análisis A se omite cuando el nivel de comprobación transitive está ajustado a off (config set checks.transitive off).

Modo de fallo: fail-open, igual que los demás hooks. Cualquier error (falta el shim, payload malformado, Python no disponible) termina con 0 en silencio.

Ejemplo de WARNING:``` WARNING: [email protected] in lock file has GHSA-29mw-wpgm-hmr9, GHSA-35jh-r3h4-6jhm

### Modo Post-Agent (Par de Hooks de Agent)

Los cuatro modos anteriores solo se activan para llamadas a herramientas de la **sesión raíz**. Cuando la sesión raíz lanza un subagente (mediante la herramienta `Agent` — muchas skills y comandos de barra lo hacen internamente), las llamadas Write/Edit/Bash del subagente evaden todos ellos. El Modo Post-Agent es la red de seguridad reactiva para esa brecha.

1. Un hook `PreToolUse:Agent` (`safer-dependencies-pretooluse-agent.sh`) se ejecuta inmediatamente antes de cada despacho de Agent y crea un archivo centinela en `/tmp/.safer-deps-agent-<PPID>-<session_id>.sentinel` (con un nombre solo con PPID como alternativa cuando no hay id de sesión disponible)
2. El subagente se ejecuta y puede escribir manifiestos o lockfiles
3. Un hook `PostToolUse:Agent` (`safer-dependencies-posttooluse-agent.sh`) se ejecuta después de que la llamada al Agent regresa, busca con `find` todos los manifiestos y lockfiles más nuevos que el centinela y audita cada uno mediante la misma ruta del shim
4. Los hallazgos aparecen como `additionalContext` en el siguiente turno de la sesión raíz; el centinela se elimina

Los subagentes anidados se cubren automáticamente: el `PostToolUse:Agent` de la raíz se dispara solo después de que todo el trabajo del agente externo (incluido cualquier cosa que *él* haya despachado) está en disco. La única brecha es una instalación global que no escribe ningún manifiesto ni lockfile (`npm install -g …`): no hay nada que escanear. Como los otros hooks, falla en abierto: cualquier error (centinela ausente, shim ausente, payload ilegible) sale con 0 en silencio. El fundamento de diseño completo está en `skills/safer-dependencies.md`.

## Qué lo activa

La skill se activa automáticamente cuando Claude:

**Operaciones de manifiesto / instalación**
- Añade o actualiza un paquete en `package.json`, `requirements.txt`, `Gemfile`, `pom.xml`, `build.gradle`, `Cargo.toml`, `go.mod` o cualquier otro manifiesto compatible
- Escribe un `import`, `require` o `use` para un paquete aún no declarado en el manifiesto
- Genera o actualiza un lockfile (comprueba solo las entradas nuevas o cambiadas)
- Ejecuta una instalación del gestor de paquetes mediante Bash (`npm install`, `bundle install`, `poetry install`, `uv sync`, `go mod tidy`, etc.) — Pre-Install audita los argumentos del comando, Post-Install audita el lockfile resultante
- Escribe un `Dockerfile` o flujo de trabajo de CI (`.github/workflows/*.yml`, etc.) que incluya pasos de instalación del gestor de paquetes con versiones fijadas

**Preguntas de selección y recomendación**
- Comparaciones de librerías/frameworks: "¿debería usar axios o node-fetch?", "¿moment o dayjs?", "¿cuál es mejor X o Y?"
- Solicitudes de recomendación: "¿cuál es un buen cliente HTTP para Python?", "recomienda una librería de logging para Go", "¿qué paquete maneja CSV en Node?"
- Selección de versión: "¿qué versión de Django debería usar?", "¿última versión estable de Flask?"

**Expresiones de intención de uso (antes de añadir)**
- "Quiero usar FastAPI para esto", "estoy pensando en añadir Celery", "estamos viendo Prisma como ORM", "usemos Tailwind"

**Preguntas sobre salud y confianza de paquetes**
- "¿moment.js todavía se mantiene?", "¿este gem sigue activo?", "¿X está abandonado?", "¿X está EOL?", "¿puedo confiar en este paquete?", "¿cuándo fue la última actualización de faker?"

**Comandos de scaffolding**
- `npx create-react-app`, `npm create vite@latest`, `django-admin startproject`, `rails new`, `cargo new` + `cargo add`, "inicia un nuevo proyecto FastAPI"

**Adiciones implícitas de paquetes (solicitudes de funciones que implican una nueva dependencia)**
- "Añade caché Redis a la app", "conecta a Postgres", "añade autenticación JWT", "escribe código para enviar correos" — se activa cuando no hay ningún paquete para esa capacidad en el manifiesto

**Migración y portabilidad**
- "Migra de requests a httpx", "pasa de CRA a Vite", "porta de moment a date-fns" — audita el paquete entrante

Estos casos **no** lo activan:

- Importaciones de la biblioteca estándar (`os`, `fs`, `java.util.*`, etc.)
- Dependencias ya declaradas que no se están modificando
- Discusión académica sobre cómo funciona un paquete internamente ("explica el reconciler de React", "¿cómo funciona la resolución de módulos de webpack?") — las preguntas de comparación y selección sí se activan
- Instalar aplicaciones a nivel de SO, runtimes o extensiones de IDE (el propio Python, Docker, Homebrew, extensiones de VS Code)

## Qué hay en este repositorio

Esto es un **paquete de skill + hooks**, no un único archivo de skill. Una instalación completa despliega estas piezas:

| Archivo | Función |
|---|---|
| `skills/safer-dependencies.md` | La **skill** (`SKILL.md` una vez instalada). Describe los procedimientos de auditoría e incluye modo de gestión para instalación/estadísticas. |
| `skills/safer-dependencies-shim.sh` | Hook `PostToolUse:Write`/`Edit`: audita las escrituras de manifiestos y lockfiles y autocorrige las versiones vulnerables in situ (Modo Intercept). |
| `skills/safer-dependencies-pretooluse-bash.sh` | Hook `PreToolUse:Bash`: auditoría OSV previa de los comandos de instalación del gestor de paquetes; deniega pines concretos vulnerables antes de que se ejecute la instalación (Modo Pre-Install). |
| `skills/safer-dependencies-posttooluse-bash.sh` | Hook `PostToolUse:Bash`: auditoría posterior tras comandos Bash; detecta CVEs transitivos en lockfiles recién escritos, manifiestos editados mediante `sed`/`jq`/scripts y el entorno resuelto de un `pip install` simple (Modo Post-Install). |
| `skills/safer-dependencies-pretooluse-agent.sh` + `skills/safer-dependencies-posttooluse-agent.sh` | Par de hooks `PreToolUse:Agent` + `PostToolUse:Agent`: cierra la brecha de cobertura de subagentes. Los modos 2–4 solo se activan para llamadas a herramientas de la sesión raíz, por lo que cualquier manifiesto que escriba un subagente los evita. Post-Agent audita lo que el subagente escribió después de que cada llamada a la herramienta Agent regrese (Modo Post-Agent). |
| `skills/scripts/` | Biblioteca Python compartida (`safedep/`) y scripts de resolución independientes usados por todos los hooks. |
| `skills/scripts/safer_dependencies_manager.py` | Módulo de gestión para instalación interactiva, estadísticas de uso y validación de configuración. |

El archivo de skill por sí solo no es suficiente: sin hooks, la invocación automática depende de que Claude decida usar la skill. Instala las cinco piezas para una cobertura completa; muchas skills y comandos de barra despachan subagentes internamente, por lo que el par Post-Agent importa incluso si nunca generas uno explícitamente. (Consulta [FAQ.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md#why-a-skill-alone-is-not-sufficient) para saber por qué una skill por sí sola no puede garantizar la cobertura).

## Ecosistemas compatibles

| Ecosistema | Manifiesto | Lockfile |
|-----------|----------|-----------|
| npm | `package.json` | `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml` |
| PyPI | `requirements.txt`, `pyproject.toml`, `Pipfile`, `setup.py`, `setup.cfg` | `Pipfile.lock`, `poetry.lock`, `uv.lock` |
| RubyGems | `Gemfile`, `*.gemspec` | `Gemfile.lock` |
| Maven | `pom.xml`, `build.gradle`, `libs.versions.toml` | -- |
| Go | `go.mod` | `go.sum` |
| Rust | `Cargo.toml` | `Cargo.lock` |
| PHP (Composer) | `composer.json` | `composer.lock` |

## Instalación

¿Nuevo en el proyecto? Empieza con **[GETTING-STARTED.md](https://github.com/robert-auger/safer-dependencies/blob/HEAD/GETTING-STARTED.md)**. La versión corta:```bash
git clone https://github.com/robert-auger/safer-dependencies /tmp/safer-dependencies
python3 /tmp/safer-dependencies/skills/scripts/safer_dependencies_manager.py interactive_install

El instalador pregunta por el ámbito (global vs. proyecto) y qué hooks habilitar; luego escribe settings.json por ti — tanto las entradas de hooks como la lista de permisos permitidos que permite que los comandos de verificación de la skill se ejecuten sin una solicitud de aprobación en cada auditoría.

Todo lo demás relacionado con la instalación se encuentra en INSTALLATION.md, la referencia única para la mecánica de instalación: instalaciones manuales archivo por archivo (globales y a nivel de proyecto), particularidades de Windows, hooks de Post-Agent, la lista de permisos permitidos, verificación de la instalación, actualización, fijación a una etiqueta de release y desinstalación.

Después de la instalación, la gestión del día a día se realiza mediante lenguaje natural con Claude — install safer-dependencies (re-ejecutar / cambiar hooks), show safer-dependencies stats, check safer-dependencies setup — o el menú /safer-dependencies. La actualización también se realiza en la misma sesión: /safer-dependencies update aplica la última versión (update --check para una prueba en seco, update --rollback para deshacer); consulta INSTALLATION.md para el modelo de confianza.

Nota sobre plataformas: macOS, Linux y Windows son compatibles. Windows necesita Git for Windows (que proporciona bash) y Python 3 en PATH — no se requiere WSL. Las pruebas prácticas realizadas hasta la fecha se han centrado en macOS y Windows; el soporte para Linux se ejercita mediante la matriz de CI automatizada.

Configuración

Dos cosas se pueden configurar después de la instalación:

  • Lista de permisos permitidos — preaprueba los comandos de verificación de solo lectura de la skill (las reglas con la forma exacta de npm audit / bundle audit y los scripts de resolución propios de la skill) para que las auditorías se ejecuten sin una solicitud de aprobación cada vez; curl nunca se preaprueba, y npm view / pip-audit son opt-in mediante el perfil Convenience. El instalador interactivo escribe por ti las entradas principales; las instalaciones manuales añaden el bloque completo a mano. Bloque completo y justificación: INSTALLATION.md → Lista de permisos permitidos.
  • Política de seguridad — la ventana/modo de enfriamiento por antigüedad de la versión y un nivel off/warn/block por verificación para cada tipo de verificación, que se edita con /safer-dependencies config y se almacena en ~/.config/safer-dependencies/config.toml. Esquema y semántica de niveles: skills/references/configuration.md.

Niveles de advertencia

LevelMeaningExample
CRITICALDetenerse y preguntar al usuarioTyposquat detectado, firma manipulada
HIGHAdvertir y continuarCVE conocido, paquete con menos de 30 días
MEDIUMAdvertir y continuarVersión con menos de 7 días, firma faltante
LOWAdvertir y continuarGema Ruby sin firmar (esperado)

Registro de auditoría

Cada verificación se registra en ~/.claude/safer-dependencies-audit-YYYY-MM.log (un archivo por mes calendario, donde YYYY-MM es el año-mes UTC) como una sola línea JSON. Sobrescribe la ruta completa con la variable de entorno SAFE_DEP_AUDIT_LOG (cuando se establece, el sufijo de fecha no se añade). Los archivos también se rotan por tamaño cuando superan SAFE_DEP_LOG_MAX_BYTES (por defecto 10 MiB; establece 0 para desactivar). Establece SAFE_DEP_MODEL para sobrescribir el valor del modelo escrito en source.model en cada entrada — útil para comparaciones A/B entre versiones del modelo.

Los cinco modos agregan al mismo archivo. Cada entrada lleva un bloque source (esquema 2.2) que identifica qué componente la escribió:

source.componentEscrito porDisparador
shim.posttooluseshim.shEscritura de manifiesto o lockfile (Modo Interceptación, despacho Post-Install)
shim.install_errorshim.shFallo de la verificación previa de instalación del shim
bash.pretoolusepretooluse-bash.shComando de instalación de Bash (Modo Pre-Install)
bash.posttooluseposttooluse-bash.shEl propio hook Post-Install de Bash, cuando hace fail-open antes de llegar al shim
agent.pretoolusepretooluse-agent.shReservado para eventos fail-open de Pre-Agent (el propio hook es actualmente silencioso en caso de éxito)
agent.posttooluseposttooluse-agent.shEventos fail-open del hook Post-Agent (p. ej., shim faltante, python_missing)
manual.skillClaude ejecutándose en Modo NormalAuditoría manual invocada en línea

source.model registra el modelo de Claude Code activo en la sesión (p. ej., "claude-sonnet-4-6"). Presente en el esquema 2.1+; las entradas escritas por instalaciones más antiguas omiten el campo. El comando de estadísticas se degrada correctamente a "unknown" cuando está ausente.

Filtra por source.component con jq:```bash jq -r '.source.component' audit.log | sort | uniq -c | sort -rn jq -c 'select(.source.component == "bash.pretooluse")' audit.log

Surface every silent fail-open across all hooks:

jq -c 'select(.source.mode == "fail_open") | {component: .source.component, reason: .fail_open.reason, ts}' audit.log

Para facilitar el análisis, pídele a Claude las estadísticas de uso en lugar de analizar los registros manualmente:```
"Show safer-dependencies stats for the last month"

Esto proporciona resúmenes legibles por humanos de la actividad, el impacto de seguridad y las métricas de rendimiento extraídos de estos registros de auditoría.

Formas de entrada (schema 2.2). Tres formas distintas comparten el mismo encabezado ts / schema / source:

FormaCuándo se escribeCampos distintivos
Entrada de auditoríaAuditoría de manifest / lockfile / bash-installfile, ecosystem, checked, findings, abandoned, stale, typosquat, unknown, signatures, notes, clean
Entrada de error de instalaciónError de instalación en preflight del shim (componente shim.install_error)install_error, shim_dir, scripts_dir
Entrada de fail-openCualquier punto de entrada de hook sale anticipadamente debido a helper_missing / shim_missing / python_missing. source.mode es "fail_open"fail_open: { reason, detail? }

Entradas de auditoría: Intercept Mode ejecuta la canalización completa (procedencia, antigüedad de la versión, OSV, abandonado/obsoleto, typosquat, firmas), por lo que todos los arreglos pueden poblarse. Pre-Install Mode ejecuta solo OSV actualmente, por lo que abandoned / stale / typosquat / signatures siempre están vacíos. El envío posterior a la instalación (auditoría de lockfile) escribe bajo shim.posttooluse con findings poblado por cadenas WARNING: de los auditores de lockfile. El arreglo notes transporta señales informativas NOTE: (p. ej., manifest-skipped-because-unpinned).

Schema 2.2 añadió —de forma aditiva— cuatro campos a las entradas de auditoría de lockfile: lockfile, manifest_ref, relation_summary (una clasificación directa/transitiva/desconocida de cada paquete marcado respecto al manifest hermano), y un bloque policy que registra el nivel transitive vigente. El incremento es retrocompatible: los lectores de entradas 2.1 toleran los nuevos campos, y el campo source.model permanece presente desde 2.1 en adelante.```json { "ts": "2026-04-19T12:34:56Z", "schema": "2.2", "source": { "component": "shim.posttooluse", "script": "shim.sh", "hook": "PostToolUse:Write", "tool": "Write", "mode": "intercept", "model": "claude-sonnet-4-6" }, "file": "/path/to/project/package.json", "ecosystem": "npm", "checked": ["[email protected]", "[email protected]"], "findings": ["UPDATED: express 4.18.2 → 4.22.1 (HIGH: 1 CVE fixed)"], "abandoned": [], "stale": [], "typosquat": [], "unknown": [], "signatures": [], "notes": [], "clean": ["[email protected]"] }

Ejemplo del modo Pre-Install (hook de Bash, pin vulnerable denegado):```json
{
  "ts": "2026-04-23T06:56:21Z",
  "schema": "2.2",
  "source": {
    "component": "bash.pretooluse",
    "script": "pretooluse-bash.sh",
    "hook": "PreToolUse:Bash",
    "tool": "Bash",
    "mode": "intercept",
    "model": "claude-sonnet-4-6"
  },
  "file": "bash:npm install [email protected] [email protected]",
  "ecosystem": "npm",
  "checked": ["[email protected]", "[email protected]"],
  "findings": [
    "BLOCKED: [email protected] GHSA-35jh-r3h4-6jhm (CVSS:3.1/...): Command Injection in lodash"
  ],
  "abandoned": [],
  "stale": [],
  "typosquat": [],
  "unknown": [],
  "signatures": [],
  "notes": [],
  "clean": ["[email protected]"]
}

Ejemplo de modo fail-open (hook de Bash posterior a la instalación llamado sin un shim adyacente — instalación rota):```json { "ts": "2026-05-03T07:14:11Z", "schema": "2.2", "source": { "component": "bash.posttooluse", "script": "safer-dependencies-posttooluse-bash.sh", "hook": "PostToolUse", "tool": "Bash", "mode": "fail_open", "model": "claude-sonnet-4-6" }, "fail_open": { "reason": "shim_missing", "detail": "/home/alice/.claude/skills/safer-dependencies" } }

Una entrada de fail-open dice: «este hook se ejecutó pero salió temprano sin auditar porque faltaba algún requisito previo». Usa el filtro jq de arriba (`select(.source.mode == "fail_open")`) para sacar a la luz cada evento silencioso de pérdida de protección en tu registro.

Cuando el shim se ejecuta en modo dry-run (`SAFE_DEP_DRY_RUN=1`), las entradas también incluyen `"mode": "dry_run"` para que el análisis posterior pueda filtrar las invocaciones solo de auditoría.

## Requisitos

- Python 3.9+ (los hooks lo comprueban y hacen fail-open en intérpretes más antiguos)
- `curl` (para llamadas a la API del registro y comprobaciones de vulnerabilidades OSV)
- Herramientas del ecosistema (opcionales; la skill recurre a la API de OSV si faltan):
  - `npm` para paquetes npm
  - `pip-audit` para paquetes de Python
  - `bundle` para paquetes de Ruby
  - `dependency-check` para paquetes de Java

## Preguntas frecuentes

La justificación de las decisiones de diseño (por qué `PostToolUse` en lugar de `PreToolUse`, por qué no se verifican las firmas, por qué los scripts y el shim están duplicados, los problemas de carga de la skill, etc.) está documentada en [`FAQ.md`](https://github.com/robert-auger/safer-dependencies/blob/HEAD/FAQ.md).

Categorías