Nunca interpoles la entrada del agente en comandos o consultas
Never interpolate agent input into commands or queries
Trata cada argumento que envía un agente como entrada no confiable, y pásalo a shells, bases de datos e intérpretes solo como parámetro, nunca como parte de una cadena que construyes y ejecutas.
Por qué
Los argumentos de una herramienta los escribe un modelo, y el contexto del modelo puede contener texto que un atacante dejó en una página web, un correo o un documento. Lo que llega a tu herramienta puede ser hostil aunque ni el agente ni su usuario lo sean. OWASP incluye la inyección de comandos como MCP05 en su MCP Top 10: ocurre cuando la petición de un agente se convierte en un comando del sistema, un script, una consulta o un fragmento de código construido con entrada no confiable y sin validar. Las defensas son antiguas y conocidas, y se aplican sin cambios. La guía de OWASP es no usar nunca shell=True, eval(), exec() ni comandos construidos con cadenas, ejecutar con parámetros estructurados, validar la salida del agente contra un esquema antes de actuar y usar SQL y APIs parametrizadas. Su hoja de referencia sobre inyección de comandos pone primero evitar los comandos del sistema (una función de biblioteca no se puede convencer de hacer otra cosa) y después la parametrización junto con la validación de entradas. La especificación de MCP deja clara la parte del servidor: los servidores DEBEN validar todas las entradas de las herramientas y sanear sus salidas. El esquema de entrada de tu herramienta es el primer filtro; la ejecución parametrizada es la que resiste cuando el esquema admite una cadena.
Haz
Valida los argumentos contra el esquema de la herramienta y pásalos a comandos y consultas como parámetros separados.
No hagas
Construir un comando de shell, una sentencia SQL o una cadena para eval concatenando lo que envió el agente.
Artefacto
# Mal: la ruta del agente pasa a formar parte de la línea de comandos
os.system(f"tar -czf backup.tgz {args['path']}")
cursor.execute(f"SELECT * FROM orders WHERE customer = '{args['customer']}'")
# Bien: los argumentos siguen siendo datos
subprocess.run(["tar", "-czf", "backup.tgz", "--", args["path"]], check=True)
cursor.execute("SELECT * FROM orders WHERE customer = %s", (args["customer"],))
Fuentes
- [01]MCP Specification 2026-07-28: Tools (Security Considerations) ↗
Servers MUST validate all tool inputs, implement proper access controls, rate limit tool invocations, and sanitize tool outputs
- [02]OWASP MCP Top 10 (MCP05:2025 Command Injection & Execution) ↗
Command injection occurs when an AI agent constructs and executes system commands, shell scripts, API calls, or code snippets using untrusted input without proper validation or sanitization. Never use shell=True, eval(), exec(), or string-built commands; always execute with structured parameters, validate agent output against schemas before execution, and use parameterized SQL/APIs, never interpolating input
- [03]OWASP Cheat Sheet Series: OS Command Injection Defense ↗
The primary defense is to avoid calling OS commands directly, since built-in library functions cannot be manipulated to perform other tasks; where that is not possible, use parameterization, structured mechanisms that automatically enforce the separation between data and command, together with input validation