Hook de seguridad para bloquear comandos peligrosos en Claude Code
Hola, bienvenido. En la lección anterior vimos cómo se escribe un hook en settings.json, qué recibe, qué devuelve y cómo se comprueba con /hooks, y en esta lección vamos a crear el primer hook de claude-tasks: guard.sh, un script que se ejecuta en PreToolUse, antes de cada lectura, edición o comando de Bash, y bloquea lo que no debe pasar nunca en el proyecto. Vamos a escribirlo, a probarlo a mano, a registrarlo y a probarlo dentro de Claude Code, y después veremos 2 cosas que tienes que tener claras antes de fiarte de él: qué pasa si el propio hook falla y cómo convive con auto mode.
¿Por qué un hook, si ya tenemos reglas deny y el sandbox? Porque cada una de esas capas tiene un hueco que ya conoces. En la lección Permisos en Claude Code: reglas allow, ask y deny vimos que una regla de Bash se compara con el texto del comando, y que Bash(./vendor/bin/sail artisan migrate:fresh *) para ese comando, pero no ./vendor/bin/sail php artisan migrate:fresh, que hace exactamente lo mismo. Y en la lección Sandbox de Claude Code en WSL2 y Linux sacamos Sail del sandbox, así que un comando que se ejecuta dentro del contenedor, donde está montado el proyecto entero con su .env, solo lo frenan los permisos. Un hook PreToolUse cubre justo eso: ve el comando completo antes de que se ejecute y le aplica tu propia lógica, escribas el comando como lo escribas.
Es el tercero de los límites que te propuse en la lección de modos de permiso para trabajar con auto mode en el día a día, junto a las reglas deny y el sandbox. Y conviene decir desde ya lo que no hace: guard.sh impide acciones antes de que ocurran, pero no revisa el código que escribe Claude. Una inyección SQL o una ruta sin autorización viven en ese código, y revisarlo es otra capa que veremos en la lección Revisar la seguridad del código con Claude Code: qué usar y cuándo.
Para seguir esta lección necesitas claude-tasks con el .claude/settings.json de la lección del sandbox, jq instalado como vimos en la lección anterior y Claude Code con la versión 2.1.139 o posterior, por la forma exec.
Qué va a bloquear guard.sh
Un hook de seguridad tiene que bloquear poco y claro. Si bloquea demasiado, acabas quitándolo el día que te estorba, y si su lista crece sin criterio, nadie sabe ya qué protege. guard.sh va a cubrir 4 cosas, y cada una tiene su motivo:
- Los archivos
.env, que tienen las credenciales de la base de datos, del correo y de cualquier API. Para las herramientas de archivos ya tenemos las reglasRead(./.env)yRead(./.env.*), y el hook las repite como segunda capa. Lo que aporta de verdad es Bash: va a bloquear cualquier comando que nombre un archivo.env, también los que se ejecutan dentro del contenedor de Sail, donde el sandbox no llega. - Los archivos de lock,
composer.lockypackage-lock.json. Solo los deben tocar Composer y npm, y una edición a mano deja el lock desincronizado de lo que hay instalado. Leerlos sí está permitido, porque Claude los consulta para saber qué versiones tienes. - Los comandos de Git que descartan trabajo:
git reset --hard,git push --forceygit clean -f.reset --hardyclean -fpierden cambios locales sin vuelta atrás, y el force push reescribe el historial del remoto. - Los comandos de Artisan que vacían la base de datos:
migrate:fresh,migrate:refresh,migrate:resetydb:wipe. Son los 3 que ya bloquean las reglasdeny, másmigrate:refresh, que revierte todas las migraciones y las vuelve a lanzar, y el hook los para aunque vayan conphpdelante o dentro de un comando compuesto.
Fíjate en que ninguna de estas cosas es algo que Claude necesite hacer para trabajar en el proyecto. Si alguna vez te hace falta vaciar la base de datos o descartar cambios, lo haces tú desde tu terminal, que es el mismo criterio que usamos con las reglas deny.
- 02El script guard.sh
- 03Probarlo a mano
- 04Registrarlo en settings.json
- 05Probarlo dentro de Claude Code
- 06Qué pasa si el hook falla
- 07Cómo convive con auto mode