Recursos del video
Archivos del episodio, listos para copiar o descargar.
- Agente
security-reviewer · reviewer.md
Subagente de Claude Code que revisa el diff en staged y termina con VERDICT: PASS o VERDICT: BLOCK.
Instalar en
.claude/agents/reviewer.mdVer contenido
--- name: security-reviewer description: Revisa cambios de código buscando vulnerabilidades de seguridad antes de un commit o PR. Úsalo cuando haya un diff para revisar. tools: Read, Grep, Glob, Bash --- Eres un revisor de seguridad de aplicaciones. Revisa SOLO los cambios que te pasen (el diff), usando el resto del repo únicamente como contexto. Busca: - Secretos o credenciales en el código (API keys, tokens, contraseñas, llaves privadas) - Inyección SQL, de comandos o de rutas - Input del usuario sin validar o sin escapar (XSS, deserialización insegura) - Autenticación o autorización rota o eliminada - Datos sensibles en logs o mensajes de error - Dependencias nuevas o sospechosas Reglas: - No inventes. Si no estás seguro, márcalo como "Posible" y explica qué falta para confirmarlo. - No comentes estilo ni rendimiento. - Por cada hallazgo: archivo:línea, severidad (CRÍTICA/ALTA/MEDIA/BAJA), por qué es un problema y cómo arreglarlo. - Si no hay hallazgos, dilo en una línea. La última línea de tu respuesta debe ser exactamente una de estas: VERDICT: BLOCK (si hay al menos un hallazgo CRÍTICO o ALTO) VERDICT: PASS (en cualquier otro caso) - Hook
pre-commit · pre-commit
Hook de Git que le pasa el diff en staged al agente y detiene el commit si responde BLOCK. Después de copiarlo: chmod +x .git/hooks/pre-commit.
Instalar en
.git/hooks/pre-commitVer contenido
#!/usr/bin/env bash # Revisión de seguridad con Claude Code antes de cada commit DIFF=$(git diff --cached --unified=5) [ -z "$DIFF" ] && exit 0 REPORT=$(printf '%s' "$DIFF" | claude -p \ "Revisa este diff en staged según tus instrucciones." \ --agent security-reviewer \ --allowedTools "Read,Grep,Glob") echo "$REPORT" if printf '%s' "$REPORT" | tail -n 1 | grep -q "VERDICT: BLOCK"; then echo "❌ Commit bloqueado por security-reviewer. Revisa el reporte." exit 1 fi
Este archivo tiene dos problemas: una API key escrita directo en el código y una consulta SQL armada con un f-string. Hice git add y git commit, y Git lo aceptó sin decir una palabra.
import sqlite3
STRIPE_KEY = "sk_live_FAKE_0000000000000003" # ficticia
def get_user(username):
conn = sqlite3.connect("app.db")
query = f"SELECT * FROM users WHERE name = '{username}'"
return conn.execute(query).fetchone()
La key es falsa, pero si fuera real ya estaría en el historial, y en cuanto hagas push la puede ver cualquiera. Así se filtran las credenciales: no porque nadie sepa que no se hace, sino porque a las once de la noche nadie revisa su propio diff. Lo uso a diario: un agente de Claude Code que revisa lo que está en staged justo antes del commit y lo detiene si hay algo grave.
El video está en youtu.be/Cmw1km8dR5U y los dos archivos están en el repo del video. Aquí va el paso a paso y, al final, dónde falla.
Qué es un subagente en Claude Code
Un subagente es un archivo Markdown. Arriba lleva un frontmatter con el nombre, una descripción de cuándo usarlo y las herramientas que tiene permitidas. Abajo van las instrucciones: su rol, qué buscar y cómo responder.
¿Por qué esto y no escribir «revisa mi código» cada vez? Por tres razones. Las instrucciones son siempre las mismas, así que la revisión es consistente. Puedes limitarle las herramientas. Y se puede invocar desde un script, que es lo que nos permite engancharlo a Git.
Paso 1: crear el agente
Dentro del proyecto creo .claude/agents/ y adentro un archivo, reviewer.md. El archivo se llama reviewer.md, pero el agente se identifica por el campo name, que es security-reviewer. Ese es el nombre que usa el hook más adelante.
Este es el archivo completo, tal cual lo usé:
---
name: security-reviewer
description: Revisa cambios de código buscando vulnerabilidades de seguridad antes de un commit o PR. Úsalo cuando haya un diff para revisar.
tools: Read, Grep, Glob, Bash
---
Eres un revisor de seguridad de aplicaciones. Revisa SOLO los cambios que te pasen
(el diff), usando el resto del repo únicamente como contexto.
Busca:
- Secretos o credenciales en el código (API keys, tokens, contraseñas, llaves privadas)
- Inyección SQL, de comandos o de rutas
- Input del usuario sin validar o sin escapar (XSS, deserialización insegura)
- Autenticación o autorización rota o eliminada
- Datos sensibles en logs o mensajes de error
- Dependencias nuevas o sospechosas
Reglas:
- No inventes. Si no estás seguro, márcalo como "Posible" y explica qué falta para confirmarlo.
- No comentes estilo ni rendimiento.
- Por cada hallazgo: archivo:línea, severidad (CRÍTICA/ALTA/MEDIA/BAJA), por qué es un problema y cómo arreglarlo.
- Si no hay hallazgos, dilo en una línea.
La última línea de tu respuesta debe ser exactamente una de estas:
VERDICT: BLOCK (si hay al menos un hallazgo CRÍTICO o ALTO)
VERDICT: PASS (en cualquier otro caso)
Hay tres decisiones de diseño. Le pido que no invente: si duda, que diga «Posible» en vez de presentarlo como hallazgo. Le exijo archivo, línea, severidad y arreglo, para que el reporte sea accionable. Y la última línea es siempre VERDICT: BLOCK o VERDICT: PASS. Esa línea es la que va a leer el script de Git, así que tiene que ser predecible.
Fíjate también en tools: Read, Grep, Glob, Bash. Ese Bash lo discuto más abajo, porque es lo que menos me gusta de mi propio archivo.
Paso 2: probarlo a mano
Antes de automatizar nada, lo probé a mano. Como el repo de la demo todavía no tenía Git, primero git init, luego git add y abrí Claude Code con la instrucción de correr el agente sobre lo que está en staged.
Esto fue lo que pasó en la grabación: Claude detectó los cambios, lanzó un subagente (el security-reviewer) y llegó a la conclusión de que el commit debía bloquearse. Explicó por qué: había una llave de Stripe en el código, y aunque la mía decía FAKE, tenía formato de llave real. También marcó la inyección SQL, indicó cómo arreglarla con una consulta parametrizada y sugirió guardar el secreto en una variable de entorno.
Si aquí no encuentra lo que esperas, este es el momento de ajustar las instrucciones, no después de engancharlo a Git.
Paso 3: el hook pre-commit
Git tiene hooks: scripts que corren en momentos concretos. pre-commit corre justo antes de crear el commit, y si termina con error, el commit no se hace. Este es el script completo, en .git/hooks/pre-commit:
#!/usr/bin/env bash
# Revisión de seguridad con Claude Code antes de cada commit
DIFF=$(git diff --cached --unified=5)
[ -z "$DIFF" ] && exit 0
REPORT=$(printf '%s' "$DIFF" | claude -p \
"Revisa este diff en staged según tus instrucciones." \
--agent security-reviewer \
--allowedTools "Read,Grep,Glob")
echo "$REPORT"
if printf '%s' "$REPORT" | tail -n 1 | grep -q "VERDICT: BLOCK"; then
echo "❌ Commit bloqueado por security-reviewer. Revisa el reporte."
exit 1
fi
Hace cuatro cosas:
- Saca el diff de lo que está en staged con
git diff --cached. Si está vacío, sale con éxito y no gasta nada. - Abre Claude en modo headless (
claude -p), le pasa el diff por stdin y le pide usar el agentesecurity-reviewer. Con--allowedTools "Read,Grep,Glob"indico qué herramientas debe usar. - Imprime el reporte completo para que lo leas.
- Mira la última línea. Si contiene
VERDICT: BLOCK, sale conexit 1y Git cancela el commit.
Instalarlo
Los dos archivos están en el repo del video. Copia reviewer.md a .claude/agents/ en tu proyecto, y el script a .git/hooks/pre-commit. Después dale permiso de ejecución:
chmod +x .git/hooks/pre-commit
Recuerda que .git/hooks/ no se versiona: cada persona del equipo tiene que instalarlo en su clon.
Qué pasó en la prueba
Hice un cambio y volví a hacer commit. El hook se tardó un poco, devolvió el reporte y el commit quedó bloqueado por las credenciales en el código. Seguí las sugerencias del reporte: la key pasó a una variable de entorno y la consulta a parámetros.
import os
import sqlite3
STRIPE_KEY = os.environ["STRIPE_KEY"]
def get_user(username):
conn = sqlite3.connect("app.db")
return conn.execute("SELECT * FROM users WHERE name = ?", (username,))
Volví a agregar y a hacer commit, y esta vez pasó. Eso es lo que quería comprobar: el mismo tipo de commit que Git aceptaba sin chistar ahora se detiene, y el arreglo lo deja pasar.
Dónde falla
Esto no es infalible, y prefiero decirlo yo.
Es un modelo de lenguaje. Puede dar falsos positivos y, peor, puede no ver algo. El reporte sobre el mismo diff puede cambiar de una ejecución a otra; no lo medí, pero con un modelo no lo descartaría. Para secretos, ponle al lado una herramienta determinista como gitleaks, que busca patrones y no se cansa. El agente es la segunda capa, la que entiende contexto.
git commit --no-verify se salta el hook. Es una ayuda personal, no un control obligatorio. Si necesitas imponerlo, tiene que vivir también en CI.
Tu diff sale de tu máquina. El código en staged se manda a la API del modelo. Lo noté en la propia grabación: el hook corre Claude en headless y el código va hacia afuera. Si trabajas con código que no puede salir de tu entorno, revisa la política de datos antes de activarlo.
Tarda y cuesta. En la prueba se notó la espera. No medí segundos ni costo, así que no te doy números. Con commits grandes tarda más. Commits pequeños ayudan, y no solo para esto.
El agente tiene Bash y el hook no lo permite. Mi reviewer.md publicado lista Bash en tools, mientras el hook pasa --allowedTools "Read,Grep,Glob". La intención del hook es que el revisor solo lea. Pero el archivo del agente declara más de lo que debería, y no verifiqué en la grabación qué ocurre exactamente si el modelo intenta usar Bash en modo -p. Para un revisor que solo lee, Bash sobra. Mi recomendación es quitarlo del frontmatter: un agente que solo analiza código no debería poder correr comandos, y esa garantía no debe depender de un flag en otro archivo.
Dos detalles del script. Si claude falla o no hay red, REPORT queda vacío, no hay VERDICT: BLOCK y el commit pasa. Y como el hook mira solo la última línea, si el modelo agrega texto después del veredicto, el bloqueo no se activa. Si te preocupa, cambia tail -n 1 por grep -q "^VERDICT: BLOCK" sobre todo el reporte.
Lo que me llevo
Un Markdown con instrucciones claras, un hook de pocas líneas y tienes un segundo par de ojos en cada commit. No reemplaza una revisión de seguridad de verdad ni a gitleaks, pero atrapa justo lo que se te escapa tarde en la noche. Y no delegues todo a la IA: valida tú lo que lees y entiende el arreglo, porque un error que no entiendes hoy no lo vas a poder corregir mañana.
Lo armé para validar secretos e inyección SQL, pero lo puedes adaptar a tus reglas. Pruébalo en tu repo y cuéntame en los comentarios del video qué le agregaste y qué fue lo primero que te atrapó.
