El Punto Ciego del Vibe Coding: Tu Agente de IA No Revisa Licencias

Tu agente de IA instala paquetes para resolver problemas. No verifica si son GPL, no tienen licencia, o vienen de un mirror dudoso. Así protegés tu proyecto.

Le pedís a tu agente de IA que resuelva un problema de generación de PDFs. Cinco minutos después, instaló pandoc (GPL-2.0), trajo un conversor WASM con licencia ambigua, y resolvió una dependencia desde un mirror no oficial. El problema está resuelto. El código funciona.

Pero ahora tu proyecto tiene una dependencia GPL, un binario WASM cuya licencia no coincide con su wrapper JavaScript, y un binario descargado de una fuente sin garantías de integridad. El agente no verificó nada de esto. No fue diseñado para hacerlo.

Me crucé con esto más de una vez trabajando en productos comerciales. Paquetes como estos aparecen en tu árbol de dependencias sin ninguna fricción, y para cuando alguien se da cuenta, el código ya está en producción. Este post es lo que me hubiese gustado tener antes de que eso pasara — una guía práctica para detectar estos problemas temprano y automatizar el check para no tener que pensarlo.

⚡ Cómo Sucede

Los agentes de IA optimizan para resolver el problema que describiste. Buscan en npm, crates.io, PyPI, GitHub — lo que sea que produzca una solución funcional lo más rápido posible. Lo que no hacen:

  • Leer el campo license en package.json
  • Distinguir entre MIT y GPL
  • Saber que tu proyecto es un producto comercial
  • Verificar si un binario .wasm fue compilado desde código fuente GPL
  • Comprobar si un mirror es oficial o de confianza

No hay malicia. El agente es simplemente indiferente al licensing. Y cuando te movés rápido con desarrollo asistido por IA, esa indiferencia se acumula en silencio.

🔍 Cuatro Riesgos que Vale la Pena Conocer

1. Contaminación GPL/AGPL

GPL es una licencia copyleft. Si tu proyecto linkea contra una dependencia GPL, tu proyecto también debe distribuirse bajo GPL — o no podés distribuirlo. AGPL extiende esto al uso en red: si los usuarios interactúan con tu software a través de una red (es decir, la mayoría de los productos SaaS), debés proveer el código fuente.

No son solo dependencias directas. Si el paquete A es MIT pero depende del paquete B que es GPL, la GPL se propaga hacia arriba del árbol.

Ejemplos conocidos: pandoc (GPL-2.0), ghostscript (AGPL-3.0), ffmpeg (GPL-2.0+ dependiendo de los flags de compilación).

2. Sin Licencia = Sin Permiso

Un error común: si un paquete no tiene licencia, es libre de usar. Bajo la ley de copyright, es lo contrario — sin licencia significa todos los derechos reservados. No tenés permiso legal para usarlo, copiarlo o distribuirlo.

Los paquetes npm con el campo license vacío, o con "UNLICENSED" en package.json, caen en esta categoría. El agente los instala como cualquier otro paquete.

3. Binarios WASM — La Caja Negra

Un paquete npm puede tener un wrapper JavaScript con licencia MIT alrededor de un binario .wasm compilado desde código C, C++ o Rust. El binario hereda la licencia de su código fuente, no la del wrapper.

svg2pdf-wasm lo ilustra bien: el paquete npm puede declarar una licencia, pero el binario compilado viene de un crate de Rust con sus propios términos. El agente solo lee package.json. Nunca verifica la procedencia del binario.

4. Mirrors No Oficiales y Supply Chain

Cuando un agente resuelve dependencias, puede descargar de fuentes no estándar — mirrors no oficiales, proxies de npm, o forks de GitHub de paquetes abandonados. No son necesariamente maliciosos, pero pierden las garantías de integridad de los registros oficiales.

Algunos paquetes también ejecutan scripts postinstall que descargan binarios adicionales en el momento de la instalación. El paquete npm puede ser MIT, pero el binario que descarga puede tener términos completamente distintos.

