GenAI Prompt Contains Leaked Credential

Detects known credential formats — AWS access key IDs, LLM vendor API keys, GitHub personal access tokens, SSH/PEM private key headers, JWTs, and similar — appearing in GenAI prompt or completion text, or in strings flagged by the security_ai ML model as encoded payloads.

Credentials in the model input mean an application or user is sending secrets to the model, exposing them to invocation logging, the model provider, and prompt history. Credentials in the model output or in ML-extracted encoded blobs indicate either training-data leakage, a poisoned context window, or a prompt-injection-driven exfiltration attempt. Either case warrants immediate credential rotation.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/08/19"
  3integration = ["security_ai", "aws_bedrock", "openai_chatgpt_enterprise"]
  4maturity = "production"
  5min_stack_comments = "Detection rules for the security_ai integration package are supported in v9.6.0 and above"
  6min_stack_version = "9.6.0"
  7updated_date = "2026/11/06"
  8
  9[rule]
 10author = ["Elastic"]
 11description = """
 12Detects known credential formats — AWS access key IDs, LLM vendor API keys, GitHub
 13personal access tokens, SSH/PEM private key headers, JWTs, and similar — appearing
 14in GenAI prompt or completion text, or in strings flagged by the security_ai
 15ML model as encoded payloads.
 16
 17Credentials in the model input mean an application or user is sending secrets to the
 18model, exposing them to invocation logging, the model provider, and prompt history.
 19Credentials in the model output or in ML-extracted encoded blobs indicate either
 20training-data leakage, a poisoned context window, or a prompt-injection-driven
 21exfiltration attempt. Either case warrants immediate credential rotation.
 22"""
 23false_positives = [
 24    """
 25    Prompts or completions that reference example or documentation keys (for example
 26    the AWS sample access key ending in EXAMPLE) match the access-key pattern.
 27    Review the matched value in gen_ai.input.messages, gen_ai.output.messages, or
 28    security_ai.*.strings and confirm whether it is a live credential
 29    before responding.
 30    """,
 31    """
 32    JWTs used as legitimate authentication tokens passed to the model for parsing,
 33    validation, or debugging. Inspect the prompt context to confirm whether the
 34    token was intentionally shared for a benign purpose.
 35    """,
 36]
 37from = "now-60m"
 38interval = "10m"
 39language = "esql"
 40license = "Elastic License v2"
 41name = "GenAI Prompt Contains Leaked Credential"
 42note = """
 43## Triage and Analysis
 44
 45### Investigating GenAI Prompt Contains Leaked Credential
 46
 47This rule fires when a recognized credential format appears in a GenAI invocation's
 48prompt, completion, or in strings extracted by the security_ai ML model.
 49Credential exposure via LLM invocation logs is a high-impact event: logs may be
 50retained by the cloud provider, ingested into SIEM, or replayed in future training runs.
 51
 52### Possible investigation steps
 53
 54- Identify the matched credential format from `security_ai.encoding.input_messages.strings`,
 55  `security_ai.encoding.output_messages.strings`, `security_ai.hash_string.input_messages.strings`,
 56  `security_ai.hash_string.output_messages.strings`, `gen_ai.input.messages`, or `gen_ai.output.messages`.
 57  Common format signals:
 58  - `AKIA`/`ASIA` prefix (20 chars) → AWS long-term or STS access key ID
 59  - `sk-ant-api03-` → Anthropic API key
 60  - `sk-proj-` / `sk-` (48+ chars) → OpenAI API key
 61  - `AIza` → Google API key
 62  - `ghp_`/`gho_`/`ghu_`/`ghs_` → GitHub personal/OAuth/user/server access token
 63  - `github_pat_` → GitHub fine-grained personal access token
 64  - `glpat-` → GitLab personal access token
 65  - `sk_live_` → Stripe live secret key
 66  - `hf_` → HuggingFace access token
 67  - `xox[baprs]-` → Slack bot/app/personal/incoming-webhook/refresh token
 68  - Three dot-separated base64url segments starting with `eyJ` → JWT
 69  - `-----BEGIN ... PRIVATE KEY-----` → SSH, RSA, EC, or PKCS8 private key
 70
 71- Check `gen_ai.input.messages` and `gen_ai.output.messages` for the full conversation context.
 72  Determine whether the credential appeared in user input (exfiltration attempt or
 73  accidental exposure) or in the model's response (leakage or injection-driven retrieval).
 74
 75- Identify the caller: `user.id`, `source.ip`, `user_agent.original`,
 76  `aws_bedrock.invocation.model_id`.
 77
 78- If the credential appears in the ML-extracted strings (`security_ai.*.{input_messages,output_messages}.strings`),
 79  also check whether a co-occurring base64 rule alert fired. The base64 alert is
 80  suppressed when credentials are present, so if it did not fire, the credential was
 81  the only encoded content.
 82
 83- Query CloudTrail or the relevant provider's audit logs for any use of the exposed
 84  credential within the alert window.
 85
 86### False positive analysis
 87
 88- AWS sample/documentation keys (ending in `EXAMPLE`) match the AKIA pattern.
 89  Confirm the value is real before escalating.
 90- JWTs passed deliberately for debugging are common. Check whether the model was
 91  being asked to validate, decode, or inspect the token.
 92
 93### Response and remediation
 94
 95- Rotate or revoke the exposed credential immediately, regardless of whether it
 96  appears to have been used.
 97- Identify the application or workflow that placed the credential in the prompt and
 98  remediate the root cause (secrets scanning, environment variable hygiene, guardrails).
 99- If the credential appears in the model's completion, assess whether this is a
100  training-data leakage, a context-window injection, or a configuration error.
101- Review the full invocation history for the affected user or application to identify
102  any pattern of credential exposure.
103"""
104references = [
105    "https://owasp.org/www-project-top-10-for-large-language-model-applications/",
106    "https://www.beyondtrust.com/blog/entry/aws-bedrock-security-guide-api-keys-detection-response",
107]
108risk_score = 73
109rule_id = "e3b1f8c4-7d2a-4e5b-9c1a-6f8d3b2e7a0c"
110setup = """This rule requires the security_ai Fleet integration. Install the
111integration and ensure that the ML model pipeline is enriching invocation events before
112enabling this rule. The rule also scans gen_ai.input.messages and gen_ai.output.messages directly,
113so it will partially function (message scanning only) even without the
114ML pipeline enrichment. For setup instructions, refer to the [Security for AI integration documentation](https://www.elastic.co/docs/reference/integrations/security_ai)."""
115severity = "high"
116tags = [
117    "Domain: GenAI",
118    "Use Case: Security for AI",
119    "Tactic: Credential Access",
120    "Mitre Atlas: AML.T0055",
121    "Data Source: AWS Bedrock",
122    "Data Source: OpenAI ChatGPT Enterprise",
123    "Platform: AWS",
124    "Platform: OpenAI",
125    "Service: AWS Bedrock",
126    "Service: OpenAI ChatGPT Enterprise",
127    "Rule Type: ES|QL",
128    "Resources: Investigation Guide",
129]
130timestamp_override = "event.ingested"
131to = "now"
132type = "esql"
133
134query = '''
135FROM logs-aws_bedrock.invocation-*, logs-openai_chatgpt_enterprise.codex_log-*, logs-openai_chatgpt_enterprise.conversation_message-*, logs-openai_chatgpt_enterprise.custom_agents_log-* METADATA _id, _version, _index
136// gen_ai.*.messages are mapped as flattened, which RLIKE cannot read; TO_STRING returns their JSON text.
137| EVAL Esql_priv.all_text = CONCAT(
138    COALESCE(MV_CONCAT(TO_STRING(gen_ai.input.messages), "\n"), ""), "\n",
139    COALESCE(MV_CONCAT(TO_STRING(gen_ai.output.messages), "\n"), ""), "\n",
140    COALESCE(MV_CONCAT(security_ai.encoding.input_messages.strings, "\n"), ""), "\n",
141    COALESCE(MV_CONCAT(security_ai.encoding.output_messages.strings, "\n"), ""), "\n",
142    COALESCE(MV_CONCAT(security_ai.hash_string.input_messages.strings, "\n"), ""), "\n",
143    COALESCE(MV_CONCAT(security_ai.hash_string.output_messages.strings, "\n"), ""))
144// Credential formats are split across two RLIKEs because a single pattern with every format exceeds
145// ES|QL's regex determinization limit. A key must not be glued to a preceding key character (or be
146// preceded by a JSON-escaped \n, \r or \t); that also keeps the automaton small.
147// Not lowercased: credential prefixes (AKIA, sk-, ghp_, etc.) are case-significant.
148| WHERE Esql_priv.all_text RLIKE """(.*([^A-Za-z0-9_\-]|\\[nrt]))?((AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}|ABSK[A-Za-z0-9+/=]{20}|AIza[0-9A-Za-z_\-]{35}|gh[pousr]_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_\-]{20,}|sk-ant-api03-[A-Za-z0-9_\-]{80,}|sk-proj-[A-Za-z0-9_\-]{20,}).*"""
149    OR Esql_priv.all_text RLIKE """(.*([^A-Za-z0-9_\-]|\\[nrt]))?(sk-[A-Za-z0-9]{48}|sk_live_[A-Za-z0-9]{24}|hf_[A-Za-z0-9]{34}|xox[baprs]-[A-Za-z0-9\-]{10,}|eyJ[A-Za-z0-9_\-]{10,}\.eyJ[A-Za-z0-9_\-]{10,}\..*|-----BEGIN [A-Z ]*PRIVATE KEY-----).*"""
150| KEEP _id, _version, _index, @timestamp, gen_ai.*, security_ai.*, aws_bedrock.*, user.*, cloud.*, event.*, openai_chatgpt_enterprise.*
151'''
152
153[[rule.threat]]
154framework = "MITRE ATT&CK"
155
156[[rule.threat.technique]]
157id = "T1552"
158name = "Unsecured Credentials"
159reference = "https://attack.mitre.org/techniques/T1552/"
160
161[rule.threat.tactic]
162id = "TA0006"
163name = "Credential Access"
164reference = "https://attack.mitre.org/tactics/TA0006/"
165
166[[rule.threat_mappings]]
167framework = "MITRE ATLAS"
168version = "2026.08"
169
170[[rule.threat_mappings.threat]]
171framework = "MITRE ATLAS"
172
173[[rule.threat_mappings.threat.technique]]
174id = "AML.T0055"
175name = "Unsecured Credentials"
176reference = "https://atlas.mitre.org/techniques/AML.T0055/"
177
178[rule.threat_mappings.threat.tactic]
179id = "AML.TA0013"
180name = "Credential Access"
181reference = "https://atlas.mitre.org/tactics/AML.TA0013/"

