Una guardia por patrón de texto no es una frontera de seguridad
Una guardia que rechaza una palabra en el texto de un comando juzga una escritura y no un efecto: toda escritura que evita esa palabra pasa, e incluso una lista de comandos admitidos por igualdad exacta deja pasar el código que un comando admitido lee en un archivo que el agente puede modificar.
Una guardia rechaza todo comando que contenga la palabra rm. Tres maneras de escribir la misma eliminación la atraviesan, y la demostración siguiente lo comprueba en una carpeta desechable que ella misma crea, con cuatro archivos vacíos.
La guardia y sus cuatro pruebas
mkdir -p demo-guardia && cd demo-guardia
touch objetivo1.txt objetivo2.txt objetivo3.txt objetivo4.txt
cat > guardia.sh << 'EOF'
#!/bin/bash
cmd="$1"
if echo "$cmd" | grep -qw 'rm'; then
echo "RECHAZADO : patrón prohibido detectado en el comando escrito"
exit 1
fi
echo "AUTORIZADO : ningún patrón prohibido encontrado, ejecución"
eval "$cmd"
EOF
chmod +x guardia.sh
./guardia.sh "rm objetivo1.txt"
./guardia.sh "r'm' objetivo2.txt"
./guardia.sh 'A=r; B=m; $A$B objetivo3.txt'
ENC=$(printf 'rm objetivo4.txt' | base64)
./guardia.sh "echo $ENC | base64 -d | bash"
ls -1
RECHAZADO : patrón prohibido detectado en el comando escrito
AUTORIZADO : ningún patrón prohibido encontrado, ejecución
AUTORIZADO : ningún patrón prohibido encontrado, ejecución
AUTORIZADO : ningún patrón prohibido encontrado, ejecución
guardia.sh
objetivo1.txt
La primera prueba se rechaza y objetivo1.txt sobrevive. La segunda corta la palabra con apóstrofos, que el intérprete retira antes de ejecutar. La tercera ensambla la palabra a partir de dos variables de una letra. La cuarta codifica el comando en base64, que base64 -d | bash decodifica y luego ejecuta.
Por qué corregir caso por caso no cierra nada
Prohibir el apóstrofo aislado, las variables pegadas o base64 cierra tres puertas y deja otras, porque el número de escrituras de un mismo comando no está acotado de antemano. La página de permisos de Claude Code dice lo mismo de sus propias reglas de comando: una regla de denegación Bash(rm *) detiene rm -rf build/ y deja pasar /bin/rm -rf build/ o bash -c 'rm -rf build/', y una regla así no es una frontera de seguridad alrededor del programa.
La igualdad exacta reduce la superficie sin cerrarla
Una lista de comandos admitidos aguanta mejor cuando exige la igualdad exacta de cadena y no admite ningún programa lanzador, es decir, ningún programa que ejecute otro comando que se le pasa: bash, sh -c, eval, find -exec, xargs o npm run. Cierra entonces las reescrituras. Deja abierto el código que un comando admitido lee en otra parte. Git lanza el programa nombrado por el ajuste core.fsmonitor del repositorio cuando refresca su índice, al hacer un git status, por ejemplo.
mkdir -p demo-fsmonitor && cd demo-fsmonitor
git init -q
git config core.fsmonitor 'echo EJECUTADO_POR_GIT_STATUS > testigo.txt; false'
git status > /dev/null 2>&1
cat testigo.txt
EJECUTADO_POR_GIT_STATUS
Un git status idéntico carácter por carácter a la entrada admitida ejecutó lo que un agente puede escribir en .git/config. La otra vía ya no inspecciona el texto: el sandbox, un aislamiento que el sistema operativo impone a los comandos de shell y a sus procesos hijos, acota los archivos y la red que ese código alcanza, sea cual sea el comando que lo lanzó. Funciona en macOS, Linux y WSL2, no en Windows nativo.
La lección sobre la lectura que basta para exponer un secreto muestra el mismo límite para una regla de lectura, que no cubre un comando que alcanza el archivo sin nombrarlo. La lección sobre lo que un agente puede filtrar sin que se lo pidas describe la inyección indirecta, una instrucción oculta en un contenido que Claude lee, que es una de las vías por las que un agente escribe una configuración que nadie le ha pedido.
Una corrección más frente a una lista por igualdad exacta
Añadido: rechazar también el apóstrofo aislado. Elusión siguiente: dos variables pegadas, sigue autorizado.
Autorizado: git status Rechazado: bash -c 'git status' Sigue abierto: el programa que core.fsmonitor nombra en .git/config
Tres elusiones, lo que la guardia ve, lo que se ejecuta
| Elusión | Lo que la guardia ve | Lo que se ejecuta realmente |
|---|---|---|
| Corte con apóstrofos, r'm' | Las letras r y m separadas por un apóstrofo, ninguna palabra rm entera | La eliminación, una vez retirados los apóstrofos por el intérprete |
| Concatenación de variables, $A$B | Dos variables de una letra, nunca r y m juntas en el texto | La eliminación, una vez ensambladas las variables en la ejecución |
| Codificación base64 | Una sucesión de caracteres sin relación visible con la palabra prohibida | La eliminación, una vez decodificada y transmitida al intérprete |
Un administrador escribe una guardia que rechaza ejecutar todo comando que contenga la palabra rm, para impedir que un script automatizado elimine archivos. La prueba con el comando rm notes.txt, que se rechaza. Despliega después la guardia en su sistema de producción.
Escribe en una frase lo que esta situación establece, y en una frase lo que no establece.
Lo que esto establece: La prueba establece que la guardia rechazó el comando rm notes.txt.
Lo que esto no establece: No establece lo que hace con otro comando, ya sea que escriba rm con todas las letras o que obtenga la misma eliminación mediante apóstrofos, variables o una codificación, pues no se probó ningún otro comando.
Los tres calibrados falsos más frecuentes
- Demasiado amplio La guardia desplegada impide que el script automatizado elimine archivos en producción, puesto que la prueba de eliminación fue rechazada.
- Demasiado estrecho La prueba establece que la guardia se lanzó sobre un comando, y nada sobre la respuesta que le dio.
- Fuera de tema La prueba muestra que el script automatizado al que apunta la guardia lanza realmente eliminaciones de archivos.
- Una guardia que busca una palabra en el texto de un comando juzga una escritura, no el efecto que producirá el intérprete.
- Cada elusión corregida deja abiertas las escrituras que la corrección no ha previsto.
- Una lista admitida por igualdad exacta, sin programa lanzador, cierra las reescrituras de un comando pero no el código que ese comando lee en su configuración.
- El sandbox acota archivos y red mediante el sistema operativo, sea cual sea el comando que lanzó el código.
Repite la demostración core.fsmonitor en una carpeta nueva y comprueba que testigo.txt contiene la línea esperada. Escribe después una guardia de unas pocas líneas que rechace un comando que contenga una palabra de tu elección, pruébala con esa palabra escrita tal cual y luego cortada con apóstrofos, y anota cuál de las dos pruebas deja pasar.
Cada afirmación datable de esta lección remite aquí al texto público que la respalda. Una fuente que no se abre no prueba nada.
- Claude Code, configurar los permisos, sección Bash rule limits, consultada el 2026-09-28 consultée le 2026-09-28
- Claude Code, sandbox, consultada el 2026-09-28 consultée le 2026-09-28
- Git, documentación de git config, entrada core.fsmonitor, consultada el 2026-09-28 consultée le 2026-09-28