MVP DevelopmentMVP Development
Volver a los recursos

Cómo prevenir el prompt injection en una app real con LLM

9 min min lectura
How to Prevent Prompt Injection: Guardrails for a Real LLM App

Lanza una función con LLM que lea algo que no controlas del todo (el mensaje de un usuario, un documento, una página web que trajo una herramienta) y acabas de abrir un canal en el que un atacante puede escribir. El prompt injection es texto que llega por ese canal e intenta secuestrar las instrucciones del modelo en lugar de responder la pregunta que se le hizo. Esta guía explica cómo prevenir el prompt injection con defensas que aguantan cuando el tráfico real llega a tu app. Ninguna te vuelve inmune. La defensa en profundidad eleva el coste de un ataque lo suficiente como para que la mayoría de los atacantes busquen un objetivo más fácil.

Qué es el prompt injection

Una app con LLM funciona entregándole al modelo un prompt: las instrucciones de sistema que escribió tu equipo, más todo lo que la petición arrastra consigo (el mensaje de un usuario, el párrafo de un documento, la salida de una llamada a una herramienta anterior). El modelo predice el siguiente tramo de texto a partir de todo eso a la vez, leyendo instrucciones y texto recuperado como un único flujo continuo de tokens. Nada marca una parte como instrucción de confianza y otra como dato sin confianza. El prompt injection es texto no confiable diseñado para que se lea como una instrucción en vez de como contenido que hay que resumir o sobre el que hay que responder una pregunta. Un correo de soporte que le dice al modelo que lo lee que revele datos de la cuenta que no debería revelar. Una línea en una página web recolectada por un scraper que le dice a un agente de investigación que se salte una verificación que debía ejecutar. La redacción cambia todo el tiempo. El patrón se mantiene fijo: el modelo termina obedeciendo contenido que no debía obedecer, porque no tiene forma incorporada de distinguir instrucción de dato.

Inyección directa frente a indirecta

La inyección directa es el caso más simple: alguien escribe en tu interfaz de chat e intenta anular sus instrucciones, pidiéndole al modelo que ignore su system prompt o que responda fuera de su alcance. Se solapa con el jailbreak, aunque el objetivo es distinto. El jailbreak suele apuntar al entrenamiento de seguridad propio del modelo. La inyección directa apunta a lo que tu app le indicó específicamente al modelo que hiciera. La inyección indirecta es la que toma desprevenidos a los equipos. El texto malicioso llega sin que la persona que está chateando en ese momento escriba ni una palabra de él: está metido en un documento que tu asistente resume, en una página web que lee tu agente de investigación, o en un ticket de soporte que procesa tu herramienta de triaje. El modelo no puede distinguir un párrafo legítimo de una instrucción plantada una vez que ambos son solo texto dentro del contexto. La inyección indirecta merece más atención de la que suele recibir. Filtrar lo que escribe un usuario no atrapa nada de esto, porque el usuario nunca escribió el ataque. Quien pregunta suele estar tan sorprendido como tú.

Filtrar lo que escribe un usuario no detiene nada de un ataque indirecto. La instrucción ya está metida en un documento, una página web o un ticket que tu app iba a leer de todos modos. Un guardrail que solo vigila la entrada del usuario se lo pierde por completo.

Por qué RAG y los agentes amplían la superficie de ataque

Un chatbot que responde desde un guion fijo casi no tiene superficie de ataque que merezca mención. Añade recuperación de información y eso cambia rápido. Cada documento que un pipeline de RAG mete en el contexto (un artículo de ayuda, un contrato subido, un resultado de búsqueda web en vivo) es texto que el modelo va a leer y sobre el que puede actuar. Amplía las fuentes de las que tira y amplías los lugares donde alguien podría plantar una instrucción. Los agentes empeoran la otra mitad del problema: las consecuencias. Un chatbot engañado para hablar de un tema no autorizado desperdicia una conversación. Un agente engañado mientras sostiene una herramienta que envía correos, escribe en una base de datos o llama a una API de pagos puede actuar sobre la instrucción que le hicieron creer legítima. El modelo hace exactamente lo que le dice su contexto, y el contexto es justo lo que quedó comprometido. La mayoría de las funciones útiles con LLM necesitan recuperación de información, acceso a herramientas, o ambas cosas. La tarea real es tratar cada pasaje recuperado y cada llamada a una herramienta como un lugar al que un atacante podría llegar.

Cómo prevenir el prompt injection: los guardrails que de verdad ayudan

Pregúntale a cinco proveedores cómo prevenir el prompt injection y te van a vender cinco productos distintos. Ninguno cierra el problema por sí solo. Lo que aguanta en la práctica es apilar defensas en capas, de modo que un solo fallo no le entregue al atacante el resultado que busca. Empieza por la capa más débil: la jerarquía de instrucciones, redactar el system prompt para que trate cierto contenido como dato e ignore las instrucciones escondidas dentro de él. Ayuda contra los intentos casuales, y también es la capa que los atacantes esquivan con más facilidad. Trátala como un reductor de velocidad. Nada más. El filtrado de entrada y salida está un escalón más arriba: un clasificador que marca contenido que parece una instrucción, o una salida que parece una fuga de información. Atrapa patrones conocidos y frena los intentos perezosos. Un atacante decidido reformula, codifica o divide la carga hasta que algo se le cuela. Las dos capas que realmente cambian el resultado cuando las dos primeras fallan son estas: a quién y a qué puede tocar el modelo, y cómo tratas lo que sale por el otro extremo.

