---
name: dependencias-auditoria
description: Auditoría completa de dependencias del proyecto. Detecta CVEs conocidos, licencias incompatibles con el uso comercial, dependencias abandonadas sin alternativa, y genera una estrategia de actualización priorizada. Aplica a proyectos Python, Node.js/TypeScript, y contenedores Docker.
version: "1.0.0"
herramientasPermitidas: [Read, Bash]
evolvable: true  # default para skill estandar
nist_csf: [ID.RA-01, GV.SC-07, PR.PS-01, DE.CM-09]
nist_ai_rmf: [MAP-1.6]
attack_techniques: [T1195.002]
exclusiones:
  - "No cargar para revisión de seguridad del código fuente (OWASP, inyección, auth) — para seguridad de código cargar `checklist-seguridad`."
  - "No cargar para actualizar versiones de dependencias con breaking changes — para migraciones de versión cargar `deprecacion-migracion`."
  - "No cargar para análisis de rendimiento de bundles JavaScript (tree-shaking, code splitting) — para rendimiento cargar `react-optimizacion` o equivalente."
  - "No cargar para gestión de secretos o rotación de credenciales de servicios externos — para secretos cargar `iam-secretos`."
---
# Habilidad: Auditoría de Dependencias

## Cuándo NO cargar

- La revisión es de seguridad del código fuente (inyección SQL, XSS, OWASP): cargar `checklist-seguridad`.
- La tarea es actualizar dependencias con breaking changes y guiar la migración: cargar `deprecacion-migracion`.
- El análisis es de rendimiento de bundles JS (tree-shaking, bundle size): cargar `react-optimizacion` o el skill de frontend correspondiente.
- La gestión es de secretos, credenciales o rotación de API keys: cargar `iam-secretos`.

## Propósito

Las dependencias son el vector de ataque más subestimado. El 80% de los ataques
de cadena de suministro (supply chain attacks) explotan dependencias con CVEs
conocidos y disponibles públicamente. Esta habilidad detecta el riesgo antes
de que se convierta en incidente.

## Cuándo activar

- Antes de cada deploy a producción
- Al comenzar a trabajar en un proyecto heredado
- Cuando se reporta una vulnerabilidad que podría afectar el stack
- Trimestralmente como revisión de mantenimiento
- Antes de una auditoría de seguridad o certificación

---

## Categorías de riesgo en dependencias

### Categoría 1 — CVEs conocidos (CRÍTICO)

Un CVE (Common Vulnerabilities and Exposures) en una dependencia directa o
transitiva es un riesgo activo. La severidad se mide con CVSS:

| CVSS Score | Severidad | Acción requerida |
|-----------|----------|-----------------|
| 9.0 - 10.0 | Crítica | Fix inmediato — bloquea deploy |
| 7.0 - 8.9 | Alta | Fix en 48 horas |
| 4.0 - 6.9 | Media | Fix en próximo sprint |
| 0.1 - 3.9 | Baja | Registrar, resolver en backlog |

### Categoría 2 — Licencias incompatibles (ALTO)

Dependencias con licencias restrictivas en proyectos comerciales:

| Licencia | Riesgo en proyecto comercial |
|----------|----------------------------|
| GPL v2/v3 | ALTO — puede requerir open-source del código propio |
| AGPL | CRÍTICO — cualquier uso de red activa la cláusula |
| LGPL | MEDIO — revisar caso a caso |
| SSPL | ALTO — restricciones en servicios cloud |
| MIT, Apache 2.0, BSD | Bajo riesgo — permisivas |
| ISC, 0BSD | Sin riesgo — extremadamente permisivas |

### Categoría 3 — Dependencias abandonadas (MEDIO)

Una dependencia abandonada es aquella que:
- Sin commits en el repositorio por más de 18 meses
- Sin versión nueva en más de 12 meses para proyectos activos
- Issues críticos sin respuesta por más de 6 meses
- El mantenedor ha declarado públicamente el abandono

### Categoría 4 — Dependencias desactualizadas (BAJO-MEDIO)

Versiones con 2+ versiones major de atraso acumulan:
- CVEs parcheados en versiones nuevas
- Incompatibilidades futuras con el ecosistema
- Pérdida de soporte técnico de la comunidad

---

## Herramientas y comandos por stack

### Python

