GCP Vertex AI Elevated Safety Rating on Response

Detects Vertex AI prompt-response logs where a candidate safety_ratings.probability is HIGH or MEDIUM. Those values are stronger signals than NEGLIGIBLE or LOW alone. Requires the request to include safetySettings so ratings are logged.

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 Vertex AI prompt-response logs where a candidate safety_ratings.probability is HIGH or MEDIUM. Those values are
 13stronger signals than NEGLIGIBLE or LOW alone. Requires the request to include safetySettings so ratings are logged.
 14"""
 15false_positives = [
 16    """
 17    Borderline creative-writing or news-summarization prompts can occasionally score MEDIUM. Confirm category and prompt
 18    text before escalating.
 19    """,
 20]
 21from = "now-60m"
 22interval = "10m"
 23language = "esql"
 24license = "Elastic License v2"
 25name = "GCP Vertex AI Elevated Safety Rating on Response"
 26note = """## Triage and analysis
 27
 28### Investigating GCP Vertex AI Elevated Safety Rating on Response
 29
 30A GenerateContent response included `safety_ratings.probability` of HIGH or MEDIUM for one or more
 31Gemini harm categories (for example `HARM_CATEGORY_HATE_SPEECH` or
 32`HARM_CATEGORY_DANGEROUS_CONTENT`). That is a stronger signal than NEGLIGIBLE/LOW and often means
 33the prompt probed disallowed content — whether or not generation was fully blocked.
 34
 35#### Possible investigation steps
 36
 37- Read the prompt in `gcp.vertexai.prompt_response_logs.full_request.contents.parts.text`.
 38- Note `safety_ratings.category`, `probability`, and `severity` on the alert, plus
 39  `finish_reason`. `SAFETY` with HIGH/MEDIUM is high confidence; `STOP` with HIGH still warrants
 40  review of what was returned.
 41- Check `full_request.safety_settings.threshold` on the same event. `BLOCK_NONE` means category
 42  blocking was disabled for listed categories.
 43- Pivot to `logs-gcp_vertexai.auditlogs-*` GenerateContent for `source.ip` and `client.user.email`
 44  in the same window to identify the caller.
 45- Look for related alerts (jailbreak heuristics, repeated refusals, BLOCK_NONE) from the same
 46  project/model.
 47
 48### False positive analysis
 49
 50- Authorized red-team or content-moderation workloads that intentionally score MEDIUM/HIGH.
 51  Exclude those projects or principals.
 52- Borderline creative-writing or news-summarization prompts can occasionally score MEDIUM — read
 53  the prompt before escalating.
 54
 55### Response and remediation
 56
 57- If the prompt is malicious and unauthorized: quarantine the calling identity, revoke Vertex
 58  credentials, and review IAM.
 59- If `BLOCK_NONE` was used, require stricter thresholds (for example BLOCK_MEDIUM_AND_ABOVE) via
 60  org policy or application defaults.
 61"""
 62references = [
 63    "https://www.elastic.co/docs/reference/integrations/gcp_vertexai",
 64    "https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-filters",
 65]
 66risk_score = 47
 67rule_id = "83ac492d-d5b5-4db6-89d4-d1be7456c54c"
 68setup = """## Setup
 69
 70Requires prompt_response_logs with candidates.safety_ratings.* populated. Ratings appear when the client sends
 71safetySettings on the GenerateContent request.
 72"""
 73severity = "medium"
 74tags = [
 75    "Domain: GenAI",
 76    "Domain: Cloud",
 77    "Data Source: GCP Vertex AI",
 78    "Data Source: GCP",
 79    "Data Source: Google Cloud Platform",
 80    "Platform: GCP",
 81    "Service: GCP Vertex AI",
 82    "Use Case: Policy Violation",
 83    "Use Case: Threat Detection",
 84    "Tactic: Defense Evasion",
 85    "Threat: Unauthorized AI Usage",
 86    "Resources: Investigation Guide",
 87    "Rule Type: ES|QL",
 88]
 89timestamp_override = "event.ingested"
 90type = "esql"
 91
 92query = '''
 93from logs-gcp_vertexai.prompt_response_logs-* metadata _id, _version, _index
 94| where
 95    data_stream.dataset == "gcp_vertexai.prompt_response_logs" and
 96    (
 97        MV_CONTAINS(gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.probability, "HIGH") or
 98        MV_CONTAINS(gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.probability, "MEDIUM")
 99    )
100| keep
101    _id,
102    _version,
103    _index,
104    @timestamp,
105    cloud.project.id,
106    gcp.vertexai.prompt_response_logs.model,
107    gcp.vertexai.prompt_response_logs.api_method,
108    gcp.vertexai.prompt_response_logs.full_request.contents.parts.text,
109    gcp.vertexai.prompt_response_logs.full_request.safety_settings.threshold,
110    gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason,
111    gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.category,
112    gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.probability,
113    gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.severity
114'''
115
116[[rule.threat_mappings]]
117framework = "MITRE ATLAS"
118version = "2026.08"
119[[rule.threat_mappings.threat]]
120framework = "MITRE ATLAS"
121
122[rule.threat_mappings.threat.tactic]
123id = "AML.TA0007"
124name = "Defense Evasion"
125reference = "https://atlas.mitre.org/tactics/AML.TA0007/"
126
127[rule.investigation_fields]
128field_names = [
129    "cloud.project.id",
130    "gcp.vertexai.prompt_response_logs.model",
131    "gcp.vertexai.prompt_response_logs.api_method",
132    "gcp.vertexai.prompt_response_logs.full_request.contents.parts.text",
133    "gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.category",
134    "gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.probability",
135    "gcp.vertexai.prompt_response_logs.full_response.candidates.safety_ratings.severity",
136    "gcp.vertexai.prompt_response_logs.full_response.candidates.finish_reason",
137    "gcp.vertexai.prompt_response_logs.full_request.safety_settings.threshold",
138]

Triage and analysis

Investigating GCP Vertex AI Elevated Safety Rating on Response

A GenerateContent response included safety_ratings.probability of HIGH or MEDIUM for one or more Gemini harm categories (for example HARM_CATEGORY_HATE_SPEECH or HARM_CATEGORY_DANGEROUS_CONTENT). That is a stronger signal than NEGLIGIBLE/LOW and often means the prompt probed disallowed content — whether or not generation was fully blocked.

Possible investigation steps

  • Read the prompt in gcp.vertexai.prompt_response_logs.full_request.contents.parts.text.
  • Note safety_ratings.category, probability, and severity on the alert, plus finish_reason. SAFETY with HIGH/MEDIUM is high confidence; STOP with HIGH still warrants review of what was returned.
  • Check full_request.safety_settings.threshold on the same event. BLOCK_NONE means category blocking was disabled for listed categories.
  • Pivot to logs-gcp_vertexai.auditlogs-* GenerateContent for source.ip and client.user.email in the same window to identify the caller.
  • Look for related alerts (jailbreak heuristics, repeated refusals, BLOCK_NONE) from the same project/model.

False positive analysis

  • Authorized red-team or content-moderation workloads that intentionally score MEDIUM/HIGH. Exclude those projects or principals.
  • Borderline creative-writing or news-summarization prompts can occasionally score MEDIUM — read the prompt before escalating.

Response and remediation

  • If the prompt is malicious and unauthorized: quarantine the calling identity, revoke Vertex credentials, and review IAM.
  • If BLOCK_NONE was used, require stricter thresholds (for example BLOCK_MEDIUM_AND_ABOVE) via org policy or application defaults.

References

Related rules

to-top