Describe the bug:
Everywhere notes are displayed in the Security Solution, the author's avatar is rendered from the stored display-name string only, using a plain EuiAvatar. That produces auto-generated initials and an auto-assigned color, and it ignores the avatar the user configured in their Kibana user profile (uploaded image, or custom initials + color).
The same user therefore shows one avatar in Cases, the user menu, and assignee lists (profile avatar) and a different, generated one on notes. In a workspace where several people annotate the same timeline this makes note authorship harder to scan, and it looks inconsistent next to Cases, which already renders profile avatars for comment authors.
Kibana/Elasticsearch Stack version: reproduced on a clean 9.4.4 stack (Docker images, trial license); the same code is on main at 68d2f14 and on the 9.4 branch
Server OS version: any
Browser and Browser OS versions: any
Elastic Endpoint version: n/a
Original install method: official 9.4.4 Docker images (docker.elastic.co), single-node, trial license
Functional Area: Timelines / Notes
Steps to reproduce:
- Start a stack with a trial/platinum license (notes + user profile suggestions are Platinum-gated) and log in as two different users.
- For each user, set a profile avatar — upload an image, or set custom initials and a color — via User menu → Edit profile → Avatar.
- Open a timeline and have each user add a note.
- Look at the author avatars in the timeline Notes tab, in the Participants panel, and in the "Created by" column at Security → Manage → Notes (
/app/security/administration/notes).
- For comparison, open any case and look at the same two users in the comment stream.
Current behavior:
The avatar is generated from the note's updatedBy / createdBy display-name string. The user's configured profile image is never loaded, and their chosen initials/color are not used.
Affected call sites, all passing a bare name to EuiAvatar:
| Location |
File |
| Notes list (flyout + timeline Notes tab) |
x-pack/solutions/security/plugins/security_solution/public/notes/components/notes_list.tsx |
| Note management page, "Created by" column |
x-pack/solutions/security/plugins/security_solution/public/notes/pages/note_management_page.tsx |
| Timeline participants |
x-pack/solutions/security/plugins/security_solution/public/timelines/components/notes/participants.tsx |
| Note previews (open timeline) |
x-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx |
| Timeline description comment |
x-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsx |
Expected behavior:
Note avatars should render the author's user profile avatar — image if one is set, otherwise the profile's initials and color — consistent with how Cases renders comment authors. When no matching profile exists (deleted user, note imported from another cluster, unauthenticated writes), fall back to the current generated initials avatar.
Root cause:
Notes do not persist a user profile identifier. Server-side, saved_object.ts stores only a display string:
// x-pack/solutions/security/plugins/security_solution/server/lib/timeline/saved_object/notes/saved_object.ts
savedNote.createdBy = userInfo ? getUserDisplayName(userInfo) : UNAUTHENTICATED_USER;
savedNote.updatedBy = userInfo ? getUserDisplayName(userInfo) : UNAUTHENTICATED_USER;
getUserDisplayName resolves to full_name || email || username. Since the note carries no profile uid, the client has nothing to look the profile up by, and every render site fell back to <EuiAvatar name={...} />.
Worth noting that on the note management page the profile data is already in hand — note_management_page.tsx:131 calls useSuggestUsers({ searchTerm: '', enabled: isPlatinumPlus }) to populate the "Created by" filter — it is simply not used when rendering the avatar in the column next to it.
Proposed fix:
Add a shared NoteAvatar component that resolves the display name back to a user profile and renders UserAvatar from @kbn/user-profile-components, falling back to EuiAvatar when no profile matches. It reuses the existing useSuggestUsers hook (already used elsewhere in the Security Solution, cached with staleTime: Infinity), matching on getUserDisplayName(user) === displayName. All five call sites above switch to it.
Known limitation of that approach — verified, and it matters:
useSuggestUsers({ searchTerm: '' }) hits GET /internal/detection_engine/users/_find, which calls security.userProfiles.suggest() without a size. That defaults to DEFAULT_SUGGESTIONS_COUNT = 10 (x-pack/platform/plugins/shared/security/server/user_profile/user_profile_service.ts:44), so the component can only ever see 10 profiles.
Measured on the 9.4.4 repro stack:
| Activated user profiles |
Profiles returned by suggestUsers('') |
Notes that resolve to a profile avatar |
| 2 |
2 |
3 / 3 |
| 16 |
10 |
1 / 3 |
With 16 users, Sarah Chen — author of 2 of the 3 notes — was not in the 10 returned profiles, so her notes still render the generated fallback avatar. The name-matching approach therefore only holds on very small deployments, and which users it fixes is effectively arbitrary (the suggest ordering is not stable or authorship-aware).
Two further problems with matching on display name: users sharing a display name are indistinguishable, and the note stores whatever getUserDisplayName returned at write time, so a later change to a user's full_name silently breaks the match for their existing notes.
The durable fix is to persist the author's profile uid on the note saved object and resolve it with bulkGetUserProfiles, keeping name matching only as a fallback for notes written before that change. If we want the display-name approach as a stopgap, it should at least pass an explicit size up to MAX_SUGGESTIONS_COUNT = 100 — but that only moves the cliff from 10 users to 100.
Errors in browser console (if relevant): none
Screenshots (if relevant):
- Notes management page — "Created by" shows generated letter avatars (
SC, SC, E), not the profile images both users have configured.
- Same frame, user menu open — the user menu renders
elastic's actual uploaded profile image while the table below shows E for that same user.
- Timeline → Notes tab — the notes list, the "Created by" panel and the "Participants" panel all show letter avatars (three of the five affected call sites in one view).
- Cases, same two users — Cases renders both users' real profile images in the comment stream, activity log and Participants sidebar. This is the behavior notes should match.
Describe the bug:
Everywhere notes are displayed in the Security Solution, the author's avatar is rendered from the stored display-name string only, using a plain
EuiAvatar. That produces auto-generated initials and an auto-assigned color, and it ignores the avatar the user configured in their Kibana user profile (uploaded image, or custom initials + color).The same user therefore shows one avatar in Cases, the user menu, and assignee lists (profile avatar) and a different, generated one on notes. In a workspace where several people annotate the same timeline this makes note authorship harder to scan, and it looks inconsistent next to Cases, which already renders profile avatars for comment authors.
Kibana/Elasticsearch Stack version: reproduced on a clean 9.4.4 stack (Docker images, trial license); the same code is on
mainat 68d2f14 and on the 9.4 branchServer OS version: any
Browser and Browser OS versions: any
Elastic Endpoint version: n/a
Original install method: official 9.4.4 Docker images (
docker.elastic.co), single-node, trial licenseFunctional Area: Timelines / Notes
Steps to reproduce:
/app/security/administration/notes).Current behavior:
The avatar is generated from the note's
updatedBy/createdBydisplay-name string. The user's configured profile image is never loaded, and their chosen initials/color are not used.Affected call sites, all passing a bare name to
EuiAvatar:x-pack/solutions/security/plugins/security_solution/public/notes/components/notes_list.tsxx-pack/solutions/security/plugins/security_solution/public/notes/pages/note_management_page.tsxx-pack/solutions/security/plugins/security_solution/public/timelines/components/notes/participants.tsxx-pack/solutions/security/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsxx-pack/solutions/security/plugins/security_solution/public/timelines/components/timeline/tabs/notes/index.tsxExpected behavior:
Note avatars should render the author's user profile avatar — image if one is set, otherwise the profile's initials and color — consistent with how Cases renders comment authors. When no matching profile exists (deleted user, note imported from another cluster, unauthenticated writes), fall back to the current generated initials avatar.
Root cause:
Notes do not persist a user profile identifier. Server-side,
saved_object.tsstores only a display string:getUserDisplayNameresolves tofull_name || email || username. Since the note carries no profileuid, the client has nothing to look the profile up by, and every render site fell back to<EuiAvatar name={...} />.Worth noting that on the note management page the profile data is already in hand —
note_management_page.tsx:131callsuseSuggestUsers({ searchTerm: '', enabled: isPlatinumPlus })to populate the "Created by" filter — it is simply not used when rendering the avatar in the column next to it.Proposed fix:
Add a shared
NoteAvatarcomponent that resolves the display name back to a user profile and rendersUserAvatarfrom@kbn/user-profile-components, falling back toEuiAvatarwhen no profile matches. It reuses the existinguseSuggestUsershook (already used elsewhere in the Security Solution, cached withstaleTime: Infinity), matching ongetUserDisplayName(user) === displayName. All five call sites above switch to it.Known limitation of that approach — verified, and it matters:
useSuggestUsers({ searchTerm: '' })hitsGET /internal/detection_engine/users/_find, which callssecurity.userProfiles.suggest()without asize. That defaults toDEFAULT_SUGGESTIONS_COUNT = 10(x-pack/platform/plugins/shared/security/server/user_profile/user_profile_service.ts:44), so the component can only ever see 10 profiles.Measured on the 9.4.4 repro stack:
suggestUsers('')With 16 users,
Sarah Chen— author of 2 of the 3 notes — was not in the 10 returned profiles, so her notes still render the generated fallback avatar. The name-matching approach therefore only holds on very small deployments, and which users it fixes is effectively arbitrary (the suggest ordering is not stable or authorship-aware).Two further problems with matching on display name: users sharing a display name are indistinguishable, and the note stores whatever
getUserDisplayNamereturned at write time, so a later change to a user'sfull_namesilently breaks the match for their existing notes.The durable fix is to persist the author's profile
uidon the note saved object and resolve it withbulkGetUserProfiles, keeping name matching only as a fallback for notes written before that change. If we want the display-name approach as a stopgap, it should at least pass an explicitsizeup toMAX_SUGGESTIONS_COUNT = 100— but that only moves the cliff from 10 users to 100.Errors in browser console (if relevant): none
Screenshots (if relevant):
SC,SC,E), not the profile images both users have configured.elastic's actual uploaded profile image while the table below showsEfor that same user.