GCP Vertex AI Prompt or Response Containing Credentials

Detects a GCP Vertex AI GenerateContent exchange whose prompt or model reply contains a known credential pattern (AWS access keys, GitHub tokens, PEM private keys, and similar), or whose assistant reply warns about exposed keys and revocation. Secrets in prompt/response logs are visible to anyone with access to BigQuery prompt-response export and Elastic.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/10/02"
  3integration = ["gcp_vertexai"]
  4maturity = "production"
  5min_stack_comments = "gcp_vertexai prompt_response_logs requires integration 1.4.0+ (Kibana ^9.2.0)."
  6min_stack_version = "9.3.0"
  7updated_date = "2026/10/02"
  8
  9[rule]
 10author = ["Elastic"]
 11description = """
 12Detects a GCP Vertex AI GenerateContent exchange whose prompt or model reply contains a known credential pattern (AWS
 13access keys, GitHub tokens, PEM private keys, and similar), or whose assistant reply warns about exposed keys and
 14revocation. Secrets in prompt/response logs are visible to anyone with access to BigQuery prompt-response export and
 15Elastic.
 16"""
 17false_positives = [
 18    """
 19    Documentation and unit tests that paste example keys (for example an AWS access key ending in EXAMPLE) match the
 20    token patterns. Confirm the value is live before rotating it.
 21    """,
 22]
 23from = "now-60m"
 24interval = "10m"
 25language = "esql"
 26license = "Elastic License v2"
 27name = "GCP Vertex AI Prompt or Response Containing Credentials"
 28note = """## Triage and analysis
 29
 30### Investigating GCP Vertex AI Prompt or Response Containing Credentials
 31
 32A Vertex AI prompt-response log row matched a credential pattern in the user prompt and/or model
 33reply (AWS access keys, GitHub tokens, PEM private keys, Slack tokens, Stripe live keys, Google API
 34keys, or GitLab PATs). There is no provider-side credential flag — the match is content-only.
 35Secrets in these logs are visible to anyone with access to the BigQuery export and Elastic.
 36
 37#### Possible investigation steps
 38
 39- Read `gcp.vertexai.prompt_response_logs.full_request.contents.parts.text` and
 40  `...full_response.candidates.content.parts.text` on the alert. Decide whether the match is a live
 41  secret or an example/placeholder (for example an AWS key ending in `EXAMPLE`).
 42- Note `gcp.vertexai.prompt_response_logs.model`, `api_method`, and `@timestamp`.
 43- Correlate with `logs-gcp_vertexai.auditlogs-*` GenerateContent events in the same window for
 44  `source.ip` and `client.user.email` to identify the calling principal and application egress.
 45- If the secret appears in the model reply, treat it as completion exposure as well as prompt
 46  exposure; review whether the prompt asked the model to recall or transform secrets.
 47- Scope impact: which system the credential belongs to and what privileges it has.
 48
 49### False positive analysis
 50
 51- Documentation, unit tests, and tutorials that paste example keys match the same prefixes. Confirm
 52  the value is live before rotating or paging.
 53
 54### Response and remediation
 55
 56- If the credential is live: rotate or revoke it immediately and hunt for use of that secret outside
 57  Vertex (CloudTrail, GitHub audit, IdP, etc.).
 58- Find and fix the application path that placed the secret in the prompt; add input/output filtering
 59  (Model Armor / sensitive-data policies) so secrets are not logged again.
 60"""
 61references = [
 62    "https://www.elastic.co/docs/reference/integrations/gcp_vertexai",
 63    "https://github.com/elastic/integrations/issues/20740",
 64    "https://genai.owasp.org/llmrisk/llm06-sensitive-information-disclosure",
 65]
 66risk_score = 73
 67rule_id = "4a1683ef-7f20-4c2a-bfa6-6eb7c3dc03d3"
 68setup = """## Setup
 69
 70Requires the GCP Vertex AI integration collecting `prompt_response_logs` from BigQuery request/response logging.
 71
 72https://www.elastic.co/docs/reference/integrations/gcp_vertexai
 73"""
 74severity = "high"
 75tags = [
 76    "Domain: GenAI",
 77    "Domain: Cloud",
 78    "Data Source: GCP Vertex AI",
 79    "Data Source: GCP",
 80    "Data Source: Google Cloud Platform",
 81    "Platform: GCP",
 82    "Service: GCP Vertex AI",
 83    "Use Case: Threat Detection",
 84    "Tactic: Credential Access",
 85    "Threat: LLMjacking",
 86    "Threat: Unauthorized AI Usage",
 87    "Mitre Atlas: AML.T0055",
 88    "Mitre Atlas: AML.T0057",
 89    "Resources: Investigation Guide",
 90    "Rule Type: ES|QL",
 91]
 92timestamp_override = "event.ingested"
 93type = "esql"
 94
 95query = '''
 96from logs-gcp_vertexai.prompt_response_logs-* metadata _id, _version, _index
 97| where data_stream.dataset == "gcp_vertexai.prompt_response_logs"
 98| eval request_text = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_request.contents.parts.text, " "), ""),
 99       response_raw = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text, " "), ""),
100       response_text = to_lower(response_raw)
101| where
102    request_text rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
103    response_raw rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
104    request_text rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
105    response_raw rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
106    request_text rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
107    response_raw rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
108    request_text rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
109    response_raw rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
110    request_text rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
111    response_raw rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
112    request_text rlike """.*sk_live_[A-Za-z0-9]+.*""" or
113    response_raw rlike """.*sk_live_[A-Za-z0-9]+.*""" or
114    request_text rlike """.*AIza[-A-Za-z0-9_]+.*""" or
115    response_raw rlike """.*AIza[-A-Za-z0-9_]+.*""" or
116    request_text rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
117    response_raw rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
118    response_text like "*serious security concern*" or
119    response_text like "*exposing api keys*" or
120    response_text like "*revoke/delete the api key*"
121| keep
122    _id,
123    _version,
124    _index,
125    @timestamp,
126    cloud.project.id,
127    gcp.vertexai.prompt_response_logs.model,
128    gcp.vertexai.prompt_response_logs.api_method,
129    gcp.vertexai.prompt_response_logs.full_request.contents.parts.text,
130    gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text,
131    gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason,
132    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count,
133    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count
134'''
135
136
137[[rule.threat]]
138framework = "MITRE ATT&CK"
139[[rule.threat.technique]]
140id = "T1552"
141name = "Unsecured Credentials"
142reference = "https://attack.mitre.org/techniques/T1552/"
143
144
145[rule.threat.tactic]
146id = "TA0006"
147name = "Credential Access"
148reference = "https://attack.mitre.org/tactics/TA0006/"
149[[rule.threat_mappings]]
150framework = "MITRE ATLAS"
151version = "2026.08"
152[[rule.threat_mappings.threat]]
153framework = "MITRE ATLAS"
154[[rule.threat_mappings.threat.technique]]
155id = "AML.T0057"
156name = "LLM Data Leakage"
157reference = "https://atlas.mitre.org/techniques/AML.T0057/"
158
159
160[rule.threat_mappings.threat.tactic]
161id = "AML.TA0010"
162name = "Exfiltration"
163reference = "https://atlas.mitre.org/tactics/AML.TA0010/"
164[[rule.threat_mappings.threat]]
165framework = "MITRE ATLAS"
166[[rule.threat_mappings.threat.technique]]
167id = "AML.T0055"
168name = "Unsecured Credentials"
169reference = "https://atlas.mitre.org/techniques/AML.T0055/"
170
171
172[rule.threat_mappings.threat.tactic]
173id = "AML.TA0013"
174name = "Credential Access"
175reference = "https://atlas.mitre.org/tactics/AML.TA0013/"
176
177[rule.investigation_fields]
178field_names = [
179    "cloud.project.id",
180    "gcp.vertexai.prompt_response_logs.model",
181    "gcp.vertexai.prompt_response_logs.api_method",
182    "gcp.vertexai.prompt_response_logs.full_request.contents.parts.text",
183    "gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text",
184    "gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason",
185    "gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count",
186    "gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count",
187]

