AWS Bedrock Model Invocation From High Number of Countries
Detects a single AWS principal invoking Amazon Bedrock models from three or more countries and three or more source IPs within the lookback window. LLMjacking operators often distribute stolen AWS credentials across proxies or resell them to multiple buyers, which produces inference traffic for one identity from many unrelated locations.
Elastic rule (View on GitHub)
1[metadata]
2creation_date = "2026/10/23"
3integration = ["aws"]
4maturity = "production"
5updated_date = "2026/10/23"
6
7[rule]
8author = ["Elastic"]
9description = """
10Detects a single AWS principal invoking Amazon Bedrock models from three or more countries and three or more source IPs
11within the lookback window. LLMjacking operators often distribute stolen AWS credentials across proxies or resell them
12to multiple buyers, which produces inference traffic for one identity from many unrelated locations.
13"""
14false_positives = [
15 """
16 Globally distributed applications or CI runners that call Bedrock with one shared IAM user or role. Prefer
17 per-region identities, or raise the country threshold for these principals.
18 """,
19 """
20 Users on VPNs or privacy relays that rotate exit countries. Corroborate with ASN and user agent before acting.
21 """,
22]
23from = "now-4h"
24interval = "15m"
25language = "esql"
26license = "Elastic License v2"
27name = "AWS Bedrock Model Invocation From High Number of Countries"
28note = """## Triage and analysis
29
30### Investigating AWS Bedrock Model Invocation From High Number of Countries
31
32One AWS principal (role issuer ARN when present, otherwise `aws.cloudtrail.user_identity.arn`) invoked Amazon Bedrock
33models from at least three countries and three source IPs inside the lookback window. Assumed-role sessions are grouped
34by the issuing role so re-assumes of the same role still correlate. This pattern fits credentials that have been shared,
35resold, or proxied for LLMjacking.
36
37#### Possible investigation steps
38
39- Review `Esql.source_geo_country_name_values`, `Esql.source_ip_values`, and
40 `Esql.source_as_organization_name_values`. Residential proxies and hosting ASNs across several countries are more
41 suspicious than one corporate VPN provider.
42- Check `Esql.aws_cloudtrail_user_identity_access_key_id_values` and `Esql.aws_cloudtrail_user_identity_type_values`.
43 A single long-term `AKIA` key seen in many countries is a strong indicator of credential theft.
44- Compare `Esql.user_agent_original_values`. Several distinct clients for one identity often means several operators.
45- Search CloudTrail for the principal's other activity in the window, especially model access changes, guardrail or
46 logging changes, and IAM changes.
47- Review Bedrock cost and usage for the account over the same period.
48
49### False positive analysis
50
51- Shared identities for global workloads. Move these to region-scoped roles or add an exception for the principal.
52- VPN and privacy relay users. Confirm with the account owner before rotating credentials.
53
54### Response and remediation
55
56- If the activity is not explained, deactivate the access key or revoke the role session, rotate credentials, and
57 restrict `bedrock:InvokeModel*` permissions.
58- Set AWS Budgets or service quotas to limit the cost of further abuse.
59"""
60references = [
61 "https://docs.aws.amazon.com/bedrock/latest/userguide/logging-using-cloudtrail.html",
62 "https://www.elastic.co/docs/reference/integrations/aws/cloudtrail",
63]
64risk_score = 99
65rule_id = "a81fdc25-58a0-4306-a73d-850e9f7fe9eb"
66setup = """## Setup
67
68This rule requires AWS CloudTrail management events ingested via the AWS integration (`aws.cloudtrail` data stream)
69with `source.geo.country_name` populated by the integration's GeoIP enrichment. Bedrock runtime operations are logged
70as management events by default; no Bedrock model invocation logging is required.
71"""
72severity = "critical"
73tags = [
74 "Domain: Cloud",
75 "Domain: GenAI",
76 "Data Source: AWS",
77 "Data Source: Amazon Web Services",
78 "Data Source: AWS CloudTrail",
79 "Platform: AWS",
80 "Service: AWS Bedrock",
81 "Use Case: Threat Detection",
82 "Tactic: Credential Access",
83 "Tactic: Initial Access",
84 "Threat: Impossible Travel",
85 "Threat: LLMjacking",
86 "Threat: Unauthorized AI Usage",
87 "Mitre Atlas: AML.T0012",
88 "Mitre Atlas: AML.T0091",
89 "Mitre Atlas: AML.T0091.000",
90 "Resources: Investigation Guide",
91 "Rule Type: ES|QL",
92]
93timestamp_override = "event.ingested"
94type = "esql"
95
96query = '''
97from logs-aws.cloudtrail-*
98| where
99 data_stream.dataset == "aws.cloudtrail" and
100 event.provider == "bedrock.amazonaws.com" and
101 event.action in ("InvokeModel", "InvokeModelWithResponseStream", "Converse", "ConverseStream") and
102 event.outcome == "success" and
103 aws.cloudtrail.user_identity.arn is not null and
104 source.ip is not null and
105 source.geo.country_name is not null
106| eval
107 Esql.identity = coalesce(
108 aws.cloudtrail.user_identity.session_context.session_issuer.arn,
109 aws.cloudtrail.user_identity.arn
110 )
111| stats
112 Esql.country_count = count_distinct(source.geo.country_name),
113 Esql.source_ip_count = count_distinct(source.ip),
114 Esql.user_agent_count = count_distinct(user_agent.original),
115 Esql.event_count = count(*),
116 Esql.event_action_values = values(event.action),
117 Esql.source_ip_values = values(source.ip),
118 Esql.source_geo_country_name_values = values(source.geo.country_name),
119 Esql.source_geo_city_name_values = values(source.geo.city_name),
120 Esql.source_as_organization_name_values = values(source.as.organization.name),
121 Esql.user_agent_original_values = values(user_agent.original),
122 Esql.aws_cloudtrail_user_identity_arn_values = values(aws.cloudtrail.user_identity.arn),
123 Esql.aws_cloudtrail_user_identity_type_values = values(aws.cloudtrail.user_identity.type),
124 Esql.aws_cloudtrail_user_identity_access_key_id_values = values(aws.cloudtrail.user_identity.access_key_id),
125 Esql.cloud_region_values = values(cloud.region),
126 Esql.timestamp_first_seen = min(@timestamp),
127 Esql.timestamp_last_seen = max(@timestamp)
128 by
129 Esql.identity,
130 cloud.account.id
131| where Esql.country_count >= 3 and Esql.source_ip_count >= 3
132| eval source.ip = mv_first(Esql.source_ip_values)
133| keep
134 Esql.identity,
135 cloud.account.id,
136 source.ip,
137 Esql.country_count,
138 Esql.source_ip_count,
139 Esql.user_agent_count,
140 Esql.event_count,
141 Esql.event_action_values,
142 Esql.source_ip_values,
143 Esql.source_geo_country_name_values,
144 Esql.source_geo_city_name_values,
145 Esql.source_as_organization_name_values,
146 Esql.user_agent_original_values,
147 Esql.aws_cloudtrail_user_identity_arn_values,
148 Esql.aws_cloudtrail_user_identity_type_values,
149 Esql.aws_cloudtrail_user_identity_access_key_id_values,
150 Esql.cloud_region_values,
151 Esql.timestamp_first_seen,
152 Esql.timestamp_last_seen
153'''
154
155
156[[rule.threat]]
157framework = "MITRE ATT&CK"
158[[rule.threat.technique]]
159id = "T1528"
160name = "Steal Application Access Token"
161reference = "https://attack.mitre.org/techniques/T1528/"
162
163
164[rule.threat.tactic]
165id = "TA0006"
166name = "Credential Access"
167reference = "https://attack.mitre.org/tactics/TA0006/"
168[[rule.threat]]
169framework = "MITRE ATT&CK"
170[[rule.threat.technique]]
171id = "T1078"
172name = "Valid Accounts"
173reference = "https://attack.mitre.org/techniques/T1078/"
174[[rule.threat.technique.subtechnique]]
175id = "T1078.004"
176name = "Cloud Accounts"
177reference = "https://attack.mitre.org/techniques/T1078/004/"
178
179
180
181[rule.threat.tactic]
182id = "TA0001"
183name = "Initial Access"
184reference = "https://attack.mitre.org/tactics/TA0001/"
185[[rule.threat_mappings]]
186framework = "MITRE ATLAS"
187version = "2026.09"
188[[rule.threat_mappings.threat]]
189framework = "MITRE ATLAS"
190[[rule.threat_mappings.threat.technique]]
191id = "AML.T0012"
192name = "Valid Accounts"
193reference = "https://atlas.mitre.org/techniques/AML.T0012/"
194
195
196[rule.threat_mappings.threat.tactic]
197id = "AML.TA0004"
198name = "Initial Access"
199reference = "https://atlas.mitre.org/tactics/AML.TA0004/"
200[[rule.threat_mappings.threat]]
201framework = "MITRE ATLAS"
202[[rule.threat_mappings.threat.technique]]
203id = "AML.T0091"
204name = "Use Alternate Authentication Material"
205reference = "https://atlas.mitre.org/techniques/AML.T0091/"
206[[rule.threat_mappings.threat.technique.subtechnique]]
207id = "AML.T0091.000"
208name = "Application Access Token"
209reference = "https://atlas.mitre.org/techniques/AML.T0091.000/"
210
211
212
213[rule.threat_mappings.threat.tactic]
214id = "AML.TA0015"
215name = "Lateral Movement"
216reference = "https://atlas.mitre.org/tactics/AML.TA0015/"
217
218[rule.alert_suppression]
219group_by = ["Esql.identity"]
220missing_fields_strategy = "suppress"
221
222[rule.investigation_fields]
223field_names = [
224 "Esql.identity",
225 "cloud.account.id",
226 "source.ip",
227 "Esql.country_count",
228 "Esql.source_ip_count",
229 "Esql.user_agent_count",
230 "Esql.event_count",
231 "Esql.source_geo_country_name_values",
232 "Esql.source_ip_values",
233 "Esql.source_as_organization_name_values",
234 "Esql.user_agent_original_values",
235 "Esql.aws_cloudtrail_user_identity_arn_values",
236 "Esql.aws_cloudtrail_user_identity_access_key_id_values",
237]
238
239[rule.alert_suppression.duration]
240unit = "h"
241value = 4
Triage and analysis
Investigating AWS Bedrock Model Invocation From High Number of Countries
One AWS principal (role issuer ARN when present, otherwise aws.cloudtrail.user_identity.arn) invoked Amazon Bedrock
models from at least three countries and three source IPs inside the lookback window. Assumed-role sessions are grouped
by the issuing role so re-assumes of the same role still correlate. This pattern fits credentials that have been shared,
resold, or proxied for LLMjacking.
Possible investigation steps
- Review
Esql.source_geo_country_name_values,Esql.source_ip_values, andEsql.source_as_organization_name_values. Residential proxies and hosting ASNs across several countries are more suspicious than one corporate VPN provider. - Check
Esql.aws_cloudtrail_user_identity_access_key_id_valuesandEsql.aws_cloudtrail_user_identity_type_values. A single long-termAKIAkey seen in many countries is a strong indicator of credential theft. - Compare
Esql.user_agent_original_values. Several distinct clients for one identity often means several operators. - Search CloudTrail for the principal's other activity in the window, especially model access changes, guardrail or logging changes, and IAM changes.
- Review Bedrock cost and usage for the account over the same period.
False positive analysis
- Shared identities for global workloads. Move these to region-scoped roles or add an exception for the principal.
- VPN and privacy relay users. Confirm with the account owner before rotating credentials.
Response and remediation
- If the activity is not explained, deactivate the access key or revoke the role session, rotate credentials, and
restrict
bedrock:InvokeModel*permissions. - Set AWS Budgets or service quotas to limit the cost of further abuse.
References
Related rules
- AWS Bedrock Model Invocation Impossible Travel
- GCP Vertex AI Caller Activity From High Number of Countries
- GCP Vertex AI Caller Impossible Travel
- AWS Bedrock AgentCore Execution Role Used Outside Its Runtime
- AWS Bedrock Unauthorized Foundation Model Access Attempt