
Reproducción benigna y autocontenida de CVE-2026-77521 (ejecución de comandos con inyección de prompts en MaxKB)
Un laboratorio autocontenido y benigno que reproduce
GHSA-f36j-f34j-h3rx
/ CVE-2026-77521: en MaxKB (una
plataforma de asistente de IA empresarial / RAG de código abierto), cualquier asistente con una herramienta,
herramienta MCP, skill o sub-aplicación recibe una herramienta execute de shell autoinyectada
que no está detrás de una puerta de aprobación humana — por lo que la inyección de prompt (desde el chat
o desde un documento ingerido) llega a un shell. Se suponía que un sandbox lo contendría,
pero una cadena con shell=True permitió que los metacaracteres escaparan de él.
| Aviso | GHSA-f36j-f34j-h3rx |
| CVE | CVE-2026-77521 |
| Proyecto | 1Panel-dev/MaxKB |
| Afectado | < 2.10.5-lts |
| Parcheado | 2.10.5-lts (commit 594f50f) — parcial, ver más abajo |
| CVSS | 10.0 CRÍTICO (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| Debilidad | CWE-78 (inyección de comandos del SO) · CWE-250 (privilegios innecesarios) · CWE-749 (método peligroso expuesto) |
Esto reproduce una vulnerabilidad parcheada y divulgada públicamente con fines educativos y defensivos. Se ejecuta enteramente de forma local y de manera benigna:
id, escribir un archivo marcador
que la PoC elimina). No interviene ningún gosu/sandbox/root real — el envoltorio de reducción de privilegios
se sustituye por un marcador env inerte para que la demo se ejecute en cualquier lugar.Un asistente de MaxKB con cualquier capacidad adjunta se construye sobre deepagents con
un SandboxShellBackend. deepagents autoinyecta una herramienta execute de shell (además de
read_file/write_file/…), y MaxKB no usa excluded_tools, por lo que execute está
siempre presente. La configuración interrupt_on — que decide qué requiere aprobación
humana — es {"write_file": False, "read_file": False, "edit_file": False}:
execute no está en ella, por lo que se ejecuta sin aprobación. Cualquier texto que pueda dirigir
al modelo (un mensaje de chat, o un documento envenenado que ingiere el pipeline RAG) puede
por tanto hacer que el agente ejecute comandos de shell. En instalaciones desde código fuente SANDBOX
está desactivado por defecto, por lo que los comandos se ejecutan como el usuario de la aplicación; en el contenedor
oficial (root) el envoltorio del sandbox era una cadena con shell=True, por lo que ;/>/$() se ejecutaban fuera
de gosu, como root.
interrupt_on real de MaxKB,
una llamada execute inyectada se ejecuta sin aprobación; añadir
"execute": True la condiciona. → poc/01_missing_hitl_gate.py;+redirección escapa del
prefijo gosu de cadena única; el re-entrecomillado de _build_sandbox_command() en 2.10.5-lts
lo neutraliza. → poc/02_sandbox_escape.pyexecute con el comando del atacante (y no lo hace con un documento
limpio). → poc/03_real_llm.pyEl parche 2.10.5-lts incluido (commit 594f50f)
refuerza solo el escape del sandbox — añade _build_sandbox_command(), que
divide por operadores de shell, vuelve a citar cada token con shlex.quote y envuelve
cada comando simple en el prefijo gosu. Verificado contra el
código fuente de v2.10.5-lts,
el núcleo de la agencia está sin cambios: interrupt_on sigue omitiendo execute, el
backend sigue siendo SandboxShellBackend, y SANDBOX sigue teniendo 0 por defecto. Así que
tras el arreglo, un execute inyectado por prompt sigue ejecutándose sin aprobación humana —
se reforzó el muro interior mientras la puerta permanecía abierta. La PoC 1 demuestra la
mitigación recomendada (restringir execute), que el proveedor no incluyó.
Sin dependencias para la PoC 1/2 (Python 3.9+):
./run.sh # all three (PoC 3 skips without an endpoint)
python3 poc/01_missing_hitl_gate.py # missing approval gate
python3 poc/02_sandbox_escape.py # metacharacter sandbox escape
¿Presentando esto?
DEMO.mdes un runbook ydemo.shlo guía pulsación a pulsación.
Cualquier endpoint compatible con OpenAI (autoalojado o modelo abierto alojado). Ejemplo (Groq):
export OPENAI_BASE_URL=https://api.groq.com/openai/v1
export OPENAI_API_KEY=$GROQ_API_KEY # read from env only; never logged
MODEL="openai/gpt-oss-20b" python3 poc/03_real_llm.py
Detrás de un proxy de inspección TLS, reintenta sin verificar con una advertencia
(INSECURE_SSL=1 para forzarlo). Se omite limpiamente si no hay ningún endpoint configurado.
| Ruta | Qué es |
|---|---|
sandbox_shell.py | Modelo benigno de la construcción del comando execute() de MaxKB — cadena vulnerable frente a _build_sandbox_command() parcheado |
agent_sim.py | Modelo mínimo de la puerta de aprobación humana interrupt_on de deepagents |
payloads/poisoned-document.md | Documento de KB envenenado por el atacante (inyección indirecta) |
poc/01_missing_hitl_gate.py | El execute inyectado se ejecuta sin aprobación; el gating lo bloquea |
poc/02_sandbox_escape.py | Los metacaracteres escapan del prefijo gosu; el parser de 2.10.5 los contiene |
poc/03_real_llm.py | Un modelo real llama a execute desde el documento envenenado (limpio vs envenenado) |
DEMO.md / demo.sh | Guion del presentador y controlador de demo con ritmo |
assets/attack-flow.{svg,png} | Diagrama del flujo de ataque (imagen principal del blog) |
assets/poc3-groq-sample.txt | Salida grabada de la PoC 3 (respaldo de la demo) |