GCP Vertex AI Prompt or Response Containing Credentials


Description

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.

Query · esql

from logs-gcp_vertexai.prompt_response_logs-* metadata _id, _version, _index
| where data_stream.dataset == "gcp_vertexai.prompt_response_logs"
| eval request_text = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_request.contents.parts.text, " "), ""),
       response_raw = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text, " "), ""),
       response_text = to_lower(response_raw)
| where
    request_text rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
    response_raw rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
    request_text rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
    response_raw rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
    request_text rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
    response_raw rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
    request_text rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
    response_raw rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
    request_text rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
    response_raw rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
    request_text rlike """.*sk_live_[A-Za-z0-9]+.*""" or
    response_raw rlike """.*sk_live_[A-Za-z0-9]+.*""" or
    request_text rlike """.*AIza[-A-Za-z0-9_]+.*""" or
    response_raw rlike """.*AIza[-A-Za-z0-9_]+.*""" or
    request_text rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
    response_raw rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
    response_text like "*serious security concern*" or
    response_text like "*exposing api keys*" or
    response_text like "*revoke/delete the api key*"
| keep
    _id,
    _version,
    _index,
    @timestamp,
    cloud.project.id,
    gcp.vertexai.prompt_response_logs.model,
    gcp.vertexai.prompt_response_logs.api_method,
    gcp.vertexai.prompt_response_logs.full_request.contents.parts.text,
    gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text,
    gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason,
    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count,
    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count

Investigation fields

Pivot points the source recommends for triage.

  • cloud.project.id
  • gcp.vertexai.prompt_response_logs.model
  • gcp.vertexai.prompt_response_logs.api_method
  • gcp.vertexai.prompt_response_logs.full_request.contents.parts.text
  • gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text
  • gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason
  • gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count
  • gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count

Implementation guide

Requires the GCP Vertex AI integration collecting prompt_response_logs from BigQuery request/response logging.

https://www.elastic.co/docs/reference/integrations/gcp_vertexai

Known false positives

  • Documentation and unit tests that paste example keys (for example an AWS access key ending in EXAMPLE) match the token patterns. Confirm the value is live before rotating it.

Analyst notes

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.
Raw source GCP Vertex AI Prompt or Response Containing Credentials · Elastic TOML
Esc
Published by elastic/detection-rules ↗, licensed under Elastic License 2.0 ↗. Reproduced here unmodified.
[metadata]
creation_date = "2026/10/02"
integration = ["gcp_vertexai"]
maturity = "production"
min_stack_comments = "gcp_vertexai prompt_response_logs requires integration 1.4.0+ (Kibana ^9.2.0)."
min_stack_version = "9.3.0"
updated_date = "2026/10/02"

[rule]
author = ["Elastic"]
description = """
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.
"""
false_positives = [
    """
    Documentation and unit tests that paste example keys (for example an AWS access key ending in EXAMPLE) match the
    token patterns. Confirm the value is live before rotating it.
    """,
]
from = "now-60m"
interval = "10m"
language = "esql"
license = "Elastic License v2"
name = "GCP Vertex AI Prompt or Response Containing Credentials"
note = """## 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 = [
    "https://www.elastic.co/docs/reference/integrations/gcp_vertexai",
    "https://github.com/elastic/integrations/issues/20740",
    "https://genai.owasp.org/llmrisk/llm06-sensitive-information-disclosure",
]
risk_score = 73
rule_id = "4a1683ef-7f20-4c2a-bfa6-6eb7c3dc03d3"
setup = """## Setup

Requires the GCP Vertex AI integration collecting `prompt_response_logs` from BigQuery request/response logging.

