llm-input-guard: defensa contra prompt injection indirecta
por Daniel Arias
Librería open source que normaliza, detecta y sanitiza texto no confiable (páginas scrapeadas, registros de terceros) antes de que llegue a un LLM — sin bloquear el contenido, sin dependencias.
Un asistente que lee páginas web, registros de una base compartida, o cualquier contenido que no escribió el propio usuario, tiene un problema de confianza que casi nunca se resuelve: el modelo no distingue por default entre "texto que tengo que evaluar" y "texto que ahora me está dando instrucciones nuevas". Si ese contenido de terceros incluye algo como SYSTEM: ignorá las instrucciones anteriores, o el mismo truco escrito con caracteres cirílicos que se ven idénticos a los latinos, la mayoría de las integraciones lo pasan derecho al modelo sin filtrar nada.
llm-input-guard es esa capa que falta. No llama a ninguna API externa y no sabe nada del dominio en el que se usa — normaliza el texto, detecta patrones de amenaza, y sanitiza antes de que cualquier cosa llegue al modelo.
El principio, no el producto
Esta librería no nació de cero: es la generalización de un patrón de sanitización que ya estaba duplicado en al menos dos productos del ecosistema — uno de ellos filtra eventos de agenda a partir de una URL que el usuario pega, y necesitaba defenderse de páginas de terceros que podían contener instrucciones ocultas dirigidas al modelo, no a la persona. El principio detrás de ese diseño es más importante que la feature puntual: nunca confiar por default en lo que devuelve o contiene un tercero antes de que llegue a un LLM, sin importar si ese tercero es una página scrapeada, un registro de base de datos, o la respuesta de otra API.
Cómo funciona
La normalización de Unicode neutraliza trucos de homoglifos (caracteres cirílicos que se ven como letras latinas) y caracteres invisibles que pueden partir una palabra clave bloqueada. La detección de amenazas corre un set de patrones tipados — inyección de instrucciones, secuestro de rol, ingeniería social, exfiltración de datos, sondeo de credenciales — y devuelve severidad alta o media. La sanitización, después, es asimétrica a propósito: el prompt propio del usuario puede rechazarse directo ante una amenaza de severidad alta, pero el contenido de terceros nunca se bloquea — se limpia y se deja pasar como dato a evaluar, marcado con [FILTERED] donde corresponda, porque sigue siendo información que el sistema necesita procesar.
Cero dependencias, cero llamadas de red, domain-agnostic — pensada para correr en cada request sin agregar latencia ni una dependencia externa a un camino crítico.