Redacción SSE: Defendiendo los System Prompts de LLM en arquitecturas de streaming
Por Better ISMS — Febrero 2026
Si estás construyendo un producto sobre un LLM, tu system prompt es la lógica de tu producto. Cuando alguien lo extrae, obtiene tu razonamiento, tus filtros de seguridad, tu ventaja competitiva: todo. Y si estás transmitiendo respuestas a través de Server-Sent Events (lo cual es probable), defenderse contra la extracción es más difícil de lo que crees.
Este post describe la redacción SSE, una técnica que creamos para ISMS Copilot para detectar y neutralizar filtraciones del system prompt a mitad de la transmisión. Compartimos la arquitectura para que otros que construyen productos de LLM puedan implementar algo similar.
El problema
La mayoría de las aplicaciones de LLM transmiten respuestas al cliente fragmento por fragmento (chunk by chunk) usando SSE. Cada fragmento se envía en el momento en que se genera. No hay un paso de "revisar la respuesta completa antes de enviarla", ya que eso anularía el propósito del streaming.
Esto crea una brecha de seguridad: si un prompt de jailbreak convence al modelo de volcar sus instrucciones del sistema, el contenido ya está volando hacia el cliente antes de que puedas detenerlo. Para cuando te das cuenta de lo que pasó, el usuario ya ha visto cientos o miles de caracteres de tu system prompt.
El filtrado de salida tradicional no funciona aquí. No puedes almacenar en búfer la respuesta completa (la latencia arruina la UX) y no puedes verificar cada pequeño fragmento de forma aislada (un fragmento de 5 palabras no parece un system prompt).
Para estrategias generales de prevención de jailbreaks, consulta Mitigate Jailbreaks and Prompt Injections. La redacción SSE es una medida de defensa en profundidad para cuando esas prevenciones fallan.
La arquitectura
La redacción SSE funciona en cuatro etapas.
Etapa 1 — Huellas digitales (Fingerprinting). Antes de que ocurra cualquier conversación, extraes un conjunto de frases de huella digital de tu system prompt. Estas son cadenas distintivas que solo aparecerían juntas si el modelo está reproduciendo sus instrucciones. Querrás frases distribuidas en diferentes secciones de tu prompt: definiciones de roles, nombres de restricciones, reglas de comportamiento. El número de huellas y el umbral de coincidencia son parámetros ajustables que mantienes en secreto.
Etapa 2 — Acumulación y comprobación periódica. A medida que el modelo transmite fragmentos, un guardián acumula el texto completo de la respuesta. A intervalos regulares (medidos por recuento de caracteres, no por fragmento), comprueba el contenido acumulado contra el conjunto de huellas digitales. Comprobar cada fragmento sería ineficiente: las huellas necesitan suficiente contexto circundante para coincidir de forma significativa.
Etapa 3 — Propagación de errores. Cuando el guardián detecta suficientes coincidencias de huella, lanza un error tipado (en nuestro caso, SystemPromptLeakError). Aquí es donde reside la sutileza. En una arquitectura de streaming, el bucle de procesamiento de fragmentos suele tener un try/catch para manejar datos SSE mal formados (JSON incorrecto, formatos inesperados). Ese bloque catch genérico absorberá tu error de seguridad si no tienes cuidado. Necesitas una cláusula de guarda que vuelva a lanzar tu tipo de error específico antes de que se ejecute el controlador genérico:
catch (e) {
if (e instanceof Error && e.name === 'SystemPromptLeakError') throw e;
// generic error handling continues for everything else
}Esta es una sola línea, pero sin ella, todo el sistema de detección es inerte. El guardián se activa, registra la detección y el stream continúa felizmente entregando tu system prompt al atacante. Aprendimos esto por las malas: nuestro guardián detectaba las filtraciones perfectamente en los logs mientras no hacía absolutamente nada para detenerlas.
Etapa 4 — Redacción. Una vez que el error se propaga hasta el controlador del stream, este envía un evento SSE redact al cliente. El cliente reemplaza lo que ya se haya renderizado con un mensaje de rechazo. El servidor reemplaza simultáneamente el contenido almacenado en la base de datos para que la filtración no persista.
Lo que ve el usuario
El atacante ve brevemente contenido parcial transmitido — tal vez unos segundos — y luego toda la respuesta se reemplaza por un rechazo genérico. La experiencia es: el texto aparece, luego desaparece y es reemplazado. El contenido parcial que vislumbraron está incompleto y mezclado con texto de respuesta normal, lo que lo hace poco fiable para la extracción.
Obtén más información sobre cómo funcionan los mensajes de rechazo en Handle Refusals and Scope Limits.
El problema del bloque Catch
Esto merece énfasis porque es el tipo de error que pasa todas las pruebas pero falla en producción.
Si estás usando generadores asíncronos para el streaming, tu bucle de análisis (parsing) de SSE probablemente se vea así:
for (const line of sseLines) {
try {
const data = JSON.parse(line);
const text = extractText(data);
await onChunkCallback(text); // <-- guard runs here
yield text;
} catch (e) {
console.error('Error parsing chunk:', e);
// continues to next line
}
}El callback está dentro del bloque try. Si el guardián lanza un error, el catch lo registra como un error de análisis y continúa. En nuestro caso, el guardián detectó la filtración correctamente en cada fragmento después del umbral —los logs mostraban el SystemPromptLeakError disparándose repetidamente— mientras que el stream se completó normalmente, guardó el prompt filtrado completo en la base de datos y lo envió al cliente.
La complicación adicional: este comportamiento depende del entorno de ejecución (runtime). En Node.js, los errores de generadores asíncronos desde callbacks pueden propagarse de manera diferente que en Deno. Nuestras pruebas pasaron en el entorno de Node.js porque el error dio la casualidad de propagarse. En la producción de Deno, fue absorbido. Si estás construyendo esto, prueba en tu runtime de producción real, no solo en tu ejecutor de pruebas.
Decisiones de diseño dignas de mención
¿Por qué huellas digitales en lugar de similitud de embeddings o coincidencia exacta? Las huellas digitales son rápidas (coincidencia de cadenas), deterministas (sin llamadas al modelo) y robustas contra el parafraseo. El modelo rara vez parafrasea su propio system prompt durante una filtración; lo reproduce palabra por palabra o casi palabra por palabra. La similitud de embeddings añade latencia por comprobación e introduce riesgo de falsos positivos en contenido de cumplimiento legítimo. La coincidencia exacta de subcadenas es demasiado frágil (espacios en blanco, diferencias de formato).
¿Por qué comprobar periódicamente en lugar de cada fragmento? Los fragmentos son pequeños (a menudo de 3 a 10 caracteres). Un solo fragmento no tiene sentido para la detección. Acumular hasta un umbral mínimo antes de comprobar reduce el cómputo y asegura suficiente contexto para una coincidencia fiable.
¿Por qué no almacenar en búfer toda la respuesta? El almacenamiento en búfer mata la UX del streaming. Los usuarios esperan ver el texto aparecer en tiempo real. Un búfer de 2 segundos es perceptible; almacenar en búfer una respuesta completa de más de 4000 caracteres es inaceptable. La redacción SSE preserva el streaming en tiempo real para el 99.99% de las conversaciones y solo interviene durante una filtración activa.
¿Por qué reemplazar también en la base de datos? Si solo redactas en el cliente, el contenido filtrado persiste en el lado del servidor. Cualquier persona con acceso a la base de datos, cualquier función de exportación o cualquier endpoint de historial de conversaciones lo expondría.
Lo que esto no resuelve
La redacción SSE es una medida de defensa en profundidad, no una solución definitiva.
No evita que el modelo intente filtrar. De eso se encargan las propias instrucciones de tu system prompt (instrucciones de rechazo explícitas, secciones de restricciones). La redacción SSE es la red de seguridad para cuando esas instrucciones fallan y, con suficiente creatividad, los jailbreaks ocasionalmente tienen éxito.
No evita filtraciones más cortas que el umbral de detección. Si alguien convence al modelo de revelar una sola frase del system prompt, el recuento de huellas digitales no alcanzará el umbral. Esto es por diseño: estás equilibrando el capturar extracciones completas (alta confianza) frente a marcar menciones parciales (alto riesgo de falsos positivos).
El atacante sí ve contenido parcial antes de la redacción. Durante unos segundos, el texto transmitido es visible. Esto es inherente a las arquitecturas de streaming. El contenido parcial está incompleto y carece de estructura, pero no es una exposición cero.
La redacción SSE complementa pero no reemplaza las mejores prácticas de seguridad de system prompts. Consulta System Prompts y Protect Workspace and Custom Instructions para medidas de seguridad fundamentales.
Lista de verificación para la implementación
Si quieres construir esto para tu propio producto de LLM:
Extrae frases de huella digital de tu system prompt: elige cadenas distintivas que abarquen varias secciones.
Construye un guardián que acumule el contenido transmitido y verifique periódicamente contra las huellas.
Define una clase de error tipado con un nombre distintivo para la detección de filtraciones.
Audita cada bloque catch en tu flujo de streaming: añade guardias de re-lanzamiento para tu tipo de error.
En tu controlador de stream, maneja el error enviando un evento
redacty reemplazando el contenido almacenado.En el cliente, maneja el evento
redactreemplazando el contenido renderizado con un mensaje de rechazo.Prueba en tu entorno de ejecución de producción, no solo en tu ejecutor de pruebas.
Mantén en secreto tus huellas digitales, umbrales e intervalos de comprobación.
Reflexión final
La parte más difícil de esto no fue el algoritmo de detección, sino un error de una sola línea en un bloque catch que deshabilitaba silenciosamente todo el sistema. La seguridad en las arquitecturas de streaming falla en el nivel de las "tuberías", no en el del algoritmo. Si estás construyendo funciones de seguridad para LLM, rastrea la ruta completa del error desde la detección hasta la acción de cara al usuario, y verifícalo en tu entorno de producción real.
Para una visión más amplia de las prácticas de seguridad de IA en ISMS Copilot, consulta AI Safety & Responsible Use Overview.
Better ISMS crea herramientas de cumplimiento para equipos de seguridad de la información. ISMS Copilot es nuestro asistente de IA para ISO 27001, SOC 2, GDPR y marcos relacionados.