Skip to content

[Security AI Prompts] Update Entity Highlights prompt#19999

Open
CAWilson94 wants to merge 2 commits into
elastic:mainfrom
CAWilson94:caw/entity-highlights-prompt-update
Open

[Security AI Prompts] Update Entity Highlights prompt#19999
CAWilson94 wants to merge 2 commits into
elastic:mainfrom
CAWilson94:caw/entity-highlights-prompt-update

Conversation

@CAWilson94

Copy link
Copy Markdown

Update the entityDetailsHighlights prompt content: add MITRE ATT&CK / Lockheed Martin Kill Chain mapping for anomalies, anti-fabrication guardrails, synthesise-don't-list guidance, and response size limits. Bump package version 1.0.131.0.14.

Proposed commit message

Update the entityDetailsHighlights Security AI prompt (aiForEntityDetails group) used by the Entity Analytics "Entity summary" flyout in the Security Solution.

WHAT:

  • Rewrites the prompt to (a) map significant anomalies to the relevant MITRE ATT&CK tactic / Lockheed Martin Kill Chain phase when ML job results clearly correspond to a known technique; (b) add anti-fabrication guardrails so the model only uses values explicitly present in the context (no invented scores, CVEs, job names, or technique mappings); (c) enforce "synthesise, don't list" behaviour; and (d) apply response size limits (aim for <600 chars of highlights, 1-sentence highlights, up to 3 prioritised recommendations, 2-decimal rounding, inline-code for technical values).
  • Content-only change to the single entityDetailsHighlights saved object; the saved-object id, type, and filename are unchanged.
  • Bumps the package version 1.0.131.0.14 (patch, content-only) with a matching changelog.yml entry.

WHY:

  • Mirrors the corresponding Kibana prompt change (see Related issues) so the deployed saved object matches the in-code fallback. Without this, deployments with the Security AI Prompts integration installed continue to serve the old prompt, since the saved object overrides the local prompt.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.

Author's Checklist

  • Confirm promptId (entityDetailsHighlights) and promptGroupId (aiForEntityDetails) are unchanged — only prompt.default content changed.
  • Confirm the version bump + changelog entry are consistent.
  • Confirm no other prompt saved objects were modified (single-file change).

How to test this PR locally

  1. Build and serve the package:
    cd packages/security_ai_prompts
    elastic-package lint
    elastic-package build
    elastic-package stack up -d -v --services package-registry

Update the entityDetailsHighlights prompt content: add MITRE ATT&CK /
Lockheed Martin Kill Chain mapping for anomalies, anti-fabrication
guardrails, synthesise-don't-list guidance, and response size limits.
Bump package version 1.0.13 -> 1.0.14.

Co-authored-by: Cursor <cursoragent@cursor.com>
@CAWilson94 CAWilson94 requested a review from a team as a code owner July 6, 2026 17:10
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Elastic Docs Style Checker (Vale)

Summary: 1 suggestion found

💡 Suggestions (1): Optional style improvements. Apply when helpful.
File Line Rule Message
packages/security_ai_prompts/changelog.yml 4 Elastic.WordChoice Consider using 'cancel, stop' instead of 'Kill', unless the term is in the UI.

The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

@github-actions

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Both failed Buildkite steps are caused by the new security_ai_prompts changelog entry still using the placeholder PR link. Replace https://github.com/elastic/integrations/pull/PLACEHOLDER with https://github.com/elastic/integrations/pull/19999.

Remediation

  • Update packages/security_ai_prompts/changelog.yml in the 1.0.14 entry so link: points to https://github.com/elastic/integrations/pull/19999.
  • Re-run the changelog link check or the security_ai_prompts package check after updating the link.
Investigation details

Root Cause

The PR diff adds a 1.0.14 changelog entry with link: https://github.com/elastic/integrations/pull/PLACEHOLDER. The changelog validation requires a positive issue/PR number and the dedicated Buildkite changelog check requires the link to match this PR number.

Evidence

ERROR: unexpected link: 'https://github.com/elastic/integrations/pull/PLACEHOLDER'
       expected:         'https://github.com/elastic/integrations/pull/19999'
  • Job/step: Check integrations security_ai_prompts
  • Key log excerpt:
Error: checking package failed: linting package failed: found 1 validation error:
   1. https://github.com/elastic/integrations/pull/PLACEHOLDER: issue number in changelog link should be a positive number