Triage and analysis

Investigating GCP Vertex AI Prompt or Response Containing Credentials

A Vertex AI prompt-response log row matched a credential pattern in the user prompt and/or model reply (AWS access keys, GitHub tokens, PEM private keys, Slack tokens, Stripe live keys, Google API keys, or GitLab PATs). There is no provider-side credential flag — the match is content-only. Secrets in these logs are visible to anyone with access to the BigQuery export and Elastic.

Possible investigation steps

  • Read gcp.vertexai.prompt_response_logs.full_request.contents.parts.text and ...full_response.candidates.content.parts.text on the alert. Decide whether the match is a live secret or an example/placeholder (for example an AWS key ending in EXAMPLE).
  • Note gcp.vertexai.prompt_response_logs.model, api_method, and @timestamp.
  • Correlate with logs-gcp_vertexai.auditlogs-* GenerateContent events in the same window for source.ip and client.user.email to identify the calling principal and application egress.
  • If the secret appears in the model reply, treat it as completion exposure as well as prompt exposure; review whether the prompt asked the model to recall or transform secrets.
  • Scope impact: which system the credential belongs to and what privileges it has.

False positive analysis

  • Documentation, unit tests, and tutorials that paste example keys match the same prefixes. Confirm the value is live before rotating or paging.

Response and remediation

  • If the credential is live: rotate or revoke it immediately and hunt for use of that secret outside Vertex (CloudTrail, GitHub audit, IdP, etc.).
  • Find and fix the application path that placed the secret in the prompt; add input/output filtering (Model Armor / sensitive-data policies) so secrets are not logged again.

References

Related rules

to-top