Hay un truco que usan los magos que se llama "misdirection": mientras tu ojo sigue la mano que se mueve, la otra hace algo que no ves. El vibe-coding hace exactamente lo mismo con el code review. El PR llega limpio, con tipos correctos, tests verdes, commits prolijos. Tu ojo sigue la lógica del negocio. La otra mano — la que tiene AWS_SECRET_ACCESS_KEY = "AKIA..." en la línea 47 — pasa invisible.
No me pasó una vez. Me pasó tres veces en el mismo sprint.
Vibe coding security code review: el problema que nadie quiere admitir
Cuando escribí sobre el proceso de vibe-coding vs stress-coding me enfoqué en el flujo, en la velocidad, en cómo cambia la relación con el código cuando un agente escribe el primer borrador. Lo que no dije — porque me daba vergüenza — es que en esa semana aprobé PRs que no debería haber aprobado.
Tres PRs. Misma causa raíz. Distinto contexto cada vez.
PR #1: Integración con Stripe. El modelo generó el webhook handler completo, funcionando, con validación de firma y todo. Hermoso. En el archivo de configuración, al costado del STRIPE_WEBHOOK_SECRET, había una AWS_ACCESS_KEY_ID hardcodeada que nadie pidió. El modelo la puso "por contexto" cuando le di acceso a un archivo de ejemplo.
PR #2: Script de migración de datos. Corrí los tests, pasaron. La key estaba en un comentario. Literal: // aws_secret: AKIA... como si fuera una nota al margen que nadie iba a leer.
PR #3: El más ridículo. Una key en un string de un test. Un test que nadie iba a ejecutar en CI porque era un unit test mockeado. Pero ahí estaba, en el repositorio.
Los tres los aprobé. Los tres los encontró una herramienta automática tres días después.
Por qué tu cerebro falla diferente con código de IA
Acá está el dato empírico que me importa: no es que el código de IA sea peor. En muchos casos es mejor — mejor tipado, más consistente, más prolijo que lo que yo escribiría a las 11pm. El problema es cómo cambia mi proceso de lectura.
Cuando revisás código que escribió un compañero, tu cerebro está en modo detectivesco. ¿Por qué hizo esto así? ¿Qué estaba pensando? Hay una teoría de la mente implícita operando. Buscás intención.
Cuando revisás código de IA, tu cerebro entra en modo validación. ¿Funciona? ¿Los tests pasan? ¿La estructura es correcta? Es sutil, pero es diferente. Estás checkeando output, no entendiendo proceso. Y las keys hardcodeadas no son un error de lógica — no aparecen en los tests, no rompen el build, no generan un type error. Son datos en lugares donde no deberían estar.
Dicho de otra forma: el modelo no sabe que AKIA4EJEMPLO123456789 es un secreto. Para él es un string como cualquier otro. Y vos, en modo validación, lo leés igual.
El experimento que corrí esta semana
Después del tercer PR decidí medir esto de forma más sistemática. Tomé 10 PRs del último mes — 5 escritos por humanos, 5 generados con asistencia de IA (Claude, Cursor, algún Copilot scattered). Los re-revisé con una lista de chequeo explícita de seguridad.
Resultados:
// Resumen del experimento — 10 PRs re-revisados
// PRs humanos (5):
// - Secrets hardcodeados: 0
// - SQL sin parametrizar: 1
// - Validación de input faltante: 2
// - Tiempo promedio de review: 23 minutos
// PRs asistidos por IA (5):
// - Secrets hardcodeados: 3 (!!)
// - SQL sin parametrizar: 0
// - Validación de input faltante: 1
// - Tiempo promedio de review: 14 minutos
// Observación: los PRs de IA los revisé 40% más rápido
// Hipótesis: código más prolijo = menos fricción = menos atención
El número que me golpeó no son los 3 secrets. Es que los revisé 40% más rápido. Eso no es eficiencia. Eso es que le presté menos atención.
Lo que realmente pasa en un code review de código IA
Tengo una teoría. Cuando el código es prolijo, bien estructurado, con nombres descriptivos y comentarios claros, tu cerebro lo procesa como "confiable". Es el mismo sesgo que hace que la gente confíe más en un mensaje de estafa si tiene buena ortografía.
El vibe-coding produce código que parece revisado. Eso es un problema de seguridad en sí mismo.
Lo que debería hacer — lo que voy a hacer de ahora en adelante — es tener un checklist explícito que corre antes de mergear cualquier PR generado con IA:
# checklist-pr-ia.sh
# Corro esto antes de aprobar cualquier PR con asistencia de IA
echo "=== BÚSQUEDA DE SECRETOS ==="
# Buscar patrones de AWS keys
git diff main...HEAD | grep -iE '(AKIA|ASIA|AROA)[A-Z0-9]{16}'
# Buscar patrones genéricos de keys
git diff main...HEAD | grep -iE '(secret|password|token|key)\s*=\s*["\x27][^"\x27]{8,}'
# Buscar IPs hardcodeadas que no sean localhost
git diff main...HEAD | grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' | grep -v '127.0.0.1' | grep -v '0.0.0.0'
# Buscar URLs con credenciales embebidas
git diff main...HEAD | grep -iE 'https?://[^:]+:[^@]+@'
echo "=== ARCHIVOS NUEVOS ==="
# Los archivos nuevos son donde más aparecen secrets
git diff main...HEAD --name-only --diff-filter=A
echo "=== COMENTARIOS SOSPECHOSOS ==="
# El PR #2 tenía la key en un comentario
git diff main...HEAD | grep '^+.*//.*AKIA\|^+.*#.*secret\|^+.*//.*password'
No es magia. Es explicitizar lo que debería ser implícito pero no lo es cuando tu cerebro está en modo validación.
Los gotchas que nadie te cuenta
Gotcha 1: Los tests pueden pasar con keys falsas que después se reemplazan con las reales.
El modelo a veces genera código con EXAMPLE_KEY_REPLACE_ME en los tests y la key real en el archivo de config. Los tests pasan porque mockeás el cliente. La key real queda en el repo.
Gotcha 2: El modelo aprende de tu contexto.
Si le pasás un .env.example para que entienda la estructura, puede reproducir los valores de ejemplo en el código generado. Esos valores de ejemplo son, en muchos proyectos, las keys reales del entorno de desarrollo.
Gotcha 3: Los comentarios son tierra de nadie. Los linters de secrets generalmente no escanean comentarios con la misma agresividad. El modelo usa comentarios para "explicar" configuraciones y a veces mete el valor ahí.
Gotcha 4: Los archivos de test son el punto ciego. La mayoría de las configuraciones de secret scanning excluyen carpetas de test. El modelo lo sabe (o actúa como si lo supiera) y a veces genera fixtures o mocks con datos que parecen reales.
Este último punto conecta con algo que escribí sobre watermarks en código generado por IA — la idea de que el output del modelo tiene características que podemos detectar si sabemos qué buscar. El problema es que estamos muy enfocados en detectar "si lo escribió una IA" y muy poco enfocados en detectar "qué tiene adentro".
El proceso que estoy adoptando
Después de este experimento cambié tres cosas concretas:
1. Pre-commit hooks en todos los repos nuevos
# .husky/pre-commit
# Instalar: npm install --save-dev @secretlint/secretlint
npx secretlint "**/*"
// .secretlintrc.json
{
"rules": [
{
"id": "@secretlint/secretlint-rule-preset-recommend"
},
{
"id": "@secretlint/secretlint-rule-aws"
}
]
}
2. Separé mentalmente "¿funciona?" de "¿es seguro?"
Son dos reviews diferentes. El primero lo puedo hacer rápido. El segundo lo hago lento, con el script de arriba, en un estado de atención diferente. No los mezclo.
3. Agregué una pregunta explícita al PR template
## Checklist de seguridad
- [ ] No hay secrets, tokens ni API keys hardcodeados
- [ ] Variables de entorno están en .env (nunca commiteadas)
- [ ] Si usé asistencia de IA: corrí secretlint antes de abrir el PR
Es burdo. Es obvio. Funciona porque hace explícito algo que el cerebro saltea en modo automático.
Esto también cambia cómo pienso en los agentes que investigan antes de codear — si el agente tiene acceso a tu contexto para investigar mejor, también tiene más superficie para filtrar secretos sin querer.
FAQ: vibe coding security code review
¿El vibe coding es inherentemente inseguro? No inherentemente, pero crea condiciones que aumentan el riesgo. El código generado por IA puede ser técnicamente correcto y tener problemas de seguridad serios al mismo tiempo. El riesgo no está en la calidad del código sino en cómo cambia tu proceso de revisión cuando lo leés.
¿Los modelos de IA deberían detectar y rechazar requests con secrets? Algunos lo hacen parcialmente, pero no es su responsabilidad primaria. Claude, por ejemplo, no va a commitearte una key — pero si le pasás contexto que incluye una key, puede reproducirla en el output sin "saber" que es sensible. La responsabilidad del secret management es tuya.
¿Qué herramientas automáticas recomendás para detectar secrets en PRs? Para repos de GitHub: GitHub Secret Scanning (gratuito para repos públicos, incluido en GitHub Advanced Security para privados). Para CI/CD: truffleHog, gitleaks, o secretlint. Para pre-commit: el combo husky + secretlint que mostré arriba. Lo importante es tener al menos una capa automática que no dependa de tu atención manual.
¿Qué pasa si una key ya fue commiteada y pusheada?
Primero: rotá la key inmediatamente, antes de hacer cualquier otra cosa. Segundo: removela del historial con git filter-branch o BFG Repo Cleaner. Tercero: asumí que estuvo expuesta aunque el repo sea privado — los bots que scrapean GitHub son rápidos. No hay "fue solo un momento". Esto conecta con la criptografía y fecha de vencimiento de los secretos: una key comprometida es una key muerta.
¿Cómo sé si un PR fue generado con IA o no? En muchos casos no vas a saberlo — y eso es exactamente el punto. El proceso de review seguro tiene que ser el mismo independientemente de si lo escribió un humano o un modelo. Asumir que el código es de IA cuando no estás seguro te pone en el modo de atención correcto.
¿El problema mejora con modelos más nuevos? Parcialmente. Los modelos más recientes son mejores en no reproducir secrets obvios y en sugerir usar variables de entorno. Pero si les das contexto que incluye datos sensibles, los van a usar. El problema de fondo no es la capacidad del modelo — es que nosotros bajamos la guardia cuando el output es prolijo y los tests pasan. Eso no lo resuelve un modelo mejor.
Conclusión: el problema soy yo, y eso es bueno
Decir "el problema es la IA" sería cómodo y completamente inútil. Si el problema fuera el modelo, la solución sería cambiar el modelo o dejar de usarlo. Pero el problema es mi proceso de revisión, y eso sí lo puedo cambiar.
Lo que me di cuenta en estos tres PRs es que el vibe-coding no solo cambia cómo se escribe el código — cambia cómo se lee. Y si no actualizás tu proceso de review para compensar ese cambio, estás corriendo con las defensas bajas precisamente cuando el código se genera más rápido.
La buena noticia es que las herramientas existen. secretlint, truffleHog, GitHub Secret Scanning — no son nuevas, no son caras, no son difíciles de configurar. El problema era que yo no las usaba consistentemente porque mi proceso de review "manual" se sentía suficiente. Con código de IA, no lo es.
Si usás Cursor, Claude, Copilot, o cualquier herramienta de asistencia para generar código en un repo que tiene consecuencias reales — configurá secretlint hoy. Antes de cerrar esta pestaña. Son cinco minutos.
Y la próxima vez que veas un PR con tests verdes y código prolijo, acordate: eso es exactamente cuando tenés que mirar más despacio, no más rápido.
¿Te pasó algo parecido? ¿Tenés un proceso diferente para revisar PRs generados con IA? Me interesa saber — especialmente si encontraste algo que yo no estoy haciendo.
Comentarios (0)
Deja un comentario
Artículos Relacionados
Twill.ai y el sueño de 'delegá a un agente, recibí un PR': yo ya lo viví y fue más raro de lo que parece
YC S25, agentes que leen issues y mandan PRs solos. Suena al futuro. Pero llevo meses trabajando con agentes que codean y el problema real no es si el PR compila — es quién entiende ese código cuando hay que tomarlo como propio a las 11 de la noche antes de un deploy.
Francia abandona Windows por Linux: lo que los devs argentinos no estamos viendo
Francia anunció la migración Linux más grande de Europa. Yo trabajé seis meses con una dependencia provincial que intentó lo mismo y terminó peor que antes. No por el OS — por el Frankenstein debajo.
Research-Driven Agents: cuando un agente lee antes de codear
Meses viendo agentes tirar código sin contexto y romper todo. Armé un experimento real: forzar al agente a producir un artefacto de investigación antes de tocar un archivo. Lo que medí cambió cómo trabajo con IA para siempre.