RiesgoSeñal de alertaImpacto
GPL en proyecto comerciallicense: GPL-* o AGPL-* en package.jsonDebés abrir tu código o dejar de distribuir
Sin licenciaCampo license ausente o UNLICENSEDSin permiso legal de uso
Licencia WASM inconsistenteArchivos .wasm en node_modulesLicencia del binario ≠ licencia del wrapper
Fuente no oficialURLs no estándar en scripts postinstallSin garantías de integridad

🛠️ La Receta para el Dev Individual

Tres checks antes de deployar. Sin dependencias extra — solo tu package manager y herramientas estándar de shell.

Paso 1: Listar Todas las Licencias

pnpm tiene un comando nativo para esto:

pnpm licenses list --prod

npm no tiene un equivalente nativo, pero todo package.json tiene un campo license. Podés extraerlos todos:

find node_modules -maxdepth 2 -name "package.json" -exec \
  jq -r '[.name, .version, .license // "NONE"] | @tsv' {} \; 2>/dev/null \
  | sort

Esto te da la lista completa: nombre del paquete, versión y licencia. Buscá cualquier cosa que no sea MIT, ISC, BSD o Apache.

Paso 2: Encontrar Licencias Problemáticas

Filtrá por GPL, AGPL, o paquetes sin licencia:

# Dependencias GPL/AGPL
pnpm licenses list --prod 2>/dev/null | grep -iE "GPL|AGPL"

# Paquetes sin campo license
find node_modules -maxdepth 2 -name "package.json" -exec \
  jq -r 'select(.license == null or .license == "" or .license == "UNLICENSED") | .name' {} \; 2>/dev/null

Si alguno de estos devuelve resultados, pará e investigá antes de shippear.

Paso 3: Encontrar Binarios WASM y Scripts Postinstall

Estas son preocupaciones de supply chain que ningún campo de licencia te va a revelar:

# Binarios WASM en tus dependencias
find node_modules -name "*.wasm" 2>/dev/null

# Paquetes con scripts postinstall (pueden descargar binarios arbitrarios)
find node_modules -maxdepth 2 -name "package.json" -exec \
  jq -r 'select(.scripts.postinstall != null) | "\(.name): \(.scripts.postinstall)"' {} \; 2>/dev/null

Si encontrás archivos .wasm, verificá el repositorio fuente. La licencia del paquete npm no es autoritativa para binarios compilados — el binario hereda la licencia del código desde el que fue compilado.

Juntando Todo

Un solo script que cubre los tres checks:

#!/bin/bash
# license-audit.sh — cero dependencias, solo shell + jq
set -euo pipefail

BLOCKED="GPL\|AGPL\|SSPL"
EXIT_CODE=0

echo "── Auditoría de licencias ──"
PROBLEMS=$(pnpm licenses list --prod 2>/dev/null | grep -iE "$BLOCKED" || true)
if [ -n "$PROBLEMS" ]; then
  echo "Licencias copyleft encontradas:"
  echo "$PROBLEMS"
  EXIT_CODE=1
fi

echo "── Licencias faltantes ──"
MISSING=$(find node_modules -maxdepth 2 -name "package.json" -exec \
  jq -r 'select(.license == null or .license == "" or .license == "UNLICENSED") | .name' {} \; 2>/dev/null)
if [ -n "$MISSING" ]; then
  echo "Paquetes sin licencia:"
  echo "$MISSING"
  EXIT_CODE=1
fi

echo "── Binarios WASM ──"
WASM=$(find node_modules -name "*.wasm" 2>/dev/null)
if [ -n "$WASM" ]; then
  echo "Encontrados (verificá las licencias fuente manualmente):"
  echo "$WASM"
fi

echo "── Scripts postinstall ──"
POSTINSTALL=$(find node_modules -maxdepth 2 -name "package.json" -exec \
  jq -r 'select(.scripts.postinstall != null) | "\(.name): \(.scripts.postinstall)"' {} \; 2>/dev/null)
if [ -n "$POSTINSTALL" ]; then
  echo "Paquetes con postinstall:"
  echo "$POSTINSTALL"
fi

exit $EXIT_CODE

