Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .claude/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Type this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
skills CLI
$ npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a codex
Project install goes to .agents/skills/; add -g for ~/.codex/skills/.
Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .agents/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a cursor
Project install goes to .agents/skills/; add -g for ~/.cursor/skills/.
Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .cursor/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
skills CLI
$ npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a gemini-cli
Project install goes to .agents/skills/; add -g for ~/.gemini/skills/.
Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .gemini/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Installs for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
skills CLI
$ npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a github-copilot
Project install goes to .agents/skills/; add -g for ~/.copilot/skills/.
Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .github/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
skills CLI
$ npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a opencode
OpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
Install the "detecting-anomalous-authentication-patterns" agent skill from https://github.com/mukul975/Anthropic-Cybersecurity-Skills/tree/main/skills/detecting-anomalous-authentication-patterns into .opencode/skills/detecting-anomalous-authentication-patterns/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "detecting-anomalous-authentication-patterns", then confirm the skill loads.
OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
Facts
Skill name
detecting-anomalous-authentication-patterns
GitHub stars
34k
Token cost
~7.5k tokens
SKILL.md length
641 words
Files
4 (incl. scripts, references)
Skills in repo
644
Repo updated
First seen
Licence
Apache-2.0
At a glance
Detects anomalous authentication patterns using UEBA analytics, statistical baselines, and machine learning models to identify impossible travel, credential stuffing, brute force, password spraying…
Works in 6 steps: Collect and Normalize Authentication Logs → Detect Impossible Travel Anomalies → Detect Brute Force and Password Spraying → …
Tasks that involve Authentication
SKILL.md covers When to Use, Prerequisites, Workflow and Key Concepts, plus 3 more sections
Runs Python scripts from its folder
What it does
Detecting Anomalous Authentication Patterns is an agent skill from mukul975/Anthropic-Cybersecurity-Skills. Detects anomalous authentication patterns using UEBA analytics, statistical baselines, and machine learning models to identify impossible travel, credential stuffing, brute force, password spraying, and compromised account behaviors across authentication logs. Activates for requests involving authentication anomaly detection, login behavior analysis, UEBA implementation, or suspicious sign-in investigation.
Its SKILL.md is about 7.5k tokens, which your agent loads only when the skill is triggered. The skill folder holds 5 other files, including scripts and reference files (for example `references/api-reference.md` and `scripts/agent.py`).
It sits in Data & Analytics, covering Authentication, Anomaly detection and Machine learning. The repository describes itself as: 817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io…. The licence is Apache-2.0.
When your agent uses it
Tasks that involve Authentication
Tasks that involve Anomaly detection
Tasks that involve Machine learning
Example prompts
“Use the detecting-anomalous-authentication-patterns skill to detect anomalous authentication patterns using UEBA analytics, statistical baselines…”
“/detecting-anomalous-authentication-patterns”
Requirements
Python 3
Workflow steps
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 54a7988. It shows what the files ask for, not the result of running them.
Tool permissions
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Runs code
Ships 1 file in scripts/ (Python), which the agent can run.
From the folder's file list and the shell code blocks in SKILL.md.
Network
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Credentials
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Context cost
Detecting Anomalous Authentication Patterns loads about 7.5k tokens when it runs, and up to ~8.1k if it reads all its reference files. Until then it costs about 114 tokens; SKILL.md has 641 words of instructions outside code blocks.
Always· name and description, kept in context so the agent knows when to use it
~114
When it runs· the whole SKILL.md, loaded when a task matches
~7.5k
With references· SKILL.md plus every file in references/, read only if the agent opens them
~8.1k
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
Safety
Auto-check passed
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
Download SKILL.mdSave it as .claude/skills/detecting-anomalous-authentication-patterns/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
detecting-anomalous-authentication-patterns
description
Detects anomalous authentication patterns using UEBA analytics, statistical baselines, and machine learning models to identify impossible travel, credential stuffing, brute force, password spraying, and compromised account behaviors across authentication logs. Activates for requests involving authentication anomaly detection, login behavior analysis, UEBA implementation, or suspicious sign-in investigation.
Security operations needs to identify compromised accounts from authentication log analysis
Implementing impossible travel detection to flag geographically inconsistent logins
Detecting brute force, password spraying, and credential stuffing attacks in real time
Building behavioral baselines for users to identify deviations indicating account compromise
Correlating authentication anomalies with threat intelligence for lateral movement detection
Investigating alerts from SIEM or IdP for suspicious sign-in activity
Do not use for static rule-based alerting on single failed logins; anomaly detection requires statistical baselines across time and entity dimensions to reduce false positives.
Prerequisites
Authentication log sources (Azure AD/Entra ID sign-in logs, Okta system logs, Active Directory event logs 4624/4625/4648/4768/4771)
SIEM platform (Splunk, Microsoft Sentinel, Elastic SIEM) with at least 90 days of baseline data
GeoIP database for location-based anomaly detection (MaxMind GeoLite2 or IP2Location)
Python 3.9+ with pandas, scikit-learn, and scipy for custom analytics
User identity context (department, role, typical work hours, location)
Workflow
Step 1: Collect and Normalize Authentication Logs
Aggregate authentication events from all identity sources:
python
import pandas as pd
import json
from datetime import datetime, timedelta
from collections import defaultdict
# Parse authentication logs from multiple sources
def normalize_auth_logs(log_source, raw_logs):
"""Normalize authentication events to a common schema."""
normalized = []
for event in raw_logs:
if log_source == "azure_ad":
normalized.append({
"timestamp": event["createdDateTime"],
"user": event["userPrincipalName"],
"source_ip": event["ipAddress"],
"location": {
"city": event.get("location", {}).get("city"),
"state": event.get("location", {}).get("state"),
"country": event.get("location", {}).get("countryOrRegion"),
"lat": event.get("location", {}).get("geoCoordinates", {}).get("latitude"),
"lon": event.get("location", {}).get("geoCoordinates", {}).get("longitude")
},
"result": "success" if event["status"]["errorCode"] == 0 else "failure",
"failure_reason": event["status"].get("failureReason", ""),
"app": event.get("appDisplayName", "Unknown"),
"device": event.get("deviceDetail", {}).get("operatingSystem", "Unknown"),
"browser": event.get("deviceDetail", {}).get("browser", "Unknown"),
"mfa_result": event.get("authenticationDetails", [{}])[0].get("succeeded", None),
"risk_level": event.get("riskLevelDuringSignIn", "none"),
"client_app": event.get("clientAppUsed", "Unknown"),
"source": "azure_ad"
})
elif log_source == "okta":
normalized.append({
"timestamp": event["published"],
"user": event["actor"]["alternateId"],
"source_ip": event["client"]["ipAddress"],
"location": {
"city": event["client"].get("geographicalContext", {}).get("city"),
"state": event["client"].get("geographicalContext", {}).get("state"),
"country": event["client"].get("geographicalContext", {}).get("country"),
"lat": event["client"].get("geographicalContext", {}).get("geolocation", {}).get("lat"),
"lon": event["client"].get("geographicalContext", {}).get("geolocation", {}).get("lon")
},
"result": "success" if event["outcome"]["result"] == "SUCCESS" else "failure",
"failure_reason": event["outcome"].get("reason", ""),
"app": event.get("target", [{}])[0].get("displayName", "Unknown"),
"device": event["client"].get("device", "Unknown"),
"browser": event["client"].get("userAgent", {}).get("browser", "Unknown"),
"source": "okta"
})
elif log_source == "windows_ad":
normalized.append({
"timestamp": event["TimeCreated"],
"user": event["TargetUserName"],
"source_ip": event.get("IpAddress", ""),
"location": None, # Requires GeoIP enrichment
"result": "success" if event["EventId"] in [4624, 4648] else "failure",
"failure_reason": event.get("FailureReason", ""),
"logon_type": event.get("LogonType", ""),
"source": "windows_ad"
})
return pd.DataFrame(normalized)
# Enrich with GeoIP data for Windows AD logs missing location
import geoip2.database
def enrich_geoip(df, geoip_db_path="/opt/geoip/GeoLite2-City.mmdb"):
"""Add geolocation data to events missing location information."""
reader = geoip2.database.Reader(geoip_db_path)
for idx, row in df.iterrows():
if row["location"] is None and row["source_ip"]:
try:
response = reader.city(row["source_ip"])
df.at[idx, "location"] = {
"city": response.city.name,
"country": response.country.iso_code,
"lat": response.location.latitude,
"lon": response.location.longitude
}
except Exception:
pass
reader.close()
return df
Step 2: Detect Impossible Travel Anomalies
Identify logins from geographically impossible locations:
python
from math import radians, sin, cos, sqrt, atan2
from datetime import datetime
def haversine_distance(lat1, lon1, lat2, lon2):
"""Calculate great-circle distance between two points in km."""
R = 6371 # Earth's radius in kilometers
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
dlat = lat2 - lat1
dlon = lon2 - lon1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
return R * c
def detect_impossible_travel(df, max_speed_kmh=900):
"""
Detect impossible travel events where a user authenticates from
two locations faster than physically possible.
max_speed_kmh: Maximum realistic travel speed (900 km/h ~= commercial flight)
"""
alerts = []
# Sort by user and timestamp
df_sorted = df.sort_values(["user", "timestamp"])
for user, user_events in df_sorted.groupby("user"):
successful_events = user_events[user_events["result"] == "success"]
for i in range(1, len(successful_events)):
prev = successful_events.iloc[i-1]
curr = successful_events.iloc[i]
# Skip if location data is missing
if not prev.get("location") or not curr.get("location"):
continue
if not prev["location"].get("lat") or not curr["location"].get("lat"):
continue
# Calculate distance and time delta
distance_km = haversine_distance(
prev["location"]["lat"], prev["location"]["lon"],
curr["location"]["lat"], curr["location"]["lon"]
)
time_diff = (pd.Timestamp(curr["timestamp"]) -
pd.Timestamp(prev["timestamp"])).total_seconds() / 3600
if time_diff <= 0:
continue
required_speed = distance_km / time_diff
# Flag if required speed exceeds maximum realistic travel
if required_speed > max_speed_kmh and distance_km > 100:
alerts.append({
"alert_type": "IMPOSSIBLE_TRAVEL",
"severity": "HIGH",
"user": user,
"timestamp": curr["timestamp"],
"details": {
"location_1": f"{prev['location']['city']}, {prev['location']['country']}",
"location_2": f"{curr['location']['city']}, {curr['location']['country']}",
"time_1": prev["timestamp"],
"time_2": curr["timestamp"],
"distance_km": round(distance_km, 1),
"time_hours": round(time_diff, 2),
"required_speed_kmh": round(required_speed, 1),
"source_ip_1": prev["source_ip"],
"source_ip_2": curr["source_ip"]
}
})
return alerts
# Run impossible travel detection
travel_alerts = detect_impossible_travel(auth_df)
print(f"Impossible travel alerts: {len(travel_alerts)}")
for alert in travel_alerts:
print(f" [{alert['severity']}] {alert['user']}: "
f"{alert['details']['location_1']} -> {alert['details']['location_2']} "
f"({alert['details']['distance_km']} km in {alert['details']['time_hours']}h)")
Step 3: Detect Brute Force and Password Spraying
Identify credential attack patterns across authentication logs:
python
from collections import Counter
def detect_brute_force(df, threshold_failures=10, window_minutes=10):
"""
Detect brute force attacks: many failed attempts against
a single account in a short time window.
"""
alerts = []
failed = df[df["result"] == "failure"].copy()
failed["timestamp"] = pd.to_datetime(failed["timestamp"])
for user, user_fails in failed.groupby("user"):
user_fails_sorted = user_fails.sort_values("timestamp")
# Sliding window analysis
for i, row in user_fails_sorted.iterrows():
window_start = row["timestamp"]
window_end = window_start + timedelta(minutes=window_minutes)
window_events = user_fails_sorted[
(user_fails_sorted["timestamp"] >= window_start) &
(user_fails_sorted["timestamp"] <= window_end)
]
if len(window_events) >= threshold_failures:
source_ips = window_events["source_ip"].unique()
alerts.append({
"alert_type": "BRUTE_FORCE",
"severity": "HIGH",
"user": user,
"timestamp": str(window_start),
"details": {
"failed_attempts": len(window_events),
"window_minutes": window_minutes,
"source_ips": list(source_ips),
"distributed": len(source_ips) > 1,
"failure_reasons": dict(Counter(window_events["failure_reason"]))
}
})
break # One alert per user per detection pass
return alerts
def detect_password_spray(df, threshold_users=10, window_minutes=30):
"""
Detect password spraying: failed logins against many different
accounts from the same source in a short window (1-2 attempts per user).
"""
alerts = []
failed = df[df["result"] == "failure"].copy()
failed["timestamp"] = pd.to_datetime(failed["timestamp"])
for source_ip, ip_events in failed.groupby("source_ip"):
ip_events_sorted = ip_events.sort_values("timestamp")
for i, row in ip_events_sorted.iterrows():
window_start = row["timestamp"]
window_end = window_start + timedelta(minutes=window_minutes)
window_events = ip_events_sorted[
(ip_events_sorted["timestamp"] >= window_start) &
(ip_events_sorted["timestamp"] <= window_end)
]
unique_users = window_events["user"].nunique()
attempts_per_user = len(window_events) / unique_users if unique_users > 0 else 0
# Password spray: many users targeted, few attempts per user
if unique_users >= threshold_users and attempts_per_user <= 3:
# Check if any succeeded (compromised account)
success_after = df[
(df["source_ip"] == source_ip) &
(df["result"] == "success") &
(pd.to_datetime(df["timestamp"]) > window_start) &
(pd.to_datetime(df["timestamp"]) < window_end + timedelta(hours=1))
]
alerts.append({
"alert_type": "PASSWORD_SPRAY",
"severity": "CRITICAL" if len(success_after) > 0 else "HIGH",
"timestamp": str(window_start),
"details": {
"source_ip": source_ip,
"targeted_users": unique_users,
"total_attempts": len(window_events),
"avg_attempts_per_user": round(attempts_per_user, 1),
"window_minutes": window_minutes,
"successful_logins_after": len(success_after),
"compromised_accounts": list(success_after["user"].unique()) if len(success_after) > 0 else []
}
})
break
return alerts
# Run detections
brute_force_alerts = detect_brute_force(auth_df)
spray_alerts = detect_password_spray(auth_df)
print(f"Brute force alerts: {len(brute_force_alerts)}")
print(f"Password spray alerts: {len(spray_alerts)}")
Step 4: Build Behavioral Baselines and Detect Deviations
Create user behavioral profiles and flag statistical anomalies:
python
import numpy as np
from scipy import stats
from sklearn.ensemble import IsolationForest
def build_user_baseline(df, user, lookback_days=90):
"""Build behavioral baseline for a specific user."""
user_events = df[df["user"] == user].copy()
user_events["timestamp"] = pd.to_datetime(user_events["timestamp"])
user_events["hour"] = user_events["timestamp"].dt.hour
user_events["day_of_week"] = user_events["timestamp"].dt.dayofweek
baseline = {
"user": user,
"typical_hours": {
"start": int(user_events["hour"].quantile(0.05)),
"end": int(user_events["hour"].quantile(0.95)),
"mean": float(user_events["hour"].mean()),
"std": float(user_events["hour"].std())
},
"typical_days": list(user_events["day_of_week"].mode().values),
"typical_ips": list(user_events["source_ip"].value_counts().head(10).index),
"typical_locations": list(
user_events["location"].apply(
lambda x: x.get("country") if isinstance(x, dict) else None
).dropna().value_counts().head(5).index
),
"typical_apps": list(user_events["app"].value_counts().head(10).index),
"typical_devices": list(user_events["device"].value_counts().head(5).index),
"avg_daily_logins": float(
user_events.groupby(user_events["timestamp"].dt.date).size().mean()
),
"std_daily_logins": float(
user_events.groupby(user_events["timestamp"].dt.date).size().std()
),
"failure_rate": float(
(user_events["result"] == "failure").mean()
)
}
return baseline
def detect_behavioral_anomalies(event, baseline):
"""Compare a new authentication event against user baseline."""
anomalies = []
event_time = pd.Timestamp(event["timestamp"])
# Off-hours login detection
hour = event_time.hour
if baseline["typical_hours"]["std"] > 0:
z_score = abs(hour - baseline["typical_hours"]["mean"]) / baseline["typical_hours"]["std"]
if z_score > 2.5:
anomalies.append({
"type": "OFF_HOURS_LOGIN",
"severity": "MEDIUM",
"detail": f"Login at {hour}:00 (baseline: {baseline['typical_hours']['start']}:00-{baseline['typical_hours']['end']}:00)",
"z_score": round(z_score, 2)
})
# New source IP
if event["source_ip"] not in baseline["typical_ips"]:
anomalies.append({
"type": "NEW_SOURCE_IP",
"severity": "MEDIUM",
"detail": f"Login from unknown IP: {event['source_ip']}"
})
# New country
if event.get("location") and isinstance(event["location"], dict):
country = event["location"].get("country")
if country and country not in baseline["typical_locations"]:
anomalies.append({
"type": "NEW_COUNTRY",
"severity": "HIGH",
"detail": f"Login from new country: {country}"
})
# New application
if event.get("app") and event["app"] not in baseline["typical_apps"]:
anomalies.append({
"type": "NEW_APPLICATION",
"severity": "LOW",
"detail": f"Access to new application: {event['app']}"
})
# New device
if event.get("device") and event["device"] not in baseline["typical_devices"]:
anomalies.append({
"type": "NEW_DEVICE",
"severity": "MEDIUM",
"detail": f"Login from new device: {event['device']}"
})
# Weekend login for weekday-only users
if event_time.dayofweek >= 5 and 5 not in baseline["typical_days"] and 6 not in baseline["typical_days"]:
anomalies.append({
"type": "WEEKEND_LOGIN",
"severity": "LOW",
"detail": f"Weekend login detected (typical days: {baseline['typical_days']})"
})
return anomalies
def isolation_forest_anomaly_detection(df):
"""Use Isolation Forest for multivariate anomaly detection."""
# Feature engineering
features_df = df.copy()
features_df["timestamp"] = pd.to_datetime(features_df["timestamp"])
features_df["hour"] = features_df["timestamp"].dt.hour
features_df["day_of_week"] = features_df["timestamp"].dt.dayofweek
features_df["is_failure"] = (features_df["result"] == "failure").astype(int)
# Encode categorical features
features_df["ip_frequency"] = features_df.groupby("source_ip")["source_ip"].transform("count")
features_df["user_frequency"] = features_df.groupby("user")["user"].transform("count")
feature_columns = ["hour", "day_of_week", "is_failure", "ip_frequency", "user_frequency"]
X = features_df[feature_columns].fillna(0)
# Train Isolation Forest
model = IsolationForest(
n_estimators=200,
contamination=0.01, # Expect 1% anomaly rate
random_state=42,
n_jobs=-1
)
features_df["anomaly_score"] = model.fit_predict(X)
features_df["anomaly_probability"] = model.score_samples(X)
# Extract anomalies (labeled as -1)
anomalies = features_df[features_df["anomaly_score"] == -1]
return anomalies.sort_values("anomaly_probability")
Step 5: Implement SIEM Detection Rules
Deploy detection rules for common authentication attack patterns:
yaml
# Splunk SPL queries for authentication anomaly detection
# 1. Brute Force Detection
# name: Authentication Brute Force - Multiple Failed Logins
# severity: high
brute_force_spl: |
index=auth sourcetype IN ("azure:aad:signin", "okta:im:log", "WinEventLog:Security")
(result="failure" OR EventCode=4625)
| bin _time span=10m
| stats count as failed_attempts dc(src_ip) as unique_ips
values(src_ip) as source_ips
latest(_time) as last_attempt
by user _time
| where failed_attempts >= 10
| eval alert_type=if(unique_ips > 3, "Distributed Brute Force", "Standard Brute Force")
# 2. Password Spray Detection
# name: Password Spray Attack - Multiple Users Same Source
# severity: critical
password_spray_spl: |
index=auth sourcetype IN ("azure:aad:signin", "okta:im:log")
result="failure"
| bin _time span=30m
| stats dc(user) as targeted_users count as total_attempts
values(user) as users_targeted
by src_ip _time
| where targeted_users >= 10
| eval attempts_per_user = round(total_attempts / targeted_users, 1)
| where attempts_per_user <= 3
| eval severity=if(targeted_users > 50, "CRITICAL", "HIGH")
# 3. Impossible Travel Detection
# name: Impossible Travel - Geographically Inconsistent Logins
# severity: high
impossible_travel_spl: |
index=auth result="success"
| 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
by user
| where isnotnull(prev_lat) AND isnotnull(lat)
| eval distance_km = 6371 * 2 * asin(sqrt(
pow(sin((lat - prev_lat) * pi() / 360), 2) +
cos(prev_lat * pi() / 180) * cos(lat * pi() / 180) *
pow(sin((lon - prev_lon) * pi() / 360), 2)))
| eval time_hours = (_time - prev_time) / 3600
| eval required_speed = distance_km / time_hours
| where required_speed > 900 AND distance_km > 100
# 4. Credential Stuffing Detection
# name: Credential Stuffing - High Volume Failed Logins with Some Successes
# severity: critical
credential_stuffing_spl: |
index=auth
| bin _time span=1h
| stats count(eval(result="failure")) as failures
count(eval(result="success")) as successes
dc(user) as unique_users
dc(src_ip) as unique_ips
by src_ip _time
| where failures > 100 AND successes > 0 AND unique_users > 20
| eval success_rate = round(successes / (failures + successes) * 100, 2)
| where success_rate < 5
Step 6: Correlate and Score Authentication Anomalies
Combine multiple detection signals into risk scores:
Authentication anomaly where a user logs in from two geographically distant locations within a timeframe that makes physical travel impossible
Password Spraying
Credential attack that tries a small number of commonly used passwords against many accounts to avoid lockout thresholds
Credential Stuffing
Automated attack using stolen username/password pairs from data breaches to gain unauthorized access to accounts
UEBA
User and Entity Behavior Analytics technology that builds behavioral baselines and detects deviations using machine learning and statistical analysis
Behavioral Baseline
Statistical profile of a user's normal authentication patterns including typical hours, locations, devices, and applications
Isolation Forest
Unsupervised machine learning algorithm that detects anomalies by isolating observations that differ from the majority of data points
Risk Score
Composite numerical value aggregating multiple anomaly signals with weighted scoring to prioritize authentication threats
Show full SKILL.md (263 more words)Show less
Tools & Systems
Microsoft Sentinel UEBA: Cloud-native SIEM with built-in entity behavior analytics for Azure AD and multi-cloud authentication anomaly detection
Exabeam Advanced Analytics: UEBA platform using machine learning for user session analysis and automated threat timeline construction
Splunk UBA: Behavioral analytics add-on for Splunk providing pre-built authentication anomaly models and risk scoring
Elastic SIEM ML Jobs: Machine learning anomaly detection jobs for authentication log analysis in the Elastic Stack
Common Scenarios
Scenario: Detecting Compromised Executive Account After Password Spray
Context: SOC observes a spike in failed authentication attempts from a cloud VPS IP address targeting 200+ accounts. Two hours later, an executive account shows successful authentication from the same IP range followed by mailbox rule creation and data exfiltration.
Approach:
Run password spray detection across the timeframe to identify all targeted accounts
Cross-reference targeted accounts with subsequent successful logins from related IP ranges
Build behavioral baseline for the executive account and flag all deviations
Check for impossible travel between the executive's last legitimate login and the attacker's session
Detecting Anomalous Authentication Patterns next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
Detecting Anomalous Authentication Patterns compared with similar skills
Skill
Stars
Used in
Tokens
Auto-check
Licence
Repo updated
Detecting Anomalous Authentication Patterns this skillmukul975/Anthropic-Cybersecurity-Skills
Build a new time-series analytics use case on top of the deployed Time Series Analytics microservice — bring it up with Docker Compose (from a repo clone, or by fetching the compose files from…
Guides time series machine learning with the aeon toolkit: classification, regression, clustering, forecasting, anomaly detection, segmentation and similarity search.
A skill your agent uses when the user asks for a WorkOS docs URL, term, or dashboard field (Sign-in endpoint, initiateloginuri, Redirect URI, WORKOS env vars), or is implementing, debugging, or…
Walks through reverse engineering Go-compiled malware in Ghidra: parsing buildinfo and pclntab, recovering stripped function names and extracting dependencies.
Detects DNS tunneling, ICMP exfiltration and HTTP-based covert channels in packet captures and DNS logs when hunting for hidden command-and-control traffic.
Questions about Detecting Anomalous Authentication Patterns
What does Detecting Anomalous Authentication Patterns do?
Detects anomalous authentication patterns using UEBA analytics, statistical baselines, and machine learning models to identify impossible travel, credential stuffing, brute force, password spraying…. Detecting Anomalous Authentication Patterns is an agent skill from mukul975/Anthropic-Cybersecurity-Skills. Detects anomalous authentication patterns using UEBA analytics, statistical baselines, and machine learning models to identify impossible travel, credential stuffing, brute force, password spraying, and compromised account behaviors across authentication logs.
When should I use Detecting Anomalous Authentication Patterns?
Detecting Anomalous Authentication Patterns fits situations like: tasks that involve Authentication; tasks that involve Anomaly detection; tasks that involve Machine learning.
How do I install Detecting Anomalous Authentication Patterns in Claude Code?
Run `npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a claude-code`. Or copy the skill folder (skills/detecting-anomalous-authentication-patterns in mukul975/Anthropic-Cybersecurity-Skills) into .claude/skills/detecting-anomalous-authentication-patterns in your project. Claude Code loads it when a task matches its description.
How do I install Detecting Anomalous Authentication Patterns in Codex?
Run `npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a codex`. Or copy the skill folder (skills/detecting-anomalous-authentication-patterns in mukul975/Anthropic-Cybersecurity-Skills) into .agents/skills/detecting-anomalous-authentication-patterns in your project. Codex loads it when a task matches its description.
Can I use Detecting Anomalous Authentication Patterns in Cursor, Gemini CLI or GitHub Copilot?
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add mukul975/Anthropic-Cybersecurity-Skills --skill detecting-anomalous-authentication-patterns -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/detecting-anomalous-authentication-patterns, .gemini/skills/detecting-anomalous-authentication-patterns, .github/skills/detecting-anomalous-authentication-patterns and .opencode/skills/detecting-anomalous-authentication-patterns in your project.
What does Detecting Anomalous Authentication Patterns need to run?
Going by SKILL.md and its folder, Detecting Anomalous Authentication Patterns needs Python for the scripts in its folder. Our summary lists: Python 3.
Does Detecting Anomalous Authentication Patterns access the network?
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Is Detecting Anomalous Authentication Patterns safe to install?
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
What licence does Detecting Anomalous Authentication Patterns use?
Detecting Anomalous Authentication Patterns is published under the Apache-2.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
How many tokens does Detecting Anomalous Authentication Patterns use?
About 7.5k tokens (SKILL.md is roughly 30k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 595 tokens, read only when the agent opens those files.
What are the alternatives to Detecting Anomalous Authentication Patterns?
Skills that share tags, products or a category with Detecting Anomalous Authentication Patterns: Time Series Analytics User (open-edge-platform/edge-ai-libraries, 169 stars), Aeon Time Series Machine Learning (davila7/claude-code-templates, 32k stars), Automl Skill (LeoYeAI/openclaw-master-skills, 2.2k stars) and Oci Data Science (oracle/accelerated-data-science, 125 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Who maintains Detecting Anomalous Authentication Patterns?
mukul975 (a GitHub user) maintains it in mukul975/Anthropic-Cybersecurity-Skills, which has 33,993 GitHub stars. The repository holds 644 skills in this directory. The repository was last updated on August 31, 2026.