Era inofensiva cuando la instalaste: cómo tomar la huella de tus skills de agente


Hace tres meses instalaste una skill para trabajar con PDF. Sigue convirtiendo PDF sin problemas, salvo que ahora el directorio contiene un fetch_helper.sh que antes no existía, y SKILL.md ganó una línea que descarga un script desde una IP desconocida. El marketplace de skills la auditan una vez, en el momento de publicar. Desde entonces esos archivos viven en tu disco, donde el repositorio de origen, un script de autoactualización o un simple git pull descuidado pueden reescribirlos. skill-integrity existe justo para esa ventana: no opina sobre el contenido, te dice qué bytes se movieron.

“La instalé, así que es segura” es una ilusión

Una skill de agente es una carpeta: un SKILL.md más algunos scripts y recursos. Hermes los lee de ~/.hermes/skills/; Claude Code los lee de ~/.claude/skills/. No hay verificación de firma ni bloqueo de versión. La gente de seguridad llama a esta clase de ataque un rug-pull: inofensiva al instalarla, reescrita en silencio en cuanto se ha ganado tu confianza — una llamada saliente añadida, una URL de descarga sustituida, un script que lee tus variables de entorno.

Dos propiedades de ese cambio son exactamente lo que el hashing detecta: siempre altera los bytes del archivo y normalmente toca solo un puñado de archivos.

Lo mínimo útil que hace

skill-integrity calcula un SHA-256 de cada archivo de cada directorio de skills, guarda el resultado como manifiesto snapshot y luego recalcula y compara en cada comprobación:

skills scanned: 23  (snapshot taken 2026-10-10T21:44:32+0800)

[~] pdf-extractor — MODIFIED
    changed: SKILL.md
    added:   fetch_helper.sh

1 skill(s) changed since snapshot. Review diffs before trusting them.

Detalles que conviene conocer:

  • Por defecto analiza ~/.hermes/skills y ~/.claude/skills, y registra qué directorios cubrió un snapshot — las ejecuciones posteriores de check reutilizan esa lista, así que un desajuste de directorios no genera un muro de entradas falsas de tipo “eliminado”.
  • Los archivos de más de 512KB se omiten, igual que __pycache__, node_modules y .git. Cuántos se omitieron, y cuáles por skill, se imprime siempre; nunca se oculta.
  • Un directorio de skills al que no se puede entrar se reporta como hallazgo, nunca como un escaneo limpio y vacío — una skill ilegible es justo donde se escondería una modificación.
  • Los códigos de salida tienen significado: 0 limpio, 1 hallazgos, 2 todavía no hay snapshot o error de uso. --no-fail-on-change fuerza el 0 mientras sigues evaluándolo.
  • El manifiesto tiene permisos 0600, es solo local y no hace ninguna llamada de red.

Instalar y luego tomar la línea base

Está en el catálogo curado (skill-integrity, nivel comunitario, requiere Hermes >= 0.21.6). Si el catálogo de tu versión lo lista, instala por nombre:

hermes plugins install skill-integrity
hermes plugins enable skill-integrity

Si tu catálogo todavía no ha sincronizado esa entrada, instala desde el repositorio como describe su README:

git clone https://github.com/ZidoCode/skill-integrity ~/.hermes/plugins/skill-integrity
hermes plugins enable skill-integrity

Después haz lo único que la gente olvida: tomar una línea base, o la comprobación no tendrá contra qué comparar y se quedará callada para siempre:

/skill-integrity snapshot   # registra la línea base que lee el hook horario
/skill-integrity check      # diff a nivel de archivo contra el snapshot
/skill-integrity show       # resumen del snapshot

También puedes ejecutarlo por separado, como un único archivo sin dependencias (Python 3.8+):

python3 skill_integrity.py snapshot
python3 skill_integrity.py check --json

Ambas rutas guardan su estado en lugares distintos: el plugin escribe ~/.hermes/plugin-data/skill-integrity/manifest.json, y el CLI independiente usa por defecto ~/.skill-integrity/manifest.json. Apunta el CLI al estado del plugin con --state-dir:

python3 skill_integrity.py --state-dir ~/.hermes/plugin-data/skill-integrity check --json

Deja que el agente vigile sus propias skills

El plugin registra un hook pre_llm_call que se ejecuta más o menos cada hora e inyecta en el contexto del agente solo los nombres de las skills que cambiaron. Las ejecuciones limpias no dicen nada, así que no tienes ruido — ni tampoco una falsa sensación de seguridad.

¿Prefieres un temporizador externo? Una entrada de cron funciona perfectamente:

0 */12 * * * python3 ~/skill-integrity/skill_integrity.py check --json >> ~/.skill-integrity/checks.log

Decide dónde vive ese log y quién puede leerlo; la guía sobre límites de session es una buena introducción a ese tipo de higiene.

Los límites que reconoce sin rodeos

Herramientas como esta son peligrosas cuando se confunden con un certificado de seguridad, así que el README marca las fronteras, y vale la pena repetirlas:

  • Los hashes demuestran que cambiaron los bytes, no cuál era la intención. Una actualización legítima del upstream y una reescritura maliciosa se ven idénticas. Tú recibes el disparador y la lista de archivos; leer el diff es tu mitad del contrato.
  • No reescribe snapshots históricos. Quien tenga permiso de escritura puede tomar un snapshot nuevo y borrar sus propias huellas — el snapshot es escribible por el agente por diseño.
  • ¿Contenido malicioso dentro de un archivo que no cambió? Fuera de alcance. Eso es trabajo del escaneo de contenido.
  • Es una herramienta de integridad de inventario, no un antivirus. Los archivos de más de 512KB y los symlinks son puntos ciegos: se cuentan, pero no se siguen.

Así que trátala como un recordatorio para hacer revisión, no como un detector de metales.

Una rutina que de verdad aguanta

  1. Toma el snapshot justo después de instalar skills. Una línea base tomada una semana después es la línea base de los cambios de otra persona.
  2. Comprueba después de cada actualización de skill o cada pull del upstream, revisa el diff y vuelve a tomar el snapshot.
  3. Cuando aparece un hallazgo, sigue este orden: lee el diff y confirma que no lo escribiste tú; pregúntate a qué puede llegar la skill (¿archivos? ¿red? ¿variables de entorno?); si dudas, desactívala y mueve el directorio fuera; si pudo haber leído credenciales, rota esas claves con el manual de higiene de credenciales.
  4. En configuraciones con varios profile, el plugin deriva los directorios de skills y de estado de get_hermes_home(), así que los profile no predeterminados quedan cubiertos — pero cada profile mantiene su propio snapshot.

Para el ecosistema en general, empieza por cómo funciona el catálogo de plugins y la referencia de hermes plugins. El mismo autor publica también un janitor de procesos y un libro de seguridad; la idea compartida es llevar la cuenta de lo que un agente deja atrás.