flawopen.com/Teardowns/cve-2026-87913-aws-security-agent-mcp-s3-bucket-ownership
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]
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]
Mapeos de marcos
- Referencia CWE para la debilidad descrita en esta guía: CWE-283 CWE-341
- OWASP GenAI 2025 — LLM06:2025 Agencia excesiva
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ímite | Condición documentada | Acción del operador |
|---|---|---|
| Versiones afectadas | awslabs.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 bucket | El 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 cuentas | El 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 corregido | ExpectedBucketOwner 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
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.
# 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,
)
# 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
- ✓Actualiza a 0.2.0 o posterior y comprueba la versión activa, incluidos plugins, imágenes CI y forks.[2], [4]
- ✓Antes de analizar, verifica que el bucket derivado pertenece a la cuenta AWS prevista; resolver el nombre no prueba propiedad.[1], [2]
- ✓Envía el ID esperado mediante
ExpectedBucketOwneren cada operación S3, incluida la subida.[8], [9] - ✓Falla de forma segura si el dueño no coincide. Si pertenece a terceros, detén los análisis y contacta con AWS.[1]
- ✓Cuando corresponda, crea el bucket en la cuenta del cliente antes del primer uso y aplica mínimo privilegio y cifrado.[3], [1]
- ✓Revisa análisis realizados con versiones afectadas y rota credenciales si los archivos pudieron contener secretos.[2], [1]
Fuentes
- AWS Security Bulletin 2026-105-AWS — CVE-2026-87913
- Maintainer GHSA-3jxw-vj8m-8x77
- AWS Security Agent IDE integration and scan bucket workflow
- awslabs.security-agent-mcp-server 0.2.0 release
- NVD — CVE-2026-87913
- MITRE CWE-283 — Unverified Ownership
- MITRE CWE-341 — Predictable from Observable State
- Boto3 HeadBucket — ExpectedBucketOwner
- Boto3 PutObject — ExpectedBucketOwner
- Fallo relacionado en el mismo paquete (CVE distinto): inyección de argumentos Git en AWS MCP, CVE-2026-97662