Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Performs User and Entity Behavior Analytics (UEBA) to detect anomalous user activities including impossible travel, unusual access patterns, privilege abuse, and insider threats using SIEM-based behavioral baselines and statistical analysis. Use when SOC teams need to identify compromised accounts or insider threats through deviation from established behavioral norms.
.claude/skills/performing-user-behavior-analytics/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
| case-20 | ✗→✓ | ▲ Improved | — | — |
| case-03 | ✗→✓ | ▲ Improved | — | — |
Use this skill when:
Do not use as the sole basis for disciplinary action — UEBA findings are indicators requiring investigation, not proof of malicious intent.
Create behavioral baselines from historical data:
splindex=auth sourcetype IN ("o365:management:activity", "vpn_logs", "WinEventLog:Security") earliest=-30d latest=-1d | stats dc(src_ip) AS unique_ips, dc(src_country) AS unique_countries, dc(app) AS unique_apps, count AS total_logins, earliest(_time) AS first_login, latest(_time) AS last_login, values(src_country) AS countries, avg(eval(strftime(_time, "%H"))) AS avg_login_hour, stdev(eval(strftime(_time, "%H"))) AS stdev_login_hour by user | eval avg_daily_logins = round(total_logins / 30, 1) | eval login_hour_range = round(avg_login_hour, 0)." +/- ".round(stdev_login_hour, 1)." hrs" | table user, unique_ips, unique_countries, unique_apps, avg_daily_logins, login_hour_range, countries
Identify logins from geographically distant locations within impossible timeframes:
splindex=auth sourcetype IN ("o365:management:activity", "vpn_logs") action=success earliest=-24h | iplocation src_ip | sort user, _time | streamstats current=f last(lat) AS prev_lat, last(lon) AS prev_lon, last(_time) AS prev_time, last(City) AS prev_city, last(Country) AS prev_country, last(src_ip) AS prev_ip by user | where isnotnull(prev_lat) | eval distance_km = round( 6371 * acos( cos(pi()/180 * lat) * cos(pi()/180 * prev_lat) * cos(pi()/180 * (lon - prev_lon)) + sin(pi()/180 * lat) * sin(pi()/180 * prev_lat) ), 0) | eval time_diff_hours = round((_time - prev_time) / 3600, 2) | eval speed_kmh = if(time_diff_hours > 0, round(distance_km / time_diff_hours, 0), 0) | where speed_kmh > 900 AND distance_km > 500 | eval alert = "IMPOSSIBLE TRAVEL: ".prev_city.", ".prev_country." -> ".City.", ".Country | table _time, user, prev_city, prev_country, City, Country, distance_km, time_diff_hours, speed_kmh, alert | sort - speed_kmh
Identify logins outside a user's normal working hours:
splindex=auth action=success earliest=-7d | eval hour = strftime(_time, "%H") | eval day_of_week = strftime(_time, "%A") | eval is_weekend = if(day_of_week IN ("Saturday", "Sunday"), 1, 0) | eval is_off_hours = if(hour < 6 OR hour > 22, 1, 0) | join user type=left [ search index=auth action=success earliest=-60d latest=-7d | eval hour = strftime(_time, "%H") | stats avg(hour) AS baseline_avg_hour, stdev(hour) AS baseline_stdev_hour, perc95(hour) AS baseline_latest_hour by user ] | where (is_off_hours=1 OR is_weekend=1) AND (hour > baseline_latest_hour + 2 OR hour < baseline_avg_hour - baseline_stdev_hour * 2) | stats count, values(hour) AS login_hours, values(day_of_week) AS login_days, values(src_ip) AS source_ips by user, baseline_avg_hour, baseline_latest_hour | where count > 0 | sort - count
Monitor for abnormal file or database access volumes:
splindex=file_access OR index=sharepoint earliest=-24h | stats sum(bytes) AS total_bytes, dc(file_path) AS unique_files, count AS access_count by user | join user type=left [ search index=file_access OR index=sharepoint earliest=-30d latest=-1d | stats avg(eval(count)) AS baseline_avg_files, stdev(eval(count)) AS baseline_stdev_files, avg(eval(sum(bytes))) AS baseline_avg_bytes by user ] | eval bytes_gb = round(total_bytes / 1073741824, 2) | eval z_score_files = round((unique_files - baseline_avg_files) / baseline_stdev_files, 2) | where z_score_files > 3 OR bytes_gb > 5 | eval anomaly_level = case( z_score_files > 5, "CRITICAL", z_score_files > 3, "HIGH", bytes_gb > 10, "CRITICAL", bytes_gb > 5, "HIGH", 1=1, "MEDIUM" ) | sort - z_score_files | table user, unique_files, bytes_gb, baseline_avg_files, z_score_files, anomaly_level
Monitor privileged account usage anomalies:
splindex=wineventlog sourcetype="WinEventLog:Security" (EventCode=4672 OR EventCode=4624 OR EventCode=4648) earliest=-24h | eval is_privileged = if(EventCode=4672, 1, 0) | eval is_explicit_cred = if(EventCode=4648, 1, 0) | stats sum(is_privileged) AS priv_events, sum(is_explicit_cred) AS explicit_cred_events, dc(ComputerName) AS unique_hosts, values(ComputerName) AS hosts_accessed by TargetUserName, src_ip | join TargetUserName type=left [ search index=wineventlog EventCode IN (4672, 4624, 4648) earliest=-30d latest=-1d | stats dc(ComputerName) AS baseline_hosts, avg(eval(count)) AS baseline_daily_events by TargetUserName ] | where unique_hosts > baseline_hosts * 2 OR priv_events > baseline_daily_events * 3 | eval risk_score = (unique_hosts / baseline_hosts * 30) + (priv_events / baseline_daily_events * 20) | sort - risk_score | table TargetUserName, src_ip, unique_hosts, baseline_hosts, priv_events, baseline_daily_events, risk_score, hosts_accessed
Aggregate all UEBA signals into a composite risk score:
spl| inputlookup ueba_impossible_travel.csv | append [| inputlookup ueba_off_hours_access.csv] | append [| inputlookup ueba_data_access_anomaly.csv] | append [| inputlookup ueba_privilege_abuse.csv] | stats sum(risk_points) AS total_risk, values(anomaly_type) AS anomaly_types, dc(anomaly_type) AS anomaly_count by user | lookup identity_lookup_expanded identity AS user OUTPUT department, managedBy, priority AS user_priority | eval final_risk = total_risk * case( user_priority="critical", 2.0, user_priority="high", 1.5, user_priority="medium", 1.0, 1=1, 0.8 ) | sort - final_risk | head 20 | table user, department, managedBy, anomaly_types, anomaly_count, total_risk, final_risk
| Term | Definition | |------|-----------| | UEBA | User and Entity Behavior Analytics — behavioral analysis detecting anomalies against established baselines | | Impossible Travel | Login events from geographically distant locations within timeframes making physical travel impossible | | Behavioral Baseline | Statistical profile of normal user activity patterns built from 30-90 days of historical data | | Z-Score | Statistical measure of how many standard deviations an observation is from the mean — values > 3 indicate anomalies | | Risk Score | Composite numerical score aggregating multiple behavioral anomalies weighted by asset criticality | | Peer Group Analysis | Comparing a user's behavior to others in the same department/role to identify outliers |
UEBA ANOMALY REPORT — Weekly Summary
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Period: 2024-03-11 to 2024-03-17
Users Baselined: 2,847
Anomalies Detected: 23
TOP RISK USERS:
# User Dept Risk Anomalies
1. jsmith Finance 94.5 Impossible travel (NYC->Moscow, 2h), off-hours access, 15GB download
2. admin_svc01 IT Ops 82.0 Login from 12 new IPs, 47 hosts accessed (baseline: 8)
3. mwilson HR 67.3 Off-hours file access (2AM), 3x normal download volume
INVESTIGATION STATUS:
jsmith: Escalated to Tier 2 — possible account compromise (IR-2024-0445)
admin_svc01: Under review — may be new automation deployment (checking with IT Ops)
mwilson: Pending HR context — employee on notice period, monitoring increased| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 21 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.