
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.
Cuando los asistentes de codificación con IA como Claude añaden paquetes a tu proyecto, a menudo eligen la versión que les suena 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 arriesgada escrita en un manifiesto se corrige en disco justo después de la escritura. Detecta y corrige dependencias arriesgadas — CVEs, typosquats, paquetes abandonados y problemas de antigüedad de versión, además de un período de enfriamiento para lanzamientos completamente nuevos — en npm, PyPI, RubyGems, Maven, Go, Rust y PHP (Composer). Consulta CAPABILITIES.md para ver exactamente qué está y qué no está cubierto.
¿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 (egreso de datos, sin telemetría) y CAPABILITIES.md (contra qué se defiende la herramienta y contra qué no).
Licencia (código disponible — NO es "código abierto" OSI): Gratis para 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 para monetizar el software — 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 mantener la licencia y dar crédito a este proyecto. Consulta (Sección 4 para la restricción comercial); solicitudes de licencia comercial vía .
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, detalles de Windows, la lista de permisos permitidos, actualización y desinstalación), consulta INSTALLATION.md.
Uso diario: una vez instalados los hooks, no hay nada que ejecutar — safer-dependencies funciona automáticamente en segundo plano. Cuando Claude añade o instala paquetes, marca las dependencias arriesgadas y actualiza las versiones vulnerables a una segura en el mismo lugar — y bloquea una instalación conocidamente vulnerable antes de que siquiera se ejecute — de modo que los paquetes inseguros se detectan y corrigen sin que tengas que pedirlo. Aun así puedes invocarlo directamente en cualquier momento: "¿es seguro [email protected]?", "comprueba la configuración de safer-dependencies" o "muestra las estadísticas de safer-dependencies".
Cuando Claude está a punto de añadir un paquete a tu proyecto, safer-dependencies lo intercepta y ejecuta 5 comprobaciones:
requirements.txt de PyPI con pines --hash=sha256:..., el hash declarado se valida contra los hashes publicados por PyPI; una discrepancia emite una ADVERTENCIApaperclip, request, pycrypto, github.com/dgrijalva/jwt-go) se bloquean de inmediato con una alternativa sugerida; los paquetes sin lanzamiento 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).
La skill se activa automáticamente cuando Claude:
Operaciones de manifiesto / instalación
package.json, requirements.txt, Gemfile, pom.xml, build.gradle, Cargo.toml, go.mod o cualquier otro manifiesto compatibleimport, require o use para un paquete aún no declarado en el manifiestonpm install, bundle install, poetry install, uv sync, go mod tidy, etc.) — Pre-Instalación audita los argumentos del comando, Post-Instalación audita el archivo de bloqueo resultanteDockerfile o un flujo de trabajo de CI (.github/workflows/*.yml, etc.) que incorpore pasos de instalación del gestor de paquetes con versiones fijadasPreguntas de selección y recomendación
Expresiones de intención de uso (pre-adición)
Preguntas sobre salud y confianza de paquetes
Comandos de scaffolding
npx create-react-app, npm create vite@latest, django-admin startproject, rails new, cargo new + cargo add, "inicializar un nuevo proyecto FastAPI"Adiciones implícitas de paquetes (solicitudes de funciones que implican una nueva dependencia)
Migración y portabilidad
No se activa para:
os, fs, java.util.*, etc.)Este es un paquete de skill + hooks, no un único archivo de skill. Una instalación completa despliega estas piezas:
| Archivo | Rol |
|---|---|
skills/safer-dependencies.md | La skill (SKILL.md una vez instalada). Describe los procedimientos de auditoría e incluye el modo de gestión para instalación/estadísticas. |
skills/safer-dependencies-shim.sh | Hook PostToolUse:Write/Edit — audita las escrituras de manifiestos y archivos de bloqueo y autocorrige versiones vulnerables en el mismo lugar (Modo Intercepción). |
skills/safer-dependencies-pretooluse-bash.sh | Hook PreToolUse:Bash — auditoría OSV previa al vuelo de comandos de instalación del gestor de paquetes; deniega pines concretos vulnerables antes de que la instalación se ejecute (Modo Pre-Instalación). |
skills/safer-dependencies-posttooluse-bash.sh | Hook PostToolUse:Bash — auditoría posterior al vuelo después de comandos Bash; detecta CVEs transitivos en archivos de bloqueo recién escritos, manifiestos editados vía sed/jq/scripts y el entorno resuelto de pip install simple (Modo Post-Instalación). |
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 de herramientas de la sesión raíz, por lo que cualquier manifiesto que escriba un subagente los elude. Post-Agente audita lo que el subagente escribió después de que cada llamada de herramienta Agent regrese (Modo Post-Agente). |
skills/scripts/ | Biblioteca Python compartida (safedep/) y scripts de resolución independientes utilizados 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 recurrir a 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-Agente importa incluso si nunca generas uno explícitamente. (Consulta FAQ.md para saber por qué una skill por sí sola no puede garantizar la cobertura.)
| Ecosistema | Manifiesto | Archivo de bloqueo |
|---|---|---|
| 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 |
¿Nuevo en el proyecto? Empieza con 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 solicita el ámbito (global vs. proyecto) y qué hooks habilitar, y 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 vive en **[INSTALLATION.md](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md)**, la referencia única para la mecánica de instalación: instalaciones manuales archivo por archivo (a nivel global y de proyecto), particularidades de Windows, hooks de Post-Agent, la [lista de permisos permitidos](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#permissions-allowlist), verificación de la configuración, actualización, fijación a una etiqueta de release y desinstalación.
Después de la instalación, la gestión diaria funciona 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 ocurre dentro de la sesión: `/safer-dependencies update` aplica el último release (`update --check` para una prueba en seco, `update --rollback` para deshacer); consulta [INSTALLATION.md](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#in-session-self-updater-safer-dependencies-update) para el modelo de confianza.
> **Nota de plataforma:** macOS, Linux y Windows son compatibles. Windows necesita Git for Windows (proporciona bash) y Python 3 en `PATH` — no se requiere WSL. Las pruebas prácticas hasta la fecha se han centrado en **macOS y Windows**; el soporte de Linux se ejercita mediante la matriz de CI automatizada.
### Configuración
Dos cosas son configurables después de la instalación:
- **Lista de permisos permitidos** — pre-aprueba los comandos de verificación de solo lectura de la skill (las reglas de forma exacta `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 pre-aprueba, y `npm view` / `pip-audit` son opcionales mediante el perfil de Conveniencia. El instalador interactivo escribe las entradas principales por ti; las instalaciones manuales añaden el bloque completo a mano. Bloque completo y justificación: [INSTALLATION.md → Lista de permisos permitidos](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#permissions-allowlist).
- **Política de seguridad** — la ventana/modo de enfriamiento por antigüedad del release y un nivel `off`/`warn`/`block` por verificación para cada tipo de verificación, editado con `/safer-dependencies config` y almacenado en `~/.config/safer-dependencies/config.toml`. Esquema y semántica de niveles: [`skills/references/configuration.md`](https://github.com/robert-auger/safer-dependencies/blob/main/skills/references/configuration.md).
### Cambiar el período de enfriamiento
El enfriamiento (llamado **cooloff** en la configuración) es la antigüedad mínima que un release debe alcanzar antes de que la skill lo seleccione — por defecto **7 días**. Para cambiarlo, pídele a Claude o ejecuta el comando de configuración directamente:```
/safer-dependencies config set cooloff.days 14 # require releases to be 14+ days old
/safer-dependencies config set cooloff.mode block # gate strength: off | warn | block (default: warn)
/safer-dependencies config unset cooloff.days # revert to the 7-day default
/safer-dependencies config # show effective values and where each comes from
Los mismos verbos funcionan fuera de una sesión de Claude:```bash python3 skills/scripts/safer_dependencies_manager.py config set cooloff.days 14
La configuración persiste en `~/.config/safer-dependencies/config.toml` (la sección `[cooloff]`); las variables de entorno `SAFE_DEP_COOLOFF_DAYS` y `SAFE_DEP_COOLOFF_MODE` anulan el archivo por sesión. Tres comportamientos a conocer: `mode = "off"` elimina por completo el filtro de antigüedad de la selección de versiones; una reescritura impulsada por CVE omite la restricción, por lo que una corrección de seguridad nunca se retiene por ser demasiado reciente; y la restricción cubre npm, PyPI, RubyGems y crates.io — Maven y Go no están restringidos intencionalmente. Semántica completa: [`skills/references/configuration.md`](https://github.com/robert-auger/safer-dependencies/blob/main/skills/references/configuration.md).
## Niveles de advertencia
| Nivel | Significado | Ejemplo |
|-------|-------------|---------|
| CRITICAL | Detenerse y preguntar al usuario | Typosquat detectado, firma manipulada |
| HIGH | Advertir y continuar | CVE conocido, paquete con menos de 30 días |
| MEDIUM | Advertir y continuar | Versión con menos de 7 días, firma faltante |
| LOW | Advertir y continuar | Gem de Ruby sin firmar (esperado) |
## Cómo funciona
La habilidad opera en cinco modos (resumidos a continuación; el fundamento de diseño más profundo se encuentra en `skills/safer-dependencies.md`):
### Modo Normal (Manual)
Cuando Claude está a punto de escribir un `import`, agregar un paquete a un manifiesto o actualizar un archivo de bloqueo, la habilidad se ejecuta en línea en tu sesión:
1. Consulta el registro de paquetes para obtener 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 versiones la manejan scripts de Python independientes incluidos con la habilidad, no el LLM interpretando reglas. El comando genera `SELECTED: <version>` y Claude usa esa versión exactamente.
### Modo de Intercepción (Automático)
Configura `.claude/settings.json` con un hook `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 el disco
2. El hook `PostToolUse` se activa inmediatamente después de que se complete 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, desactualización, fijación por hash)
4. Si se necesitan correcciones, el shim **reescribe el manifiesto en su 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:`) mediante `hookSpecificOutput.additionalContext` en stdout. `REGRESSION:` precede a un `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 desactualizado ha reintroducido una versión con vulnerabilidad conocida, y el orquestador debe restaurar la versión previamente aprobada en lugar de volver a decidir el salto de versión 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 incompatibles)
**Nota de diseño — Forma C (correctiva posterior a la escritura):** el hook NO bloquea las escrituras. Cada versión vulnerable se guarda primero en el disco y luego se corrige automáticamente dentro del mismo ciclo de uso de la herramienta. Esta es una elección deliberada frente a un diseño de bloqueo `PreToolUse` — consulta [FAQ.md](https://github.com/robert-auger/safer-dependencies/blob/main/FAQ.md#why-posttooluse-post-write-corrective-instead-of-pretooluse-pre-write-blocking-for-the-manifest-path) para conocer las ventajas y desventajas.
**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 refactorizarlo según sea necesario.
Configura .claude/settings.json con un hook PreToolUse:Bash para habilitar
la auditoría previa al vuelo de los comandos de instalación del gestor de paquetes.
Esto complementa (no reemplaza) el Modo Interceptación — juntos forman una defensa en capas.
npm install [email protected])PreToolUse se dispara antes de que se ejecute la llamada e invoca
safer-dependencies-pretooluse-bash.shgit status / ls / npm test pagan
un coste insignificante en la ruta críticanpm/pnpm/yarn
install/i/add), el helper tokeniza mediante shlex, extrae cada
argumento pkg@version y lo envía por POST a OSVpermissionDecision: "deny" con un GHSA-id por hallazgo + CVSS +
resumen, más una pista para invocar la skill safer-dependenciesPor qué existe además del Modo Interceptación: el shim posterior a la escritura
es ciego a Bash. npm install [email protected] se ejecuta hasta el final (y los
scripts 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 Pre-Instalación
cierra esas brechas estructuralmente.
El Modo 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 resolvedor
instalará realmente. El Modo Post-Instalación (abajo) audita el lockfile una vez
que la instalación se completa — los dos modos son complementarios, no redundantes.
Alcance: las CLI 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), además de Maven mediante el Modo Interceptación (las dependencias de Maven normalmente se
declaran en pom.xml/build.gradle, no se añaden mediante un verbo de CLI).
Brecha conocida: la CLI de Maven sí admite descargas directas mediante
mvn dependency:get -Dartifact=group:art:versionymvn dependency:copy. Este hook aún no reconoce esas invocaciones. Si las usas con regularidad, el shim posterior a la escritura existente sigue capturando lo que llegue a tu manifiesto, pero la protección previa al fetch solo se aplica a los ecosistemas listados arriba. Se registra como seguimiento.
Sintaxis reconocida por ecosistema:
| PM | Verbos | Sintaxis de pin concreto |
|---|---|---|
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 gestionan) |
gem, bundle | install (gem) / add | -v 1.2.3, --version 1.2.3, --version=1.2.3 (flag separado) |
go | get, install | [email protected] (debe incluir el prefijo v según los módulos de Go) |
cargo | add, install | [email protected] |
Los pines de rango (npm ^4.17, pip >=, poetry ^/~, Go @latest) y las
versiones no especificadas pasan al Modo Interceptación después de la instalación — el
shim posterior a la escritura audita lo que el resolvedor elija. La reescritura automática a una
versión segura está en cola como seguimiento.
Modo de fallo: fail-open. Cualquier error (Python ausente, fallo de red, entrada malformada) sale con 0 y sin salida, permitiendo que bash continúe. El Modo Interceptación sigue ejecutándose después de la instalación, por lo que un fallo previo al vuelo degrada con elegancia a la protección existente.
Ejemplo de denegación:``` safer-dependencies pre-flight audit blocked this install. Vulnerable pinned version(s) detected:
### Modo Post-Instalación (Hook de Bash)
Configura `.claude/settings.json` con un hook `PostToolUse:Bash` para habilitar
la auditoría posterior a la ejecución 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 — archivos de bloqueo.** Tras un verbo de instalación exitoso (`npm install`,
`bundle install`, `poetry install`, `uv sync`, `go mod tidy`, etc.), audita
los archivos de bloqueo recién modificados (`package-lock.json`, `Gemfile.lock`,
`poetry.lock`, `uv.lock`, `go.sum`, `yarn.lock`, `pnpm-lock.yaml`,
`Pipfile.lock`). Esto cubre la **brecha de CVEs transitivos** que Pre-Instalación no puede
ver: el usuario escribió `pkg@version`, pero el resolvedor puede haber incorporado
docenas de dependencias transitivas que nadie nombró.
- **Análisis B — manifiestos.** Tras cualquier comando Bash *no* incluido en una
lista de denegación de solo lectura (`ls`, `cat`, `git status`, …), audita los
manifiestos recién modificados. Este es el **único** respaldo para ediciones de manifiestos
realizadas mediante `sed -i`, `jq` o un script — estas evitan la herramienta
`Write`/`Edit` sobre la que se basa el Modo Interceptación.
- **Análisis C — entorno resuelto.** Un `pip install` simple /
`pip install -r requirements.txt` no escribe ningún archivo de bloqueo, 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 el entorno
resuelto completo (directo + transitivo).
Cómo se ejecuta un análisis:
1. Claude ejecuta una llamada a la herramienta Bash
2. El hook `PostToolUse` se activa *después* de que el comando se completa 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-Instalación), por lo que `ls` / `git` / `cat`
tienen un costo insignificante
4. Cada análisis recorre `cwd` con `find -maxdepth 5` (cubre diseños de monorepos;
excluye `node_modules`, `.git`, `.venv`, `venv`) buscando archivos modificados dentro de
los últimos 60 s — se puede anular mediante `SAFE_DEP_POSTINSTALL_MTIME_WINDOW`
5. Para cada archivo recién modificado (Análisis A/B), el hook forja una carga útil
sintética de `PostToolUse:Write` y la envía al shim existente — los auditores de archivos de bloqueo
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 de `hookSpecificOutput`
al agente padre
**Qué detecta que Pre-Instalación no detecta:** vulnerabilidades transitivas.
Un `bundle install` de apariencia limpia puede incorporar `[email protected]` (CVE-2025-27610)
como dependencia transitiva de `sinatra` — el usuario nunca escribió `rack`, por lo que
Pre-Instalación no puede verlo, pero Post-Instalación lee el
`Gemfile.lock` resuelto e informa el CVE.
**Alcance:** El Análisis A no reescribe versiones resueltas — el contrato de
auto-corrección solo se aplica a manifiestos que Claude escribió directamente. Para CVEs transitivos,
la solución suele ser "actualizar la dependencia directa que posee la transitiva", lo cual
requiere criterio humano. El Análisis B *sí* auto-corrige, porque audita manifiestos
a través de la misma ruta de shim que el Modo Interceptación. El Análisis A se omite cuando el
nivel de verificación `transitive` está configurado en `off` (`config set checks.transitive off`).
**Modo de fallo:** fail-open, igual que los otros hooks. Cualquier error (shim
faltante, carga útil malformada, Python no disponible) sale con código 0 en silencio.
**Ejemplo de ADVERTENCIA:**```
WARNING: [email protected] in lock file has GHSA-29mw-wpgm-hmr9, GHSA-35jh-r3h4-6jhm
Los cuatro modos anteriores solo se activan para llamadas a herramientas de la sesión raíz. Cuando la sesión raíz despacha un subagente (a través de la herramienta Agent — muchas skills y comandos de barra hacen esto internamente), las llamadas Write/Edit/Bash del subagente omiten todos ellos. El Modo Post-Agente es la red de seguridad reactiva para esa brecha.
PreToolUse:Agent (safer-dependencies-pretooluse-agent.sh) se ejecuta inmediatamente antes de cada despacho de Agent y toca un archivo centinela en /tmp/.safer-deps-agent-<PPID>-<session_id>.sentinel (con respaldo a un nombre solo con PPID cuando no hay id de sesión disponible)PostToolUse:Agent (safer-dependencies-posttooluse-agent.sh) se ejecuta después de que la llamada de Agent retorna, hace find de cada manifest y lockfile más reciente que el centinela, y audita cada uno a través de la misma ruta del shimadditionalContext en el siguiente turno de la sesión raíz; el centinela se eliminaLos subagentes anidados se cubren automáticamente — el PostToolUse:Agent de la raíz solo se activa después de que todo el trabajo del agente externo (incluyendo cualquier cosa que él haya despachado) esté en disco. La única brecha es una instalación global que no escribe ningún manifest ni lockfile (npm install -g …): no hay nada que escanear. Como los otros hooks, falla abierto — cualquier error (centinela faltante, shim faltante, payload ilegible) sale con 0 silenciosamente. El fundamento completo del diseño está en skills/safer-dependencies.md.
Cada comprobació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 en 0 para deshabilitar). Establece SAFE_DEP_MODEL para sobrescribir el valor del modelo escrito en source.model en cada entrada — útil para comparaciones A/B entre versiones de modelos.
Los cinco modos añaden al mismo archivo. Cada entrada lleva un bloque source (esquema 2.2) que identifica qué componente lo escribió:
source.component | Escrito por | Disparador |
|---|---|---|
shim.posttooluse | shim.sh | Escritura de manifest o lockfile (Modo Interceptación, despacho Post-Instalación) |
shim.install_error | shim.sh | Fallo de instalación de preflight del shim |
bash.pretooluse | pretooluse-bash.sh | Comando de instalación Bash (Modo Pre-Instalación) |
bash.posttooluse | posttooluse-bash.sh | El propio hook Bash Post-Instalación, cuando falla abierto antes de alcanzar el shim |
agent.pretooluse | pretooluse-agent.sh | Reservado para eventos de fallo abierto Pre-Agente (el hook en sí es actualmente silencioso en éxito) |
agent.posttooluse | posttooluse-agent.sh | Eventos de fallo abierto del hook Post-Agente (p. ej. shim faltante, python_missing) |
manual.skill | Claude ejecutando Modo Normal | Auditorí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 degrada con elegancia 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
jq -c 'select(.source.mode == "fail_open") | {component: .source.component, reason: .fail_open.reason, ts}' audit.log
Para un análisis más sencillo, pide a Claude 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 en la seguridad y las métricas de rendimiento extraídas de estos registros de auditoría.
Formas de entrada (esquema 2.2). Tres formas distintas comparten el mismo encabezado ts / schema / source:
| Forma | Cuándo se escribe | Campos distintivos |
|---|---|---|
| Entrada de auditoría | Auditoría de manifiesto / lockfile / instalación bash | file, ecosystem, checked, findings, abandoned, stale, typosquat, unknown, signatures, notes, clean |
| Entrada de error de instalación | Error de instalación previo al shim (componente shim.install_error) | install_error, shim_dir, scripts_dir |
| Entrada de fail-open | Cualquier punto de entrada de hook sale de forma anticipada debido a helper_missing / shim_missing / python_missing. source.mode es "fail_open" | fail_open: { reason, detail? } |
Entradas de auditoría: El modo de intercepción ejecuta el pipeline completo (procedencia, antigüedad de versión, OSV, abandonado/obsoleto, typosquat, firmas), por lo que todos los arrays pueden poblarse. El modo de preinstalación ejecuta solo OSV hoy en día, 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 array notes transporta señales informativas NOTE: (p. ej., manifiesto omitido porque no está fijado).
El esquema 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 frente al manifiesto hermano) y un bloque policy que registra el nivel transitive en vigor. El cambio es compatible con versiones anteriores: 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]"]
}
Pre-Install Mode example (Bash hook, vulnerable pin denied):```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]"]
}
Fail-open Mode example (Post-Install Bash hook called with no shim adjacent — broken install):```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 indica: "este hook se ejecutó pero salió temprano sin auditar porque faltaba algún requisito previo." Usa el filtro jq anterior (`select(.source.mode == "fail_open")`) para sacar a la superficie 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 detectan 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 (opcional, 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
## FAQ
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, problemas de carga de la skill, etc.) está documentada en [`FAQ.md`](https://github.com/robert-auger/safer-dependencies/blob/main/FAQ.md).