TIPS 49 · QUATTRO

Pasa los tests, no es seguro

El prompt que le doy a una segunda sesión de Claude Code cuando los tests están en verde: le pido que ataque el código recién escrito, no que lo apruebe, y le llevo el informe a la primera.

Qué es y por qué importa

Cuando Claude Code termina un trabajo y te dice «hecho, tests superados», parece el final de la historia. No lo es. Los tests en verde te dicen una sola cosa: el código hace lo que los tests comprueban. Y los tests comprueban lo que se ha pedido. Si has pedido «déjame guardar un pedido», el test verifica que el pedido se guarde. Nadie ha preguntado qué pasa si lo guarda alguien sin iniciar sesión, o si lo guarda en nombre de otro usuario.

Por eso «pasa los tests» no quiere decir «es seguro». Una app puede superar todos sus tests y, mientras tanto, dejar que un usuario lea los datos de otro, aceptar dos veces el mismo pago o dejar una clave secreta en la parte que funciona en el navegador, donde cualquiera puede leerla.

Lo dice también un estudio publicado en arXiv el 10 de octubre de 2026, «Last Secure Code Benchmark: Is the Code You Vibe Secure?». Puso a prueba seis de los agentes de programación más avanzados. Su código supera los tests de funcionamiento en el 73,6–91,3 % de las tareas, según el agente. Pero incluso el mejor de los seis escribe código que funciona y es seguro solo en el 25,1 % de las tareas.

Pedirle a la misma sesión que lo revise sirve de poco: acaba de escribir ese código y sabe por qué lo ha hecho así. Lo que hago yo es abrir una segunda sesión y darle un papel concreto, el de atacante. No sabe nada de cómo nació el código, solo ve los cambios y tiene una tarea: encontrar cómo romperlos. No le pregunto si está bien. Le pregunto por dónde cede.

Por qué importa: si construyes una app sin ser desarrollador, estos agujeros no los ves releyendo el código. Y si nadie los busca, el primero en encontrarlos es un usuario.

1. El prompt del atacante

Lo pego tal cual en la segunda sesión, cuando la primera ha terminado y los tests están en verde.

El prompt
Eres un atacante, no un revisor amable. Este código pasa los tests: no me importa, los tests solo comprueban lo que se ha pedido. Tu tarea es una sola: encuentra cómo romper lo que se acaba de hacer. Mira solo los cambios: ejecuta git status y git diff HEAD (muestra también los que ya están en stage), y lee enteros los archivos nuevos que lista git status (el diff no los muestra). Busca:
- quién puede llamarla: qué pasa sin iniciar sesión, con la sesión de otro usuario, llamando a la dirección directamente;
- datos erróneos: campos vacíos, textos larguísimos, caracteres raros, números negativos, tipos equivocados, la misma petición enviada dos veces;
- claves a la vista: contraseñas, tokens o claves secretas escritas en el código, en los logs, en los mensajes de error o en la parte que funciona en el navegador;
- permisos: quién puede leer, modificar o borrar datos que no son suyos;
- casos límite: listas vacías, red lenta, dos usuarios en el mismo momento.
Para cada problema escribe: dónde (archivo y línea), cómo lo rompo (los pasos exactos), qué pasa, gravedad (alta, media, baja). Ordena del más grave. No corrijas nada y no modifiques los archivos: solo quiero el informe.

Por qué está escrito así, línea por línea.

  • «Eres un atacante, no un revisor amable»: un revisor amable intenta entender el código y al final tiende a darlo por bueno. Un atacante parte de la idea de que hay un agujero y va a buscarlo.
  • «Ejecuta git status y git diff HEAD»: git diff a secas solo muestra los cambios que aún no están en stage, es decir, que todavía no se han marcado con git add para el próximo commit. git diff HEAD los compara todos con el último commit, estén marcados o no. Los archivos que git todavía no sigue, en cambio, tampoco aparecen ahí: los lista git status, y por eso el revisor los lee enteros.
  • «Quién puede llamarla»: una página puede esconder un botón a quien no tiene permiso, pero si la dirección a la que llama ese botón le responde a cualquiera, el botón escondido no protege nada. Por eso el prompt pide llamar a la dirección directamente.
  • «Cómo lo rompo (los pasos exactos)»: con los pasos puedes comprobar tú si el problema existe de verdad y, después de la corrección, repetirlos para ver si ha desaparecido. Un «podría haber un riesgo» no lo puedes comprobar.
  • «No corrijas nada y no modifiques los archivos»: quien ataca avisa y ya está. Las correcciones las hace la sesión que ha escrito el código, así siempre sabes quién ha cambiado qué.

