11 de octubre de 2026 · 5 min de lectura

Fail-closed en hooks y reglas deny: por qué un control que falla deja pasar

seguridad claude-code harness agentes
Nicolás Neira
Nicolás Neira
Arquitectura de agentes e IA aplicada

Escribes una regla deny para rm -rf. La pruebas y bloquea. Semanas después, alguien antepone una variable de entorno al comando y la regla ya no lo ve. Nadie recibe un error. El agente simplemente ejecuta lo que debías haber bloqueado.

Esa es la forma más común de fallo en los controles de un agente: no se rompen con ruido, fallan en silencio hacia el lado permisivo. Las notas de Claude Code de esta semana tienen varios ejemplos, y casi todos caen en dos familias.

Familia 1: la regla compara la escritura, no el efecto

Una regla deny suele comparar cómo está escrita la acción. Lo que importa es qué hace. Cada vez que esas dos cosas se separan, hay un bypass. Las notas de la v2.1.289 listan varios casos:

La v2.1.290 añade otro: un CLAUDE.md, una regla o un AGENTS.md que era un symlink fuera de los directorios de trabajo se cargaba aunque estuviera activo permissions.blockReadsOutsideWorkingDirectories o una regla deny de Read. También corrige patrones de URL con comodín dentro de una etiqueta de host xn-- que coincidían distinto de un proceso a otro.

La v2.1.292 sigue con lo mismo. Corrige que rm -rf sobre el nombre corto 8.3 de la carpeta home, u otra grafía alternativa en Windows, no se tratara como borrado del home o de una unidad. Y corrige que los hooks PreToolUse y el auto mode se saltaran el prompt de permisos al leer archivos desde rutas de red UNC.

El SDK de TypeScript 0.3.290 tiene el mismo patrón en versión de API. Las reglas deny y ask no alcanzaban herramientas definidas en toolAliases cuando se escribían con comodín (Bash*), con un patrón que coincide con todo (Bash(**)) o con un campo de entrada que también estaba en disallowedTools.

Hay un caso en otro proyecto. Codex 0.162.0 corrige que la configuración de ripgrep pudiera debilitar las máscaras deny-glob.

El patrón es siempre el mismo. Existe una segunda forma de nombrar lo mismo: un alias, una ruta alterna, un prefijo, un enlace. La regla cubría la primera forma y no la segunda.

Familia 2: el control falla y la acción pasa

La segunda familia no es de coincidencia, sino de error. Un hook que no arranca, que expira o que sale con un código inesperado no está diciendo “sí”, pero el sistema puede tratarlo como un sí.

La v2.1.295 de Claude Code añade onFailure: "block" para hooks de comando y HTTP. Con esa opción, un hook que no puede arrancar, expira o sale con un código inesperado bloquea la acción “en lugar de dejarla pasar”. La propia redacción de la nota dice cuál era el comportamiento sin ella.

Otros dos arreglos apuntan en la misma dirección:

Un control cuyo veredicto no se interpreta bien es equivalente a un control ausente.

Qué tienen en común

Ninguno de estos casos es un exploit sofisticado. Son huecos entre lo que el control entiende y lo que el sistema ejecuta, y huecos entre “el control no pudo decidir” y “el sistema decidió permitir”. En ambos, el valor por defecto de la ruta desconocida es permitir.

Un guardrail sólido invierte ese valor. Lo que no reconoce, lo que no puede evaluar y lo que falla se bloquea.

Reglas accionables

  1. Declara qué hace cada hook de seguridad al fallar. Si usas hooks de comando o HTTP como control, configura onFailure: "block". Un hook que se cae no debe equivaler a aprobación.
  2. Prueba cada regla deny con variantes del mismo comando. Prefijo de variable, asignación previa, comando anidado dentro de uno compuesto, ruta a través de un symlink, grafía alterna en Windows. Si una variante pasa, la regla cubre texto y no efecto.
  3. No escribas hooks de bloqueo como instrucciones sueltas. Los hooks prompt y agent redactados como “Bloquea comandos que…” fallaron en la práctica. Verifica con casos que deban bloquearse, no solo con casos que deban pasar.
  4. Al definir reglas por herramienta, prueba también los alias y los comodines. Comprueba que toolAliases queda cubierto por la regla deny que escribiste.
  5. Después de cada actualización, vuelve a correr tu suite de casos prohibidos. Una regla que bloqueaba antes puede dejar de hacerlo, y una corrección puede cambiar lo que tu equipo daba por cierto. Esa suite es el único registro de que el control sigue funcionando.
  6. En máquinas administradas, revisa las rutas de lectura y las fuentes de configuración. Las correcciones de CLAUDE.md y AGENTS.md con symlinks muestran que lo que carga el agente también es superficie de control.

Fuentes:

Seguir leyendo

Nicolás Neira

Esto se demuestra en video, y se sigue a diario en la comunidad

Las demos completas van al canal. El seguimiento release por release, adentro.