Triage and Analysis

Investigating GenAI Prompt Contains Leaked Credential

This rule fires when a recognized credential format appears in a GenAI invocation's prompt, completion, or in strings extracted by the security_ai ML model. Credential exposure via LLM invocation logs is a high-impact event: logs may be retained by the cloud provider, ingested into SIEM, or replayed in future training runs.

Possible investigation steps

  • Identify the matched credential format from security_ai.encoding.input_messages.strings, security_ai.encoding.output_messages.strings, security_ai.hash_string.input_messages.strings, security_ai.hash_string.output_messages.strings, gen_ai.input.messages, or gen_ai.output.messages. Common format signals:

    • AKIA/ASIA prefix (20 chars) → AWS long-term or STS access key ID
    • sk-ant-api03- → Anthropic API key
    • sk-proj- / sk- (48+ chars) → OpenAI API key
    • AIza → Google API key
    • ghp_/gho_/ghu_/ghs_ → GitHub personal/OAuth/user/server access token
    • github_pat_ → GitHub fine-grained personal access token
    • glpat- → GitLab personal access token
    • sk_live_ → Stripe live secret key
    • hf_ → HuggingFace access token
    • xox[baprs]- → Slack bot/app/personal/incoming-webhook/refresh token
    • Three dot-separated base64url segments starting with eyJ → JWT
    • -----BEGIN ... PRIVATE KEY----- → SSH, RSA, EC, or PKCS8 private key
  • Check gen_ai.input.messages and gen_ai.output.messages for the full conversation context. Determine whether the credential appeared in user input (exfiltration attempt or accidental exposure) or in the model's response (leakage or injection-driven retrieval).

  • Identify the caller: user.id, source.ip, user_agent.original, aws_bedrock.invocation.model_id.

  • If the credential appears in the ML-extracted strings (security_ai.*.{input_messages,output_messages}.strings), also check whether a co-occurring base64 rule alert fired. The base64 alert is suppressed when credentials are present, so if it did not fire, the credential was the only encoded content.

  • Query CloudTrail or the relevant provider's audit logs for any use of the exposed credential within the alert window.

False positive analysis

  • AWS sample/documentation keys (ending in EXAMPLE) match the AKIA pattern. Confirm the value is real before escalating.
  • JWTs passed deliberately for debugging are common. Check whether the model was being asked to validate, decode, or inspect the token.

Response and remediation

  • Rotate or revoke the exposed credential immediately, regardless of whether it appears to have been used.
  • Identify the application or workflow that placed the credential in the prompt and remediate the root cause (secrets scanning, environment variable hygiene, guardrails).
  • If the credential appears in the model's completion, assess whether this is a training-data leakage, a context-window injection, or a configuration error.
  • Review the full invocation history for the affected user or application to identify any pattern of credential exposure.

References

Related rules

to-top