Descripción general

Xinference utiliza la función insegura eval() de Python al parsear la salida de tool-calls generada por el modelo Llama3. Dado que la salida del modelo puede ser influenciada por prompts controlados por un atacante enviados a la API de chat completion, un atacante remoto puede construir prompts que provoquen que el modelo devuelva una expresión Python arbitraria. Xinference evalúa esa expresión en el proceso del servidor durante el post-procesamiento del resultado del tool-call. En el despliegue por defecto analizado, la autenticación no estaba habilitada, por lo que la vulnerabilidad era explotable por un atacante remoto no autenticado a través del endpoint /v1/chat/completions.

Detalles técnicos

Los usuarios pueden interactuar con los modelos desplegados a través de la API compatible con OpenAI de Xinference: /v1/chat/completions. El punto de entrada de las peticiones está implementado en xinference/api/restful_api.py; las peticiones no streaming invocan el método chat() de la instancia del modelo y devuelven el resultado de la inferencia.

Cuando se utiliza el backend Transformers, los resultados de inferencia fluyen a través de la lógica de batching en xinference/model/llm/transformers/core.py. Los resultados de chat no streaming son gestionados por handle_chat_result_non_streaming(). Si la petición contiene un campo tools, Xinference invoca _post_process_completion() para parsear la salida de tool-calls de la respuesta del modelo.

El parser de tool-calls de Llama3 está implementado en xinference/model/llm/tool_parsers/llama3_tool_parser.py. En las versiones afectadas, extract_tool_calls() parseaba la salida del modelo con eval():

python
def extract_tool_calls(
    self, model_output: str
) -> List[Tuple[Optional[str], Optional[str], Optional[Dict[str, Any]]]]:
    try:
        data = eval(model_output, {}, {})
        return [(None, data["name"], data["parameters"])]
    except Exception:
        return [(model_output, None, None)]

El comportamiento previsto era convertir una cadena con formato de diccionario Python generada por el modelo en un objeto diccionario. Sin embargo, eval() ejecuta la entrada como una expresión Python, y eval(model_output, {}, {}) no constituye un sandbox de seguridad. Si un atacante puede influir en la salida del modelo mediante prompt injection o entrada directa de chat, puede provocar que el modelo devuelva una expresión como:

python
__import__('os').system('touch /tmp/hacked')

Cuando la expresión alcanza eval(), se ejecuta en el contexto del proceso del servidor Xinference. El comando inofensivo touch /tmp/hacked puede sustituirse por otros payloads, como una reverse shell, descarga de malware, lectura de ficheros sensibles o payloads de movimiento lateral.

Puntuación CVSS

Severidad: Crítica

CVSS v3.1: 10.0

Vector:

code
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Justificación de la puntuación:

  • AV:N: la API vulnerable es accesible remotamente a través de la red.
  • AC:L: la explotación solo requiere una petición de chat completion y un parámetro de tool-call manipulados.
  • PR:N: la configuración por defecto analizada no requería autenticación.
  • UI:N: no se requiere interacción del usuario.
  • S:C: la ejecución de comandos puede afectar a recursos más allá del límite de la aplicación Xinference.
  • C:H/I:H/A:H: la ejecución remota de código puede comprometer completamente la confidencialidad, integridad y disponibilidad.

Créditos

Esta vulnerabilidad fue descubierta por: