Resumen
Amazon Bedrock permite generar API keys de tipo bearer: las de larga duración empiezan por ABSK y las de corta duración por bedrock-api-key-. Para protegerse si una de esas claves se filtra, AWS publica tres controles en su documentación y en su blog de seguridad:
- Una política SCP/IAM que deniega
bedrock:CallWithBearerToken. - Una regla de detección en CloudTrail que filtra por
additionalEventData.callWithBearerToken = true. - El registro de prompts y respuestas con
aws bedrock put-model-invocation-logging-configuration.
El investigador descubrió que esas mismas claves también autenticaban contra un segundo plano de inferencia, https://bedrock-mantle.{region}.api.aws, que no aparecía en la documentación de Bedrock ni en la de sus API keys. Ese plano expone una API compatible con OpenAI (/v1/models, /v1/chat/completions), respondía en al menos 7 regiones y permitía invocar y facturar 38 de los 39 modelos del catálogo. Ninguno de los tres controles anteriores le afectaba:
| Control recomendado | Comportamiento en bedrock-mantle | |---|---| | Deny de bedrock:CallWithBearerToken | No aplica: mantle usa la acción bedrock-mantle:CallWithBearerToken. | | Filtro additionalEventData.callWithBearerToken = true | No coincide: en mantle el campo está en requestParameters.callWithBearerToken. | | put-model-invocation-logging-configuration | Los prompts de mantle no llegan al bucket de logs, y no existe una API equivalente para mantle. |
La política gestionada AmazonBedrockLimitedAccess (versión 8), que la consola asigna automáticamente al usuario IAM creado junto con cada clave de larga duración, ya incluía las acciones bedrock-mantle:* (CallWithBearerToken, Get*, List*, CreateInference). El fallo se clasificó como inicialización insegura por defecto de un recurso y con severidad media.
Pasos de reproducción
Requisitos previos:
- Una cuenta de AWS con Bedrock disponible en la región de prueba (
us-east-1) y acceso aprobado a algún modelo. - Una API key de larga duración creada desde la consola (Amazon Bedrock Console → API keys → Generate API key → Long-term). Esto crea un usuario IAM
BedrockAPIKey-<id>conAmazonBedrockLimitedAccessy devuelve un token que empieza porABSK. - AWS CLI con permisos
iam:PutUserPolicyeiam:DeleteUserPolicysobre ese usuario. - Un trail de CloudTrail en la región (para ver el evento del paso 4) y el registro de invocaciones de Bedrock enviando a un bucket S3 (para el paso 5).
1. Comprobar que el endpoint existe y acepta la clave
$ curl -sS -H "Authorization: Bearer $ABSK" https://bedrock-mantle.us-east-1.api.aws/v1/models | jq '.data | length'
39
El dominio resolvía al menos en us-east-1, us-east-2, us-west-2, eu-west-1, ap-northeast-1, ap-south-1 y sa-east-1, y el DNS inverso y el WHOIS confirmaban que pertenece a Amazon.
2. Verificar que la autenticación se aplica y que valen los dos tipos de clave
$ curl -sS -o /dev/null -w "%{http_code}\n" https://bedrock-mantle.us-east-1.api.aws/v1/models
401 # sin token
$ curl -sS -H "Authorization: Bearer ABSKBOGUS" -o /dev/null -w "%{http_code}\n" https://bedrock-mantle.us-east-1.api.aws/v1/models
401 # token falso
$ curl -sS -H "Authorization: Bearer $ABSK" -o /dev/null -w "%{http_code}\n" https://bedrock-mantle.us-east-1.api.aws/v1/models
200 # ABSK de larga duración
$ curl -sS -H "Authorization: Bearer $SHORT" -o /dev/null -w "%{http_code}\n" https://bedrock-mantle.us-east-1.api.aws/v1/models
200 # bedrock-api-key-* de corta duración
Con las dos claves, POST /v1/chat/completions devolvía inferencia facturable: por ejemplo, mistral.voxtral-mini-3b-2507 respondió con usage.total_tokens: 13 usando la clave ABSK y 7 usando la de corta duración. El único modelo listado que no se podía invocar era anthropic.claude-opus-4-7.
3. Aplicar el Deny recomendado y ver que mantle sigue respondiendo
$ aws iam put-user-policy --user-name [REDACTADO] --policy-name VDPDenyBedrockBearer \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Action":"bedrock:CallWithBearerToken","Resource":"*"}]}'
$ sleep 10
$ curl -sS -o /dev/null -w "bedrock std: %{http_code}\n" -H "Authorization: Bearer $ABSK" https://bedrock.us-east-1.amazonaws.com/foundation-models
bedrock std: 403
$ curl -sS -o /dev/null -w "mantle: %{http_code}\n" -H "Authorization: Bearer $ABSK" https://bedrock-mantle.us-east-1.api.aws/v1/models
mantle: 200
El plano estándar queda bloqueado, pero mantle no. Si en la política se cambia la acción por bedrock-mantle:CallWithBearerToken, mantle también devuelve 403: IAM funciona, el problema es que la acción recomendada no es la que usa este plano.
4. Revisar el evento en CloudTrail
Las llamadas a mantle sí generan un evento de datos (eventSource: bedrock-mantle.amazonaws.com, eventName: CreateInference), visible en trails con AWS::BedrockMantle::Project en los selectores avanzados. Pero la marca de uso de token bearer aparece en otra ruta:
- additionalEventData.callWithBearerToken: true (lo que busca la regla publicada por AWS)
+ requestParameters.callWithBearerToken: true (lo que trae el evento de mantle)
El campo additionalEventData no existe en estos eventos, así que una regla de SIEM construida con el ejemplo de AWS no detecta ninguno.
5. Comparar el registro de invocaciones
Con el registro de invocaciones activo hacia un bucket S3, el investigador lanzó casi a la vez (a las 22:41:35Z del 27 de abril de 2026) una llamada InvokeModel por bedrock-runtime y una CreateInference por mantle, ambas con el mismo marcador de texto vdp-paired-test-1777329695. Un minuto después llegó el fichero de logs:
22:42:36Z AWSLogs/.../BedrockModelInvocationLogs/.../22/<file>.json.gz delivered
inputBodyJson.messages[0].content == "vdp-paired-test-1777329695 reply OK" # bedrock prompt
grep across every file delivered for the day for the same marker # mantle: 0 hits
Resultado del día: un prompt registrado del plano estándar y ninguno de mantle. Además, no había forma de activarlo: el subcomando aws bedrock-mantle no existía en la CLI (comprobado con aws bedrock-mantle help).
El investigador repitió las pruebas el 27 y el 28 de abril de 2026 con varios usuarios IAM sucesivos, también tras rotar la clave, y adjuntó un script (reproduce.sh) que automatiza los pasos.
Impacto
Si una API key de Bedrock se filtraba, quien la tuviera podía usarla contra mantle aunque la víctima hubiera seguido al pie de la letra las recomendaciones de AWS:
- Prevención inútil: el Deny de
bedrock:CallWithBearerTokenno bloqueaba nada en mantle. - Sin detección: las reglas de SIEM, EventBridge o Athena basadas en el ejemplo oficial no veían ninguna llamada a mantle.
- Sin análisis forense: no quedaba constancia de qué prompts había enviado el atacante ni qué habían respondido los modelos, y el cliente no podía activar ese registro por su cuenta.
- Coste: 38 de 39 modelos eran facturables, incluidos algunos caros como
mistral.mistral-large-3-675b-instruct,qwen.qwen3-coder-480b-a35b-instruct,openai.gpt-oss-120b,moonshotai.kimi-k2-thinkingodeepseek.v3.2. Funcionaban el streaming y las llamadas a herramientas, así que una clave filtrada servía para flujos agénticos completos, y al poder usar los dos planos a la vez se duplicaba el volumen alcanzable antes de llegar a los límites por modelo.
Remediación
El reporte figura como resuelto, pero el texto no detalla qué cambió AWS. El investigador propuso, por orden de prioridad:
- Que el registro de invocaciones (o una API equivalente) capture también los prompts y respuestas de mantle.
- Emitir
additionalEventData.callWithBearerToken = truetambién en los eventos de mantle, o publicar reglas de ejemplo que cubran las dos rutas JSON y los dos orígenes (aws.bedrockyaws.bedrock-mantle). - Actualizar los ejemplos de SCP para denegar tanto
bedrock:CallWithBearerTokencomobedrock-mantle:CallWithBearerToken. - Documentar el endpoint
bedrock-mantle.{region}.api.awsy su prefijo de accionesbedrock-mantle:*en las guías de Bedrock, de sus API keys, de CloudTrail y del registro de invocaciones.
La divulgación fue coordinada: el investigador indicó que la investigación forma parte de una guía sobre API keys de Bedrock que se publicaría en el blog de BeyondTrust Phantom Labs y en Black Hat Arsenal USA 2026, y que su herramienta abierta bks (repositorio BeyondTrust/bedrock-keys-security) había retirado la mención a mantle hasta que AWS lo corrigiera. El reporte se envió el 28 de abril de 2026 y se divulgó el 14 de julio de 2026.
Qué aprender de este caso
- Cuando una credencial de un servicio cloud se puede usar como bearer, revisa qué acciones IAM concede realmente la política gestionada que lleva asociada (aquí
AmazonBedrockLimitedAccessincluíabedrock-mantle:*): cada prefijo de acción distinto es un posible plano que los controles documentados no cubren. - Los Deny en SCP que nombran una acción concreta solo protegen ese prefijo de servicio. Al denegar el uso de tokens, enumera todos los prefijos que la credencial puede invocar y revisa la lista cuando cambie la versión de la política gestionada.
- Las reglas de detección que buscan un campo en una ruta JSON fija (
additionalEventData.*) fallan en silencio si otro servicio lo pone en otra ruta. Pruébalas generando el evento real desde cada endpoint que acepte la credencial, no solo desde el documentado. - Un marcador único enviado a la vez por dos caminos y buscado después en los logs, como hizo el investigador, es una forma sencilla de comprobar si un registro de auditoría cubre de verdad todos los puntos de entrada.