Verification

  • Not run locally; this was a read-only CI log investigation. The failure is deterministic from the invalid changelog URL shown in both logs.

What is this? | From workflow: PR Buildkite Detective

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

Co-authored-by: Cursor <cursoragent@cursor.com>
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

@mergify

mergify Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@CAWilson94

Copy link
Copy Markdown
Author

Waiting to merge in kibana PR first: elastic/kibana#276038

@andrewkroh andrewkroh added the Integration:security_ai_prompts Security AI Prompts label Jul 6, 2026
@CAWilson94

Copy link
Copy Markdown
Author

@andrewkroh @andrew-goldstein added this to merge queue prior to the kibana related PR merging in due to timing. Just an FYI

CAWilson94 added a commit to elastic/kibana that referenced this pull request Jul 7, 2026
…regenerate nudge (#276038)

## Summary

Persists the **Entity AI Summary** so it no longer regenerates on every
flyout open/click-away. Instead of writing to the entity-store
`entity.attributes.summary` field (POC #269344), the summary is now
stored as an **append-only document in the entity metadata datastream**
(`.entities.v2.metadata.security_*`, base #271806), per
[security-team#17968](elastic/security-team#17968).

## What changed

- **Write** — generation persists a single immutable `ai_summary.*` doc
via `asInternalUser` (server-derived `generated_by`; no per-user
metadata write privilege needed). Structural caps applied (max 4
highlights, 3 recommended actions).
- **Read** — gated `GET` (`asCurrentUser`): with metadata read access
the persisted summary is shown; without it, the flyout gracefully falls
back to on-demand generation (nothing persisted).
- **Removed** the never-merged `entity.attributes.summary` field +
`includeSummary` listing param.
- **Staleness nudge** — if the entity's risk score drifts from the
snapshot taken at generation time, a warning callout prompts
regeneration.
- **Prompt** — promoted the improved entity-highlights prompt (MITRE /
Kill Chain mapping, synthesize-don't-list, anti-fabrication) as the
single default.
- **Tests/docs** — Scout API permissions matrix + `check_privileges`
coverage, unit tests, and README privilege docs.

Updated Security AI prompts Integration SO:
elastic/integrations#19999

<details>
<summary>
<strong>Prompt and Summary Content</strong>
</summary>

- [Customer feedback flagged that the summary was **too long to be a
summary**.](elastic/security-team#16484 (comment))
Rather than just trimming length, I reworked the prompt to change the
*shape* of the output while keeping , and focussing, its value - helping
an analyst quickly see **what needs their attention and how to move
forward with an investigation**, not handing them a raw data dump to
interpret themselves.

- **Risk score** stays high-level: describe the dominant threat pattern,
and only name a specific rule/alert when it clearly accounts for the
majority of the score - instead of listing every contributing rule.
- **Anomalies** are summarized as the single most significant pattern
rather than listed, and mapped to a MITRE ATT&CK tactic or Lockheed
Martin Kill Chain phase only when the ML results clearly correspond to a
known technique (the mapping is omitted when anomalies are ambiguous or
benign, to avoid guessing).
- **Criticality / vulnerabilities** state the level / most critical
finding and *why it matters*, not raw values.

- **Reinforced with hard guardrails:** 1 sentence per highlight (2 only
when an anomaly needs the extra clause for a MITRE/Kill Chain mapping),
a concise highlights budget, up to 3 prioritized recommendations, no
fabricated values, and consistent formatting (backticks for technical
values, 2-decimal rounding).
- The result is shorter *because* it's focused - not truncated. This
directly addresses design/product feedback that the risk score and
anomalies should be summarized at a high level rather than enumerated.

Prompt quality is inherently subjective and hard to unit-test, so I
validated it by desk-testing against seeded rich data (risk,
criticality, anomalies, vulnerabilities); the telemetry below is there
to keep tuning it from real usage post-merge.
</details>

<details>
<summary>
<strong>Telemetry</strong>
</summary>

- Generating an entity AI summary emits an `entity_ai_summary_persisted`
EBT event with `entityType`, `spaceId`, and `highlightsCount` /
`recommendedActionsCount`. The two counts are the **raw number of items
the model produced, captured client-side before structural capping** —
not the number persisted (the doc is always capped to
`MAX_ENTITY_SUMMARY_HIGHLIGHTS` /
`MAX_ENTITY_SUMMARY_RECOMMENDED_ACTIONS`).

- **Why it's useful:** comparing these raw counts against the caps tells
us how often, and by how much, the prompt overshoots the intended
summary length — a data-driven feedback loop for tuning the prompt (e.g.
if the model routinely returns 7 highlights against a cap of 4, the
prompt is asking for too much). The counts are captured on the client
because the server only ever receives the already-capped content and so
cannot observe overshoot itself. No summary text or entity identifiers
are included in the event.

- **How it connects to the prompt change:** the prompt was reworked to
be shorter by being more focused (per the customer feedback that it was
too long); this telemetry closes the loop by letting us track overshoot
over time and keep tuning the prompt and caps from real usage rather
than guesswork.
</details>

## Demo 

Latest Demo! 🔥


https://github.com/user-attachments/assets/471bb53e-ce6d-46dd-838b-4bd2e2e63c26



## Notes for reviewers

- **Generation is currently client-side** (the client POSTs the
generated summary). This is transitional — it reuses the assistant's
client-side anonymization/replacements context. Moving generation fully
server-side is a tracked follow-up (also required to move staleness
computation server-side so Agent Builder / external clients share it).
- **The summary body (highlights + recommended actions) is
English-only.** This matches all AI-generated content in the Security
solution (no assistant prompt does locale-based generation) and is the
same as pre-persistence behavior — **not a regression**. All UI chrome
(headers, buttons, staleness callout + message) is i18n'd.
**- Entity AI Summary runtime helpers:** (staleness detection + caps)
are exported from a dedicated `@kbn/entity-store/common/entity_summary`
subpath, not the top-level common barrel. The barrel is the page-load
entry (always-loaded primitives only); this logic is used only by the
lazy flyout and server, so keeping it in the barrel pushed the
entityStore page-load bundle over budget. The subpath code-splits it out
- fixing the size regression structurally rather than raising the limit
- mirroring the existing euid_helpers / entity_maintainers modules.
Types stay in the barrel (zero page-load cost).

## Testing

**1. Prereqs:** Entity Store v2 enabled, an Enterprise license, and a
configured AI connector.

**2. Seed data** (uses generator PR
[security-documents-generator#417](elastic/security-documents-generator#417)
for entity-correlated vulnerabilities):

```bash
# Entities + risk score + asset criticality + alerts
yarn start risk-score-v2 --entity-kinds host,idp_user --hosts 20 --no-setup
# Layer anomalies + vulnerabilities + misconfigurations, correlated to those entities
yarn start generate-entity-ai-insights --correlate-with-entity-store -h 20 -u 20 -a 20
```

**3. Verify persistence:**
- Open a host/user entity flyout → AI summary → **Generate**.
- Close and reopen the flyout → the **same** summary shows, with no
regeneration, plus a "Generated by … on …" line.
- As a second user (with metadata read) → the same summary + original
generated-by is shown.

**4. Verify staleness nudge:**
- For an entity with an already generated summary - change the asset
criticality, then re-open the flyout for that summary and verify → a
warning callout appears ("Entity risk has changed…") → click
**Regenerate summary** → callout clears.

**5. Verify gated-read fallback:**
- As a user **without** read on `.entities.v2.metadata.security_*` → the
flyout falls back to on-demand generation and does **not** persist.


Mappings - 

Using `GET .entities.v2.metadata.security_default/_mapping` from dev
tools, after some reviews the latest mappings (Tuesday July 7th):
```
 "Ai_summary": {
          "properties": {
            "anomaly_job_ids": {
              "type": "keyword"
            },
            "generated_at": {
              "type": "date",
              "format": "epoch_millis"
            },
            "generated_by": {
              "type": "keyword"
            },
            "highlights": {
              "type": "object",
              "enabled": false
            },
            "recommended_actions": {
              "type": "keyword",
              "index": false,
              "doc_values": false
            },
            "staleness": {
              "properties": {
                "enabled_signals": {
                  "type": "keyword"
                },
                "snapshot": {
                  "properties": {
                    "risk_score": {
                      "type": "float"
                    }
                  }
                }
              }
            },
            "variant_id": {
              "type": "keyword"
            }
          }
        },
```

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Alex Prozorov <alex.prozorov@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants