FlawOpen

flawopen.com/Teardowns/cve-2026-87913-aws-security-agent-mcp-s3-bucket-ownership

● CVE-2026-87913 · CVSS 5.1 · Media
Investigación · FlawOpen

CVE-2026-87913: Fuga S3 en el MCP de AWS

Un bucket predecible podía recibir archivos de análisis privados en otra cuenta. Actualiza a 0.2.0 y verifica al propietario.[1], [2], [4]

💡 Explicación en Lenguaje Sencillo (ELI5)

Imagina un mensajero que comprueba que existe un edificio en una dirección, pero no quién es su dueño. Otra persona puede registrar esa dirección primero y recibir el paquete. S3 debe confirmar al propietario esperado al comprobar y al subir.[2], [1]

Conceptos Clave y Términos

Servidor MCP
Servicio local que ofrece herramientas a un asistente de IA; se ejecutan con los permisos del proceso servidor.[3]
Bucket S3
Contenedor Amazon S3 con nombre global; el nombre no revela qué cuenta AWS lo posee.[2], [3]
ExpectedBucketOwner
Parámetro S3 que exige confirmar el ID esperado de la cuenta propietaria antes de operar.[2], [8], [9]
CWE-283 y CWE-341
Debilidades MITRE de propiedad no verificada y valores predecibles; el aviso asigna ambas al problema.[8], [9]

Mapeos de marcos

Análisis de Causa Raíz

El servidor MCP de AWS Security Agent deriva el nombre del bucket de entrada del análisis a partir del ID de cuenta AWS del cliente y la región: security-agent-scans-<account-id>-<region>. AWS y el mantenedor indican que la versión vulnerable comprobaba si existía el bucket, pero no si pertenecía al cliente. Los nombres S3 son globales y los ID de cuenta son públicos. Un tercero que registrara primero el nombre predecible podía recibir el archivo privado enviado por el servidor; puede contener código, credenciales y estado de infraestructura. Es un fallo de propiedad de recursos cloud y nombre predecible, no prompt injection del modelo de IA. Afecta a las versiones 0.1.0–0.1.5; la 0.2.0 añade ExpectedBucketOwner a las operaciones S3 y falla si el dueño es otro. Actualizar no libera un nombre ya registrado: verifica al propietario real y no reanudes análisis si el bucket es de un tercero.

El nombre del bucket no demuestra quién es su propietario

LímiteCondición documentadaAcción del operador
Versiones afectadasawslabs.security-agent-mcp-server 0.1.0 a 0.1.5 están afectadas; 0.2.0 añade la comprobación de propiedad.Actualiza a 0.2.0 o posterior y verifica la versión del paquete en ejecución.
Nombre predecible del bucketEl nombre del bucket de análisis se deriva del ID de cuenta y la región; otra cuenta de AWS puede registrarlo.Trata el nombre coincidente como una dirección, no como prueba de propiedad.
Carga entre cuentasEl servidor vulnerable podía aceptar el bucket por su nombre sin verificar al propietario y luego cargar un archivo privado del análisis.Verifica que el bucket pertenece a la cuenta esperada antes de analizar o cargar.
Límite de propiedad corregidoExpectedBucketOwner hace que S3 compare el propietario tanto en la comprobación como en la carga.Actualiza, verifica al propietario real y detén los análisis si el nombre pertenece a terceros; la actualización no transfiere el bucket.

Flujo de Ataque Paso a Paso

Paso 1

La solicitud de análisis recibe el código

Un cliente de IA solicita el análisis; el servidor empaqueta el espacio de trabajo y usa su identidad AWS.[3], [2]

Paso 2

El destino se puede predecir

El nombre deriva del ID de cuenta y la región; los ID no son secretos y los nombres S3 son globales.[1], [2]

Paso 3

La comprobación solo ve existencia

El servidor aceptaba el bucket por su nombre sin confirmar que pertenecía al cliente.[2], [1]

Paso 4

El archivo puede llegar a otra cuenta

Si otra cuenta registraba antes el nombre, podía recibir el archivo privado, que quizá contiene datos sensibles.[2], [1]

Código Fuente: Vulnerable vs. Seguro

El ejemplo es esquemático, no una copia literal. La existencia no basta: S3 debe comparar la cuenta propietaria esperada al comprobar y al escribir. Obtén esa cuenta de la identidad AWS autenticada y detén la operación si no coincide. Tras actualizar, verifica por separado al propietario del bucket: la actualización no transfiere ni libera un nombre ya registrado. AWS documenta ExpectedBucketOwner tanto para HeadBucket como para PutObject: si no coincide, la petición falla con 403. Úsalo como control fail-closed, pero investiga los errores de acceso denegado mediante una vía autorizada de verificación de propiedad antes de concluir que el bucket es ajeno.[2], [8], [9]

Fragmento de origen: Ejemplo de AWS SDK basado en el aviso; no es un diff literal del código fuente.

IMPLEMENTACIÓN VULNERABLE
# Forma vulnerable simplificada: se comprueba el nombre, pero no quién es su propietario.
s3.head_bucket(Bucket=bucket_name)
s3.put_object(
    Bucket=bucket_name,
    Key=object_key,
    Body=archive_bytes,
)
PARCHE SEGURO Y ROBUSTO
# Vincule cada operación a la cuenta propietaria esperada del bucket.
expected_owner = sts.get_caller_identity()["Account"]
s3.head_bucket(
    Bucket=bucket_name,
    ExpectedBucketOwner=expected_owner,
)
s3.put_object(
    Bucket=bucket_name,
    Key=object_key,
    Body=archive_bytes,
    ExpectedBucketOwner=expected_owner,
)

Lista de Verificación de Seguridad para Ingeniería

Fuentes