Techniques
Sample rules
AWS Bedrock High-Frequency Single-Model Inference API Probing
- source: elastic
- technicques:
Description
Identifies an AWS principal performing a high volume of Amazon Bedrock inference API calls against a single model within a short window. Membership inference attacks require hundreds to thousands of statistically similar queries whose prompts and responses are intentionally content-benign, making guardrail- and content-based rules ineffective. This rule detects the high-frequency single-model probing pattern that precedes membership inference and related exfiltration via the inference API. It is a behavioral / volumetric precursor: it does not observe model confidence scores and a fixed call-count threshold only catches the loud variant, so paced, low-and-slow, or credential-distributed probing will evade it. Definitive membership inference detection requires ML anomaly analysis over per-entity inference-rate and response-distribution baselines.
Detection logic
from logs-aws.cloudtrail-*
// Bedrock runtime inference APIs (CloudTrail management events, logged by default) used to probe at scale
| where
event.provider == "bedrock.amazonaws.com"
and event.action in (
"InvokeModel",
"Converse",
"ConverseStream",
"InvokeModelWithResponseStream"
)
and event.outcome == "success"
and aws.cloudtrail.user_identity.arn IS NOT NULL
and aws.cloudtrail.request_parameters IS NOT NULL
| grok aws.cloudtrail.request_parameters """modelId=(?<Esql.model_id>[^,}\]]+)"""
| where Esql.model_id IS NOT NULL
// preserve the grouping keys plus the ECS context fields collected via VALUES() below
| keep
aws.cloudtrail.user_identity.arn,
cloud.account.id,
Esql.model_id,
event.action,
source.ip,
user_agent.original,
aws.cloudtrail.user_identity.type,
aws.cloudtrail.user_identity.access_key_id,
cloud.region,
source.as.organization.name
// aggregate per principal + account + model, capturing analyst context with VALUES()
| stats
Esql.inference_call_count = count(*),
Esql.event_action_values = VALUES(event.action),
Esql.source_ip_values = VALUES(source.ip),
Esql.user_agent_original_values = VALUES(user_agent.original),
Esql.aws_cloudtrail_user_identity_type_values = VALUES(aws.cloudtrail.user_identity.type),
Esql.aws_cloudtrail_user_identity_access_key_id_values = VALUES(aws.cloudtrail.user_identity.access_key_id),
Esql.cloud_region_values = VALUES(cloud.region),
Esql.source_as_organization_name_values = VALUES(source.as.organization.name)
by
aws.cloudtrail.user_identity.arn,
cloud.account.id,
Esql.model_id
| where Esql.inference_call_count >= 500
| keep
aws.cloudtrail.user_identity.arn,
cloud.account.id,
Esql.model_id,
Esql.inference_call_count,
Esql.event_action_values,
Esql.source_ip_values,
Esql.user_agent_original_values,
Esql.aws_cloudtrail_user_identity_type_values,
Esql.aws_cloudtrail_user_identity_access_key_id_values,
Esql.cloud_region_values,
Esql.source_as_organization_name_values
| sort Esql.inference_call_count desc