Capa de guardrailQué detieneQué se le escapa
Endurecer la entrada y el promptIntentos casuales, formulaciones conocidasUna inyección bien elaborada o indirecta
Acceso con mínimo privilegio a herramientas y datosEl daño después de que una inyección logra pasarEl intento de inyección en sí
Gestión de la salida y supervisión humanaUna respuesta manipulada que dispara un daño realUn uso indebido de bajo riesgo que nadie controló
Monitoreo y registroIntentos repetidos, detectados después del hechoEl primer intento exitoso

Acceso con mínimo privilegio a herramientas y datos

El acceso con mínimo privilegio es la defensa que sigue dando resultado incluso cuando todas las demás capas fallan. Dale al modelo, y a cualquier herramienta que llame, solo los permisos y los datos que necesita para la tarea que tiene delante. Un agente de soporte que responde preguntas de facturación no necesita acceso de escritura a la base de datos de facturación. Una herramienta que resume documentos no necesita una que envíe correos. Si una inyección se cuela por todos los filtros, el radio de la explosión se queda pequeño porque no hay nada peligroso al alcance. Delimita las claves de API y los permisos de herramientas por tarea, no por app. Separa las credenciales que usa una función de resumen de las que usa una función de facturación. Aísla los datos por cliente para que los documentos de uno jamás puedan responder la pregunta de otro. Mantener acotado el alcance del modelo es lo que decide si una inyección te llega a costar algo.

Tu función con LLM acaba de convertirse en una superficie de ataque

En cuanto un modelo lee contenido externo o sostiene una herramienta, el prompt injection deja de ser una hipótesis. Cuéntanos qué construiste, qué lee y qué tiene permitido tocar. Te mostramos en un mapa dónde podría hacer daño una instrucción inyectada y qué guardrails cierran esa brecha primero.

Solicita una revisión de guardrails

Gestión de la salida y supervisión humana

Todo lo que un modelo devuelve merece la misma sospecha que le tendrías a un texto escrito por un desconocido en internet. En un sentido muy real puede ser exactamente eso: las palabras de un desconocido, lavadas a través de tu modelo. Renderizar esa salida directamente en una página web sin escaparla puede convertir una inyección exitosa en un script guardado que golpea a cada visitante después del primero. Pasarla a una consulta de base de datos o a un comando de shell convierte un problema de lenguaje en un problema de ejecución de código. La supervisión humana cierra el hueco que ningún filtrado va a cerrar. Cualquier cosa con consecuencias reales (mover dinero, borrar un registro, escribirle a alguien fuera de tu empresa, cambiar un permiso) debería detenerse para que una persona lo confirme primero, sin importar cuán seguro suene el modelo. Un modelo inyectado con éxito suena exactamente tan seguro como uno legítimo. La confianza nunca fue la señal en la que había que apoyarse.

El filtrado de salida atrapa patrones maliciosos conocidos en lo que devuelve un modelo. No va a atrapar una fuga sutil formulada de una manera para la que todavía nadie escribió una regla. Trata el filtrado como una red con agujeros, y pon un límite de permisos detrás de todo lo que importa.

Pon a prueba tus defensas

Poner a prueba las defensas contra el prompt injection se ve distinto a probar una función normal. El resultado es una medida de resistencia, más un gradiente que una casilla que marcas. El único método real es hacer red teaming de tu propia app, intentando los ataques que probaría alguien de fuera antes de que lo haga de verdad. Cubre los dos ángulos. Prueba intentos directos a través de la interfaz de chat, pidiéndole al modelo que ignore sus instrucciones o revele su system prompt. Después prueba intentos indirectos: planta una instrucción dentro de un documento que tu app realmente ingeriría, y fíjate si el modelo la sigue. Un conjunto de pruebas pequeño y adversarial atrapa más que un conjunto mucho más grande de preguntas de uso normal. Ejecuta esto antes de lanzar, y de nuevo cada vez que cambie el system prompt o una fuente de datos, la misma disciplina que nuestra guía de métricas de evaluación de LLM recomienda para las pruebas de regresión. Quien escribió la defensa suele ser la peor persona para probarla. Pide a un colega que dedique veinte minutos a intentar romperla.

Un nivel base de seguridad en la etapa MVP

Un fundador que lanza rápido no necesita guardrails con la profundidad de una empresa grande desde el primer día. Un nivel base realista para la etapa MVP cubre cuatro cosas:

  • Delimita cada conexión a herramientas y datos con los permisos más estrechos posibles
  • Trata todo el contenido recuperado y toda la salida del modelo como no confiable por defecto
  • Exige que una persona confirme cualquier acción con consecuencias antes de que se ejecute
  • Registra actividad suficiente como para que un patrón raro se note

Presupuesta esto desde el inicio. El trabajo de guardrails es parte de la función misma. Saltártelo aparece después como un ticket de soporte, o algo peor. Nuestra guía de costes de desarrollo de apps con IA desglosa cuánto suma esto a una construcción. La defensa contra el prompt injection es una pieza de un panorama de seguridad más amplio. Nuestra guía de seguridad y escalabilidad en el desarrollo de MVP cubre el resto. Nada de esto vuelve inmune a una función con LLM frente a un atacante decidido. Un nivel base en capas, revisado a medida que la función crece, mantiene a un atacante realista trabajando más duro de lo que vale la pena. Si estás definiendo el alcance de los guardrails para una función que toca datos reales de usuarios, habla con nuestro equipo de integración de IA y ajustamos la defensa a su medida.

Tags

Preguntas frecuentes

Encuentra respuestas a preguntas frecuentes sobre este tema.