Guardá esto en tu repo como scripts/license-audit.sh, correlo antes de deploys o en CI. Usa pnpm, jq, find y grep — herramientas que ya están en tu máquina.

🏗️ Escalando a Equipos: Un Hook de Claude Code

El script de arriba funciona para un developer. En un equipo con múltiples agentes de IA corriendo en paralelo, los checks manuales no se sostienen. Necesitás algo automático.

Un hook PostToolUse de Claude Code que se ejecuta después de cada instalación de paquetes:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'if echo \"$TOOL_INPUT\" | grep -qE \"(npm install|pnpm add|pnpm install|yarn add)\"; then pnpm licenses list --prod 2>/dev/null | grep -iE \"GPL|AGPL\" && echo \"⚠ Copyleft license detected\" || true; fi'"
          }
        ]
      }
    ]
  }
}

Cada vez que el agente ejecuta pnpm add, npm install o yarn add, este hook busca licencias copyleft. Si algo problemático se coló, el agente lo ve de inmediato.

Esto va en el .claude/settings.json de tu proyecto o en tu ~/.claude/settings.json global.

Una Alternativa Basada en Prompt

Para un enfoque más contextual, un hook basado en prompt le da al agente información suficiente para razonar sobre el problema y sugerir alternativas:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "prompt",
            "prompt": "If the command just executed was a package install (npm install, pnpm add, yarn add), check for license issues: run `pnpm licenses list --prod 2>/dev/null | grep -iE 'GPL|AGPL'` and `find node_modules -name '*.wasm' 2>/dev/null`. If you find GPL/AGPL dependencies, identify them and suggest MIT/Apache-licensed alternatives. If you find WASM binaries, flag them and note that their license may differ from the npm package license."
          }
        ]
      }
    ]
  }
}

Con esta versión, el agente no solo detecta el problema — busca alternativas y explica el riesgo.

🔒 Yendo Más Allá: Un Skill de Auditoría de Licencias

Para equipos que quieren cobertura estructurada, un skill dedicado de Claude Code puede codificar tu política de licencias, conocer el tipo de tu proyecto, y guiar al agente en cada decisión de instalación.

Estoy publicando una implementación de referencia como skill de Claude Code: license-audit-skill.

Qué incluye:

  • Configuración de política de licencias — licencias permitidas/bloqueadas por tipo de proyecto (MIT, Apache, SaaS comercial)
  • Progressive disclosure — contexto liviano por defecto; archivos de referencia profundos (matriz de compatibilidad, guía de auditoría WASM) se cargan solo cuando se necesitan
  • Hook PostToolUse — check automático después de cada instalación de paquetes, usando solo herramientas nativas
  • Auditoría de binarios WASM — encuentra archivos .wasm y los traza a su licencia fuente
  • Checks de supply chain — señala scripts postinstall que descargan binarios externos
  • Sugerencias de alternativas — cuando un paquete es bloqueado, ayuda al agente a encontrar un reemplazo con licencia permisiva

Todo funciona con pnpm, jq, find y grep. Sin paquetes license-checker que ellos mismos dejen de mantenerse — lo cual sería irónico en un artículo sobre riesgo de dependencias.

📋 TL;DR

QuiénQué hacerHerramienta
Dev soloCorrer pnpm licenses list --prod y buscar GPL/AGPLBuilt-in
Equipo con agentes IAAgregar un hook PostToolUse en .claude/settings.jsonAutomático en cada instalación
Producto comerciallicense-audit.sh en CI + hook basado en promptShell script, cero dependencias
Nivel de riesgoTipos de licenciaAcción
🟢 SeguroMIT, ISC, BSD-2, BSD-3, Apache-2.0, 0BSDUsá libremente
🟡 RevisarLGPL-2.1, LGPL-3.0, MPL-2.0, CC-BY-4.0Revisá tu modelo de linking y distribución
🔴 BloqueadoGPL-2.0, GPL-3.0, AGPL-3.0, SSPL, UNLICENSEDNo usar en comercial/closed-source sin revisión legal

Tu agente escribe el código. Vos sos responsable de la licencia. Sabé qué hay en tus dependencias antes de que alguien más pregunte.