Objective
The same adversary shows up under a user account on one host and a service account on another — same behavior, different artifacts. If your tooling treats each as a separate alert, an analyst drowns in duplicates. This recipe links observations that describe the same behavior, so one actor is one entity.
Step 1: Observations with a behavior embedding
DROP TABLE IF EXISTS actor_obs;
CREATE TABLE actor_obs (
obs_id TEXT PRIMARY KEY,
artifact TEXT,
behavior TEXT,
emb VECTOR(384)
);
INSERT INTO actor_obs VALUES
('O1','user:jdoe',
'Enumerated shares then ran encoded powershell from a temp dir at 2am.',
EMBED('Enumerated shares then ran encoded powershell from a temp dir at 2am.'));
Step 2: Does a new observation match a known actor?
SELECT obs_id,
artifact,
COSINE_SIMILARITY(
emb,
EMBED('Host SRV-07 ran base64 powershell from temp and listed network shares overnight.')
) AS sim
FROM actor_obs
ORDER BY sim DESC
LIMIT 1;
Result — the service-account observation on SRV-07 links to the same behavior first seen under
user:jdoe:
| obs_id | artifact | sim |
|---|---|---|
| O1 | user:jdoe | 0.708 |
Why it matters
Two artifacts, one actor — collapsed before a human is paged. Above your threshold, merge the observations into a single case, then run attack-path analysis on the combined host set and log the merge to a write-once audit. To build a full entity/asset knowledge graph, see knowledge-graph construction.