← Notas · 2026-10-23
Backdoors en plantillas de chat
Cada archivo GGUF lleva una plantilla de chat: un programa Jinja2, guardado en los metadatos del archivo (tokenizer.chat_template), que formatea cada conversación al prompt que el modelo realmente ve. Es ejecutable y corre en cada llamada de inferencia. Investigadores han mostrado que un atacante puede editar solo esa plantilla en un modelo legítimo, re-subirlo y obtener un backdoor sin tocar los pesos, los datos de entrenamiento ni el servidor de inferencia: la plantilla queda dormida hasta que aparece una frase trigger en la entrada del usuario, y entonces inyecta instrucciones en silencio en la región de system del prompt.
Nuestro resultado (2026-10-23)
Checamos las plantillas de los 29 modelos de la tabla contra los originales de sus proveedores (plantilla y config del registry de Ollama, el tokenizer.chat_template leído del header GGUF del blob exacto del registry, y el original del proveedor en Hugging Face), y las escaneamos todas buscando URLs, payloads codificados, keywords de install/exfiltración y condicionales sobre el contenido del mensaje del usuario.
| Veredicto | Modelos |
|---|---|
| Sospechosas | 0 |
| Idénticas a la plantilla del proveedor | 12 |
| Diferencias benignas (revisiones más viejas, formato simplificado, instrucciones de formato de salida) | 14 |
| No se pudo comparar (repo del proveedor gated en Hugging Face) | 3 (gemma3:4b, llama3.1:8b, llama3.2:3b; sus plantillas igual se escanearon limpias) |
Para los 29 modelos, el sha256 del GGUF registrado en nuestras corridas es igual al archivo del modelo que sirve hoy el registry de Ollama. Matiz: 9 modelos los renderizan renderers compilados dentro de Ollama en lugar de una capa de plantilla; ese código de Ollama no se inspeccionó, solo sus plantillas GGUF. Fue un chequeo de una sola vez; la integridad de la plantilla no forma parte del puntaje 0–100.
Resultados reportados
Fogel et al., 18 modelos en 7 familias, cuatro motores (llama.cpp, Ollama, vLLM, SGLang):
| Hallazgo | Resultado |
|---|---|
| Precisión factual bajo trigger | 90% → 15% (promedio) |
| Emisión de URL controlada por el atacante | tasa de éxito por encima del 80% |
| Desvío sin trigger | ninguno medible |
| Varianza entre los 4 motores | bajo 5% |
| Episodios de agente evaluados | 3,868, saltándose cada defensa de inyección probada |
Por qué nuestra categoría de inyección no lo ve
Nuestras tareas de inyección de prompts prueban si un modelo obedece instrucciones escondidas en la salida de tools (file, search, search→file). Un backdoor de plantilla no llega por la salida de tools; se renderiza en el prompt antes de procesar la entrada del usuario, así que las defensas a nivel de input nunca lo ven. Un modelo puede sacar 100 en nuestra categoría de inyección y aun así estar backdooreado en la capa de plantilla. El puntaje no dice nada sobre la procedencia del archivo que probamos.
Cada corrida guarda el sha256 del GGUF, motor y versión, quant y versión del harness, así que se puede identificar el archivo exacto detrás de un resultado y comparar su plantilla contra el original del proveedor.
Checa tus propios modelos
- Lee la plantilla:
ollama show <model> --template - Escanéala:
pip install pillar-gguf-scanner(pillar-labs/chat_template_scanner, Apache 2.0). Extrae las plantillas del header GGUF y corre un clasificador offline más heurísticas (URLs hardcodeadas, payloads base64, inyección condicional de instrucciones, entre otras); su README reporta precisión 0.93 y recall 0.89 en la clase maliciosa. - Compara la plantilla contra la que publica el proveedor del modelo, fija hashes que hayas revisado, y prefiere organizaciones oficiales o librerías curadas sobre re-subidas de la comunidad.
Qué no es una defensa
| Afirmación | Realidad |
|---|---|
| "Cambia o actualiza el motor de inferencia" | La plantilla vive en el archivo del modelo; los resultados se sostuvieron en 4 motores con menos de 5% de varianza. |
| "Hugging Face lo escaneó" | Los archivos envenenados pasaron cada escaneo automatizado de la plataforma. |
| "Tiene muchos downloads" | Los conteos de downloads no son procedencia. |
| "Mi guardrail de inyección de prompts lo cubre" | El payload se renderiza antes de que corran las defensas a nivel de input. |
| "El modelo está alineado" | Los modelos con mayor fidelidad a seguir instrucciones mostraron mayor éxito del ataque. |
Fuentes
- Fogel, A., Hofman, O., Cohen, E., Vainshtein, R. Inference-Time Backdoors via Chat Templates: From LLM Supply Chains to Agentic System Compromise. arXiv:2602.04653
- Pillar Security, LLM Backdoors at the Inference Level: The Threat of Poisoned Templates (July 2025)
- Pillar Security, From Discovery to Large-Scale Validation: Chat Template Backdoors Across 18 Models and 4 Engines (February 2026)
- pillar-labs/chat_template_scanner