```bash
# pip-audit: CVEs en dependencias Python (recomendado)
pip install pip-audit
pip-audit --output=json > audit-python.json
pip-audit  # Output legible para humanos

# safety: Base de datos de vulnerabilidades de PyUp.io
pip install safety
safety check --json > safety-report.json

# Licencias de todas las dependencias
pip install pip-licenses
pip-licenses --format=json --with-urls > licenses.json
pip-licenses --format=markdown  # Output legible

# Dependencias desactualizadas
pip list --outdated --format=json

# Ver árbol completo de dependencias transitivas
pip install pipdeptree
pipdeptree --warn silence --json-tree > deptree.json
```

### Node.js / TypeScript

```bash
# npm audit: CVEs en dependencias Node.js
npm audit --json > npm-audit.json
npm audit  # Output legible

# Para yarn
yarn audit --json > yarn-audit.json

# Licencias
npx license-checker --json > npm-licenses.json
npx license-checker --excludePrivatePackages --onlyAllow \
  "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC;0BSD"

# Dependencias desactualizadas
npm outdated --json

# Verificar dependencias no usadas
npx depcheck

# Tamaño del bundle por dependencia
npx cost-of-modules
```

### Docker / Contenedores

```bash
# Trivy: CVEs en imagen Docker (recomendado)
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image --format json [nombre-imagen]:latest > trivy-report.json

# Grype: alternativa a Trivy
grype [nombre-imagen]:latest

# Ver imagen base y su historial
docker inspect [nombre-imagen] | jq '.[0].Config.Image'

# Verificar si la imagen base es reciente
# Comparar con el digest publicado en Docker Hub
```

---

## Proceso de auditoría paso a paso

### Paso 1 — Inventario inicial

```bash
# Python: listar todas las dependencias con versión exacta
pip freeze > requirements-audit.txt
# Comparar con requirements.txt original para detectar dependencias no declaradas

# Node: listar todo el árbol
npm ls --all 2>/dev/null | head -100

# Verificar si hay dependencias directas no declaradas en package.json
npx depcheck
```

### Paso 2 — Escaneo de CVEs

Ejecutar todos los scanners disponibles para el stack. Los resultados se guardan
en formato JSON para procesamiento posterior.

### Paso 3 — Análisis de licencias

```bash
# Python: identificar licencias no permitidas
pip-licenses --fail-on="GPL;AGPL;LGPL;SSPL" 2>&1
# Exit code != 0 si encuentra licencias problemáticas

# Node: verificar lista blanca de licencias
npx license-checker --onlyAllow "MIT;Apache-2.0;BSD-2-Clause;BSD-3-Clause;ISC"
```

### Paso 4 — Identificar dependencias abandonadas

Para cada dependencia directa, verificar en su repositorio:
- Fecha del último commit
- Fecha del último release
- Issues abiertos sin respuesta
- Estado del repositorio (archived, deprecated)

```bash
# Script para verificar última versión en PyPI
python -c "
import json, urllib.request
packages = open('requirements.txt').read().split()
for pkg in packages[:20]:
    name = pkg.split('==')[0].split('>=')[0]
    try:
        url = f'https://pypi.org/pypi/{name}/json'
        data = json.loads(urllib.request.urlopen(url).read())
        last = max(data['releases'].keys())
        print(f'{name}: última versión {last}')
    except: pass
"
```

---

## Plantilla de reporte: `DEPENDENCIES-AUDIT.md`

