Reports
MEDIA[CONFIGURACIÓN]#3632577

AWS Bedrock AgentCore: el CLI creaba roles IAM de Gateway sin protección contra el "confused deputy" entre cuentas

El comando `agentcore gateway create` generaba roles IAM con una política de confianza sin `aws:SourceArn` ni `aws:SourceAccount`, de modo que AgentCore desde otra cuenta podía asumirlos y leer secretos, S3 o invocar Lambdas ajenas.

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 Bedrock AgentCore Starter Toolkit es la herramienta de línea de comandos de AWS para montar infraestructura de AgentCore (https://github.com/aws/bedrock-agentcore-starter-toolkit). Al ejecutar agentcore gateway create, el toolkit crea un rol IAM para el Gateway cuya política de confianza autoriza al servicio bedrock-agentcore.amazonaws.com a asumirlo, pero sin ninguna condición que limite desde qué cuenta o recurso se hace.

Ese es el patrón clásico de confused deputy entre cuentas: como el principal es un servicio compartido por todos los clientes de AWS, cualquier carga de trabajo de AgentCore en cualquier otra cuenta podía conseguir que el servicio asumiera el rol de la víctima en su nombre.

Lo llamativo es que la protección ya existía en otros sitios del mismo proyecto:

  • La consola web de AWS sí añade las condiciones al crear un Gateway.
  • La plantilla Jinja2 utils/runtime/templates/execution_role_trust_policy.json.j2 también las incluye.

El fallo estaba en la constante que usa el CLI para el Gateway, en src/bedrock_agentcore_starter_toolkit/operations/gateway/constants.py (líneas 47-56). El mismo olvido aparecía en las plantillas de infraestructura como código: la de CDK (agentcore-stack.ts.j2, líneas 37-40 y 312-314) y la de Terraform (bedrock_agentcore.tf.j2, líneas 238-247). Es decir, todas las vías automatizadas de despliegue estaban afectadas, no solo el CLI.

El problema se agrava por los permisos que recibe ese rol (líneas 58-102 del mismo fichero):

  • bedrock-agentcore:* sobre arn:aws:bedrock-agentcore:*:*:*
  • secretsmanager:GetSecretValue sobre *
  • lambda:InvokeFunction sobre arn:aws:lambda:*:*:function:*
  • kms:* sobre arn:aws:kms:*:*:*
  • La política gestionada AmazonDynamoDBFullAccess
  • La política gestionada AmazonS3ReadOnlyAccess

Pasos de reproducción

  1. Instalar el toolkit y crear un Gateway con el CLI:
pip install bedrock-agentcore-starter-toolkit
agentcore gateway create --name my-gateway
  1. Consultar la política de confianza del rol IAM que se ha creado:
aws iam get-role --role-name <gateway-role-name> --query 'Role.AssumeRolePolicyDocument'
  1. Comprobar que coincide con la constante del código, sin bloque Condition:
BEDROCK_AGENTCORE_TRUST_POLICY = {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {"Service": "bedrock-agentcore.amazonaws.com"},
            "Action": "sts:AssumeRole",
        }
    ],
}

Para comparar, la plantilla Jinja2 del propio proyecto sí restringe la cuenta y el ARN de origen:

"Condition": {
    "StringEquals": {
        "aws:SourceAccount": "{{ account_id }}"
    },
    "ArnLike": {
        "aws:SourceArn": "arn:aws:bedrock-agentcore:{{ region }}:{{ account_id }}:*"
    }
}
  1. Desde otra cuenta de AWS con acceso a AgentCore, configurar un destino (target) de un Gateway propio indicando el ARN del rol de la víctima. Cuando el Gateway del atacante hace llamadas, el servicio AgentCore asume el rol de la víctima por cuenta del atacante.

Para el paso 4 solo hace falta conocer el ARN del rol, que según el investigador sigue un patrón de nombres predecible generado por el toolkit.

Impacto

Con una cuenta de AWS propia y acceso a AgentCore, un atacante podía actuar en la cuenta de la víctima con los permisos del rol:

  • Leer todos los secretos de Secrets Manager (secretsmanager:GetSecretValue sobre *).
  • Invocar cualquier función Lambda.
  • Leer todo el contenido de S3 (AmazonS3ReadOnlyAccess).
  • Leer, modificar y borrar cualquier tabla de DynamoDB (AmazonDynamoDBFullAccess).
  • Administrar las claves KMS, incluido desactivarlas o programar su borrado (kms:*).

HackerOne clasificó el reporte como de severidad media, con la debilidad "Incorrect Permission Assignment for Critical Resource".

Remediación

El reporte figura como resuelto, aunque no detalla qué cambio aplicó AWS finalmente. El investigador propuso añadir las condiciones a BEDROCK_AGENTCORE_TRUST_POLICY en constants.py, igual que en la plantilla Jinja2, parametrizando la cuenta y la región en tiempo de ejecución:

BEDROCK_AGENTCORE_TRUST_POLICY = {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {"Service": "bedrock-agentcore.amazonaws.com"},
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "<ACCOUNT_ID>"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:bedrock-agentcore:<REGION>:<ACCOUNT_ID>:*"
                }
            },
        }
    ],
}

También recomendó aplicar el mismo cambio en las plantillas de CDK y Terraform, y reducir los permisos del rol:

  • Limitar secretsmanager:GetSecretValue a los secretos de Secrets Manager cuyo nombre empieza por bedrock-agentcore-identity!.
  • Sustituir kms:* por las acciones concretas necesarias, como kms:Decrypt y kms:GenerateDataKey.

Cronología: enviado el 27 de marzo de 2026 y divulgado el 15 de julio de 2026.