← Back to Explore
elasticmediumTTP
GCP Vertex AI High GenerateContent Volume From Single IP
Detects a single source IP making a high number of Vertex AI GenerateContent (or StreamGenerateContent) audit calls against the same model resource in the lookback window. That pattern fits model extraction, automated scraping, or a compromised caller burning prediction quota.
Detection Query
from logs-gcp_vertexai.auditlogs-*
| where
data_stream.dataset == "gcp_vertexai.auditlogs" and
source.ip is not null and
(
event.action like "*PredictionService.GenerateContent*" or
event.action like "*PredictionService.StreamGenerateContent*"
) and
(gcp.vertexai.audit.status.code is null or gcp.vertexai.audit.status.code == 0)
| stats
Esql.event_count = count(*),
Esql.timestamp_first_seen = min(@timestamp),
Esql.timestamp_last_seen = max(@timestamp),
Esql.event_action_values = values(event.action)
by
source.ip,
gcp.vertexai.audit.resource_name,
cloud.project.id
| where Esql.event_count >= 100
| keep
source.ip,
gcp.vertexai.audit.resource_name,
cloud.project.id,
Esql.event_count,
Esql.timestamp_first_seen,
Esql.timestamp_last_seen,
Esql.event_action_values
Author
Elastic
Created
2026/10/02
Data Sources
GCP Vertex AIGCPGoogle Cloud Platform
References
Tags
Domain: GenAIDomain: CloudData Source: GCP Vertex AIData Source: GCPData Source: Google Cloud PlatformPlatform: GCPService: GCP Vertex AIUse Case: Model TheftUse Case: Threat DetectionTactic: CollectionThreat: LLMjackingThreat: Unauthorized AI UsageMitre Atlas: AML.T0024Mitre Atlas: AML.T0024.002Mitre Atlas: AML.T0029Resources: Investigation GuideRule Type: ES|QL
Raw Content
[metadata]
creation_date = "2026/10/02"
integration = ["gcp_vertexai"]
maturity = "production"
updated_date = "2026/10/02"
[rule]
author = ["Elastic"]
description = """
Detects a single source IP making a high number of Vertex AI GenerateContent (or StreamGenerateContent) audit calls
against the same model resource in the lookback window. That pattern fits model extraction, automated scraping, or a
compromised caller burning prediction quota.
"""
false_positives = [
"""
Approved batch evaluation clients or shared NAT egress. Raise the threshold or exclude known source IP prefixes.
""",
]
from = "now-60m"
interval = "10m"
language = "esql"
license = "Elastic License v2"
name = "GCP Vertex AI High GenerateContent Volume From Single IP"
note = """## Triage and analysis
### Investigating GCP Vertex AI High GenerateContent Volume From Single IP
A single `source.ip` issued an unusually high number of Vertex AI `GenerateContent` /
`StreamGenerateContent` audit calls against one model resource
(`gcp.vertexai.audit.resource_name`) in the lookback window. That pattern is consistent with
model extraction, automated scraping, or a compromised caller burning prediction quota.
#### Possible investigation steps
- Note `source.ip`, `gcp.vertexai.audit.resource_name`, `cloud.project.id`, and `Esql.event_count`
on the alert. Compare the count to the project's normal peak for that model.
- Confirm whether the IP is known egress for an approved app, CI runner, or shared NAT. Check
`Esql.event_action_values` for StreamGenerateContent vs GenerateContent mix.
- Pivot to `logs-gcp_vertexai.prompt_response_logs-*` for the same time window and model: sample
prompts, token volume, and whether content looks like systematic extraction (repetitive probes,
large context dumps).
- Pivot auditlogs for the same IP: other aiplatform methods, new service accounts, or
`SetPublisherModelConfig` changes that could hide or redirect logging.
- Identify `client.user.email` on matching GenerateContent audit events to map IP → principal.
### False positive analysis
- Shared corporate NAT or proxy egress aggregating many legitimate users onto one IP.
- Approved batch evaluation, load tests, or data-migration jobs. Validate with change tickets and
expected schedules before escalating.
### Response and remediation
- If unauthorized: revoke or rotate credentials for the calling principal, restrict the IP via VPC
Service Controls / firewall, and apply per-IP or per-principal quotas.
- Review billing and quota usage for the model; hunt for similar volume from other IPs in the same
project.
"""
references = [
"https://www.elastic.co/docs/reference/integrations/gcp_vertexai",
"https://genai.owasp.org/llmrisk/llm10-model-theft",
]
risk_score = 47
rule_id = "a9f28b66-a69e-4d5b-be8d-94e5eda6c736"
setup = """## Setup
Requires GCP Vertex AI `auditlogs` for `aiplatform.googleapis.com`. Raise `Esql.event_count` above your normal peak
before broad enablement.
"""
severity = "medium"
tags = [
"Domain: GenAI",
"Domain: Cloud",
"Data Source: GCP Vertex AI",
"Data Source: GCP",
"Data Source: Google Cloud Platform",
"Platform: GCP",
"Service: GCP Vertex AI",
"Use Case: Model Theft",
"Use Case: Threat Detection",
"Tactic: Collection",
"Threat: LLMjacking",
"Threat: Unauthorized AI Usage",
"Mitre Atlas: AML.T0024",
"Mitre Atlas: AML.T0024.002",
"Mitre Atlas: AML.T0029",
"Resources: Investigation Guide",
"Rule Type: ES|QL",
]
timestamp_override = "event.ingested"
type = "esql"
query = '''
from logs-gcp_vertexai.auditlogs-*
| where
data_stream.dataset == "gcp_vertexai.auditlogs" and
source.ip is not null and
(
event.action like "*PredictionService.GenerateContent*" or
event.action like "*PredictionService.StreamGenerateContent*"
) and
(gcp.vertexai.audit.status.code is null or gcp.vertexai.audit.status.code == 0)
| stats
Esql.event_count = count(*),
Esql.timestamp_first_seen = min(@timestamp),
Esql.timestamp_last_seen = max(@timestamp),
Esql.event_action_values = values(event.action)
by
source.ip,
gcp.vertexai.audit.resource_name,
cloud.project.id
| where Esql.event_count >= 100
| keep
source.ip,
gcp.vertexai.audit.resource_name,
cloud.project.id,
Esql.event_count,
Esql.timestamp_first_seen,
Esql.timestamp_last_seen,
Esql.event_action_values
'''
[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1530"
name = "Data from Cloud Storage"
reference = "https://attack.mitre.org/techniques/T1530/"
[rule.threat.tactic]
id = "TA0009"
name = "Collection"
reference = "https://attack.mitre.org/tactics/TA0009/"
[[rule.threat_mappings]]
framework = "MITRE ATLAS"
version = "2026.08"
[[rule.threat_mappings.threat]]
framework = "MITRE ATLAS"
[[rule.threat_mappings.threat.technique]]
id = "AML.T0029"
name = "Denial of AI Service"
reference = "https://atlas.mitre.org/techniques/AML.T0029/"
[rule.threat_mappings.threat.tactic]
id = "AML.TA0011"
name = "Impact"
reference = "https://atlas.mitre.org/tactics/AML.TA0011/"
[[rule.threat_mappings.threat]]
framework = "MITRE ATLAS"
[[rule.threat_mappings.threat.technique]]
id = "AML.T0024"
name = "Exfiltration via AI Inference API"
reference = "https://atlas.mitre.org/techniques/AML.T0024/"
[[rule.threat_mappings.threat.technique.subtechnique]]
id = "AML.T0024.002"
name = "Extract AI Model"
reference = "https://atlas.mitre.org/techniques/AML.T0024.002/"
[rule.threat_mappings.threat.tactic]
id = "AML.TA0010"
name = "Exfiltration"
reference = "https://atlas.mitre.org/tactics/AML.TA0010/"
[rule.alert_suppression]
group_by = ["source.ip", "gcp.vertexai.audit.resource_name", "cloud.project.id"]
missing_fields_strategy = "suppress"
[rule.investigation_fields]
field_names = [
"source.ip",
"gcp.vertexai.audit.resource_name",
"cloud.project.id",
"Esql.event_count",
"Esql.event_action_values",
"Esql.timestamp_first_seen",
"Esql.timestamp_last_seen",
]
[rule.alert_suppression.duration]
unit = "h"
value = 1