https://www.elastic.co/docs/reference/integrations/gcp_vertexai
"""
severity = "high"
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: Threat Detection",
    "Tactic: Credential Access",
    "Threat: LLMjacking",
    "Threat: Unauthorized AI Usage",
    "Mitre Atlas: AML.T0055",
    "Mitre Atlas: AML.T0057",
    "Resources: Investigation Guide",
    "Rule Type: ES|QL",
]
timestamp_override = "event.ingested"
type = "esql"

query = '''
from logs-gcp_vertexai.prompt_response_logs-* metadata _id, _version, _index
| where data_stream.dataset == "gcp_vertexai.prompt_response_logs"
| eval request_text = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_request.contents.parts.text, " "), ""),
       response_raw = coalesce(mv_concat(gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text, " "), ""),
       response_text = to_lower(response_raw)
| where
    request_text rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
    response_raw rlike """.*(AKIA|ASIA)[A-Z0-9]{16}.*""" or
    request_text rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
    response_raw rlike """.*gh[pousr]_[A-Za-z0-9]{36}.*""" or
    request_text rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
    response_raw rlike """.*github_pat_[A-Za-z0-9_]+.*""" or
    request_text rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
    response_raw rlike """.*-----BEGIN [A-Z ]*PRIVATE KEY-----.*""" or
    request_text rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
    response_raw rlike """.*xox[baprs]-[0-9]+-[0-9]+-[A-Za-z0-9]+.*""" or
    request_text rlike """.*sk_live_[A-Za-z0-9]+.*""" or
    response_raw rlike """.*sk_live_[A-Za-z0-9]+.*""" or
    request_text rlike """.*AIza[-A-Za-z0-9_]+.*""" or
    response_raw rlike """.*AIza[-A-Za-z0-9_]+.*""" or
    request_text rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
    response_raw rlike """.*glpat-[-A-Za-z0-9_]+.*""" or
    response_text like "*serious security concern*" or
    response_text like "*exposing api keys*" or
    response_text like "*revoke/delete the api key*"
| keep
    _id,
    _version,
    _index,
    @timestamp,
    cloud.project.id,
    gcp.vertexai.prompt_response_logs.model,
    gcp.vertexai.prompt_response_logs.api_method,
    gcp.vertexai.prompt_response_logs.full_request.contents.parts.text,
    gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text,
    gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason,
    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count,
    gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count
'''


[[rule.threat]]
framework = "MITRE ATT&CK"
[[rule.threat.technique]]
id = "T1552"
name = "Unsecured Credentials"
reference = "https://attack.mitre.org/techniques/T1552/"


[rule.threat.tactic]
id = "TA0006"
name = "Credential Access"
reference = "https://attack.mitre.org/tactics/TA0006/"
[[rule.threat_mappings]]
framework = "MITRE ATLAS"
version = "2026.08"
[[rule.threat_mappings.threat]]
framework = "MITRE ATLAS"
[[rule.threat_mappings.threat.technique]]
id = "AML.T0057"
name = "LLM Data Leakage"
reference = "https://atlas.mitre.org/techniques/AML.T0057/"


[rule.threat_mappings.threat.tactic]
id = "AML.TA0010"
name = "Exfiltration"
reference = "https://atlas.mitre.org/tactics/AML.TA0010/"
[[rule.threat_mappings.threat]]
framework = "MITRE ATLAS"
[[rule.threat_mappings.threat.technique]]
id = "AML.T0055"
name = "Unsecured Credentials"
reference = "https://atlas.mitre.org/techniques/AML.T0055/"


[rule.threat_mappings.threat.tactic]
id = "AML.TA0013"
name = "Credential Access"
reference = "https://atlas.mitre.org/tactics/AML.TA0013/"

[rule.investigation_fields]
field_names = [
    "cloud.project.id",
    "gcp.vertexai.prompt_response_logs.model",
    "gcp.vertexai.prompt_response_logs.api_method",
    "gcp.vertexai.prompt_response_logs.full_request.contents.parts.text",
    "gcp.vertexai.prompt_response_logs.full_response.candidates.content.parts.text",
    "gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason",
    "gcp.vertexai.prompt_response_logs.full_response.usage_metadata.prompt_token_count",
    "gcp.vertexai.prompt_response_logs.full_response.usage_metadata.candidates_token_count",
]

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.