```markdown
# DEPENDENCIES-AUDIT.md
**Fecha**: [fecha]  **Stack**: [Python/Node/Docker/todos]

## Resumen ejecutivo
| Categoría | Críticos | Altos | Medios | Bajos |
|-----------|---------|-------|--------|-------|
| CVEs | | | | |
| Licencias | | | | |
| Abandonadas | | | | |
| Desactualizadas | | | | |

**Decisión de deploy**: BLOQUEADO / APROBADO CON PLAN / APROBADO

---

## CVEs encontrados

### [CRÍTICO] [Nombre de la dependencia] v[X.Y.Z]
- **CVE**: CVE-XXXX-XXXXX
- **CVSS**: [score]
- **Descripción**: [qué hace vulnerable]
- **Versión parcheada**: [versión que resuelve el CVE]
- **Comando de actualización**: `pip install [paquete]==[version]`
- **Dependencia directa**: Sí / No (transitiva vía [paquete])
- **Plan de acción**: [actualizar / reemplazar / parchear temporalmente]
- **Deadline**: [fecha]

[Repetir para cada CVE]

---

## Licencias problemáticas

| Paquete | Versión | Licencia | Riesgo | Alternativa |
|---------|---------|---------|--------|------------|
|         |         |         |        |            |

---

## Dependencias abandonadas

| Paquete | Último commit | Último release | Alternativa recomendada |
|---------|-------------|---------------|------------------------|
|         |             |               |                        |

---

## Dependencias desactualizadas (alta prioridad)

| Paquete | Versión actual | Última versión | Versiones de atraso | Prioridad |
|---------|---------------|----------------|--------------------| ----------|
|         |               |                |                    |           |

---

## Estrategia de actualización

### Sprint actual (bloqueos de deploy)
- [ ] [dependencia]: actualizar a [versión] — CVE crítico

### Próximo sprint
- [ ] [dependencia]: actualizar a [versión] — CVE alto

### Backlog de mantenimiento
- [ ] [dependencia]: evaluar reemplazo por [alternativa]

---

## Dependencias monitoreadas (sin acción inmediata)
| Paquete | Razón de monitoreo | Próxima revisión |
|---------|-------------------|-----------------|
|         |                   |                 |
```

---

## Automatización recomendada

Integrar en el pipeline CI/CD:

```yaml
# GitHub Actions — auditoría automática en cada PR
- name: Auditoría de dependencias Python
  run: |
    pip-audit --fail-on-severity high
    # Falla el pipeline si hay CVEs altos o críticos sin resolver

- name: Auditoría de dependencias Node
  run: npm audit --audit-level=high
```

Configurar renovación automática con Dependabot o Renovate Bot para dependencias
con actualizaciones de parche (patch) que no rompen la API.

## Gotchas / Errores comunes no obvios

**`pip-audit` reporta cero CVEs pero hay una dependencia transitiva vulnerable que `pip freeze` no muestra explícitamente**: `pip-audit` analiza el entorno instalado, pero si la dependencia vulnerable es transitiva de una dependencia directa desactualizada, puede no aparecer en `requirements.txt`. Causa: los entornos Python sin `pip freeze` completo tienen dependencias transitivas "flotantes" que se resuelven al instalar sin estar declaradas. Fix: ejecutar `pip freeze > requirements-full.txt` y auditar ese archivo completo, no solo `requirements.txt`. Alternativamente usar `pip-audit --requirement requirements-full.txt` o `pipdeptree` para ver el árbol completo.

**`npm audit` muestra 0 vulnerabilidades pero Trivy detecta CVEs en la imagen Docker**: `npm audit` analiza `node_modules/` en el sistema de archivos, mientras Trivy analiza las capas de la imagen donde las dependencias pueden diferir si el Dockerfile usa `npm ci --production` o tiene multi-stage builds. Causa: el entorno de desarrollo y el contenedor de producción pueden tener diferentes versiones si el lockfile no está commiteado o si se usa `--production`. Fix: ejecutar `trivy image` sobre la imagen de producción construida, no solo `npm audit` en el source. Son complementarios, no equivalentes.

**Una dependencia con licencia MIT tiene una subdependencia con licencia AGPL no detectada por `license-checker`**: `license-checker` analiza el campo `license` en `package.json`, pero una dependencia puede tener subdependencias con licencias diferentes que solo se ven en su árbol de dependencias transitivas. Causa: `license-checker --production` solo reporta las licencias declaradas en el nivel superior de cada paquete. Fix: para proyectos con requerimientos legales estrictos, usar `license-checker --failOn AGPL` para detectar AGPL en el árbol completo, y revisar manualmente las dependencias con licencias mixtas o duales.

**`pip-audit` en CI falla con "connection refused" porque el sistema no tiene acceso a la red de PyPI Vulnerability DB**: `pip-audit` por defecto consulta `https://osv.dev` para obtener las vulnerabilidades. En entornos CI con acceso a red restringido (firewalls corporativos, redes internas), la consulta falla silenciosamente o lanza error de red en lugar de decir "cero CVEs". Causa: la ausencia de resultados se confunde con "sin vulnerabilidades" cuando en realidad el scanner no pudo conectarse. Fix: configurar `pip-audit --local` para usar la base de datos local de OSV descargada previamente, o verificar que el exit code del comando es `0` (no errores) en lugar de solo ver el output de texto.