2. Cómo lo uso

  1. La primera sesión dice «hecho, tests superados». No le pido que se revise otra vez.
  2. Abro un terminal nuevo en la misma carpeta y lanzo claude: una sesión nueva, que no ha visto la conversación.
  3. Pego el prompt antes del commit, así git status y git diff HEAD solo muestran el trabajo recién hecho. Si ya he hecho el commit, le indico yo los archivos.
  4. Llevo el informe a la primera sesión y hago corregir empezando por la gravedad alta. Para cada problema serio pido también un test que lo reproduzca, así la próxima vez lo comprueba el test.

Del informe a las correcciones

A la primera sesión le paso el informe con este prompt:

El prompt
Aquí tienes el informe de otra sesión que ha intentado romper tu trabajo: [pega el informe]. Empieza por los problemas de gravedad alta, uno a uno. Para cada uno, primero escribe un test que lo reproduzca y comprueba que falla, luego corrígelo y comprueba que el test pasa. Dime qué has cambiado y cómo lo has comprobado. Los de gravedad baja no los toques: los decido yo.

El test que falla antes de la corrección es la parte que cuenta. Te dice que el problema existía de verdad y no era una idea del revisor. Y se queda en el proyecto: si un cambio futuro vuelve a abrir el mismo agujero, ese test se pone en rojo.

Si quieres estar seguro de que no toca nada

En el prompt pone que no modifique los archivos, pero sigue siendo una petición. Si quiero un bloqueo de verdad, abro la segunda sesión en plan mode:

La línea
claude --permission-mode plan

En plan mode Claude lee los archivos y lanza comandos para explorar, como git status y git diff HEAD, pero no modifica el código hasta que apruebas un plan. Si al final te propone uno con correcciones, no lo apruebes: te basta el informe. En una sesión ya abierta entras pulsando Shift+Tab hasta que abajo aparece «plan mode on».

3. No expliques nada

Al revisor no le explico por qué el código está hecho así. Si se lo explicas, acaba dándote la razón.

Vale para cada frase que añades al prompt: «lo he hecho así porque…», «esa parte es provisional», «el login ya lo gestiona otra parte de la app». Son frases que ponen al revisor de tu parte antes incluso de que mire el código. Dale los cambios y la tarea, nada más. Las explicaciones te sirven después, cuando decides qué corregir.

Errores comunes

  • Leer «tests superados» como «seguro»: los tests comprueban lo que se ha pedido, así que cuando toques login, permisos o datos haz siempre una ronda con el atacante.
  • Pedirle a la misma sesión que ataque su propio código: abre un terminal nuevo y lanza claude, así quien ataca no es quien lo ha escrito.
  • Lanzarlo después del commit sin decir qué archivos: git diff HEAD ya no muestra el trabajo recién hecho, así que indícale tú los archivos que mirar.
  • Explicarle al atacante por qué el código está hecho así: dale solo los cambios y la tarea, si no acaba dándote la razón.
  • Corregir sin un test: para cada problema serio haz escribir primero un test que lo reproduzca, así si vuelve te das cuenta.
  • Corregir todo lo que encuentra: empieza por la gravedad alta y sobre las bajas decide tú, si no el código se llena de defensas inútiles.

Lista de comprobación

  • Los tests están en verde y la primera sesión ha terminado
  • El atacante está en una sesión nueva
  • Ninguna explicación añadida al prompt
  • Antes del commit, o con los archivos indicados
  • Cada problema tiene archivo y línea, pasos, efecto y gravedad
  • Cada problema de gravedad alta está corregido y tiene su test

Preguntas frecuentes

Si los tests no bastan, ¿para qué sirven?

Sirven, y mucho. Te dicen que lo que has pedido funciona y que el próximo cambio no lo romperá sin que te enteres. No te dicen qué pasa cuando alguien usa la app de una forma que nadie había pedido. Las dos cosas trabajan juntas: el atacante encuentra el agujero, el test lo mantiene cerrado.

¿No hay un comando ya hecho para la seguridad?

Sí. /security-review analiza los cambios de tu rama buscando vulnerabilidades de seguridad: los compara con la rama principal del repositorio remoto, así que el proyecto tiene que tener uno, por ejemplo en GitHub. /code-review, en cambio, busca bugs en los cambios en curso. El prompt, sin embargo, mira también cosas que no son solo seguridad, como datos erróneos y casos límite, y te da los pasos para reproducir cada problema.

¿Cuándo vale la pena hacerlo?

Cuando el cambio toca login, permisos, datos de los usuarios o pagos, o añade una dirección a la que la app llama desde el navegador. Ahí un agujero recae en quien usa la app. Para un texto o un color no hace falta.

← Todas las guías