¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

El delegado confundido en agentes de IA

Después de esta lección: Puedo evitar que un agente actúe con más autoridad que la persona que pide, comprobando cada acción contra quien la pide.

Lección de 70 min8 comandosLaboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

Qué es el problema del delegado confundido

Un delegado confundido es un programa con autoridad al que convencen de usarla para alguien que no tiene ninguna. Un agente es un delegado por diseño: actúa por las personas mediante herramientas y cuentas.

Si el agente tiene una sola llave amplia y confía en cualquiera que le pida algo, todo el que pueda escribirle tiene esa llave.

Al final de esta lección

Nota

Puedo evitar que un agente actúe con más autoridad que la persona que pide, comprobando cada acción contra quien la pide.

Palabras clave

PalabraQué significaEjemplo
Delegado confundidoun programa que usa su propia autoridad para una persona que no la tiene
Autoridadlo que una identidad puede hacer, aquí como acciones sobre recursosread:nomina
Alcanceun permiso con nombre dentro de un token
Token estrechoun token con solo los alcances que necesita la tarea, durante poco tiempo
Solicitantela persona por cuenta de quien actúa el agente en esta petición

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Qué autoridad lleva una llamada

Supón que un agente entra en el sistema de nóminas con su propia llave. Ana, que solo puede leer notas, le pide el archivo de nóminas. El sistema ve la llave del agente y dice que sí.

No engañó al agente una línea oculta. Solo se lo pidieron. El fallo es que la llamada llevaba la autoridad del agente y no la de Ana.

Ejemplo resuelto: tres diseños

DiseñoLo que lleva la llamadaQué pasa cuando Ana pide la nómina
Una sola llave ampliaLa llave del agenteEl sistema lo permite
Se pasa la identidad del solicitanteLa identidad de AnaEl sistema comprueba a Ana y rechaza
Token estrecho por tareaSolo los alcances que necesita la tareaEl alcance no está en el token, así que falla

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

El Run decide las llamadas de dos maneras

El primer script guarda dos usuarios y tres llamadas inventadas. Decide cada llamada dos veces: una por el token del agente y otra por los derechos de quien pide.

Donde las dos respuestas difieren, el agente actuaría con más autoridad que la persona que pide. El script marca esa línea. No se llama a nada y nadie recibe un ataque.

Escribe la comprobación doble, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const rights = {' '  ana: [\"read:notas\"],' '  luis: [\"read:notas\", \"read:nomina\"],' '};' 'const agentToken = [\"read:notas\", \"read:nomina\"];' 'const calls = [' '  { user: \"ana\", action: \"read\", resource: \"notas\" },' '  { user: \"ana\", action: \"read\", resource: \"nomina\" },' '  { user: \"luis\", action: \"read\", resource: \"nomina\" },' '];' > deputy.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe la comprobación doble, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function want(c) { return c.action + \":\" + c.resource; }' 'function byAgent(c) { return agentToken.includes(want(c)); }' 'function byAsker(c) { return (rights[c.user] || []).includes(want(c)); }' '' 'for (const c of calls) {' '  const a = byAgent(c), b = byAsker(c);' '  let line = c.user + \" pide \" + want(c) + \": token del agente \" + (a ? \"permite\" : \"niega\");' '  line += \", derechos de quien pide \" + (b ? \"permite\" : \"niega\");' '  console.log(line + (a && b === false ? \"  <- delegado confundido\" : \"\"));' '}' >> deputy.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecuta la comprobación doble

Comando
docker exec -w /home/node/project agent node deputy.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Lo que imprime el script

LíneaLo que muestra
ana pide read:notasLas dos permiten. Ana puede leer notas
ana pide read:nominaEl token permite, sus derechos niegan: marcada como delegado confundido
luis pide read:nominaLas dos permiten. Luis tiene ese derecho

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Tres arreglos que funcionan juntos

Pasa al solicitante. Cada llamada lleva la identidad de la persona, y la herramienta o la API la comprueba.

Estrecha el token. Da a una tarea solo los alcances que necesita y deja que caduquen pronto.

Comprueba cada acción en el código. Comprueba en el punto donde ocurre la acción, cada vez. Nunca preguntes al modelo si está permitido.

Un error frecuente

Advertencia

Muchos escriben «ayuda a los usuarios solo con sus propios archivos» en el prompt y se paran ahí. Un prompt es una petición al modelo. La tabla de derechos en el código es la regla, y da la misma respuesta siempre.

Escribe el script del modelo, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' '' 'const rights = { ana: [\"read:notas\"] };' 'const call = { user: \"ana\", action: \"read\", resource: \"nomina\" };' 'const messages = [' '  { role: \"system\", content: \"Eres un asistente de oficina. La usuaria Ana solo puede leer las notas. Responde con una palabra, permitir o denegar, y una razón breve.\" },' '  { role: \"user\", content: \"Ana te pide que leas el archivo de nóminas. ¿Qué haces?\" },' '];' '// Muestra grabada, usada solo cuando ningún modelo responde.' 'const sample = \"denegar. Ana solo puede leer las notas.\";' > deputy2.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el script del modelo, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function decide(c) {' '  const allowed = rights[c.user] || [];' '  return allowed.includes(c.action + \":\" + c.resource) ? \"permitir\" : \"denegar\";' '}' '' 'async function main() {' '  const reply = await ask(messages, sample, 60);' '  console.log(\"El modelo dice: \" + reply);' '  console.log(\"El programa decide: \" + decide(call));' '  console.log(\"La llamada solo se ejecuta si el programa dice permitir.\");' '}' 'main();' >> deputy2.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el ayudante del modelo, parte 1

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 200 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"estado \" + res.status);' '    return (await res.json()).choices[0].message.content;' > model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe el ayudante del modelo, parte 2

Comando
docker exec -w /home/node/project agent sh -c "printf '%s\n' '  } catch (error) {' '    console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' '    const list = [].concat(sample);' '    const turn = messages.filter(function (m) { return m.role === \"assistant\"; }).length;' '    return list[Math.min(turn, list.length - 1)];' '  }' '}' 'module.exports = { ask };' >> model.js"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejecútalo con el modelo

Comando
docker exec -w /home/node/project agent node deputy2.js

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Una posible salida

LíneaLo que puede mostrar
El modelo diceUna palabra como denegar con una razón breve. Las palabras cambian en cada ejecución
El programa decidedenegar, siempre, porque Ana no tiene derecho a la nómina en la tabla
Muestra grabadaSe imprime primero cuando ningún modelo respondió. El script sigue con la muestra

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Sobre este laboratorio y su código: Laboratorio de agente de programación con IA: usa opencode para explicar y corregir código, y comprueba su trabajo

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.