Response playbooks, investigation guides, and Atomic Red Team tests are Pro-only. Upgrade to unlock the full detection package for THREAT-Recon-CredentialStuffingValidationSweep.

Upgrade to Pro
THREAT-Recon-CredentialStuffingValidationSweep Microsoft Sentinel · KQL

Detect Credential Stuffing Validation Sweep (Pre-Attack Breach List Testing) in Microsoft Sentinel

Before committing to an intrusion, many adversaries first validate which entries in a purchased or scraped breach-credential list (combo list) are still live against the target's own authentication endpoints. This reconnaissance activity is distinct from brute force or password spraying: the attacker tries exactly one attacker-supplied username/password pair per account — never guessing or repeating passwords across identities — and deliberately throttles request volume to stay under per-account lockout and rate-limiting thresholds. The result is a low-and-slow sweep touching a very large number of distinct, often unrelated identities (many of which do not even exist in the target directory) from a small pool of shared infrastructure (bulletproof VPS, residential proxy pools, or credential-checker tooling such as OpenBullet/SentryMBA configs) using automation-flavoured or generic user agents. Initial access brokers and groups like Scattered Spider/Muddled Libra routinely run this validation step across many organisations' SSO and webmail portals to build a list of confirmed-working credentials before selling or acting on access. Because no individual account sees more than one or two failures, this activity is invisible to lockout policies and easily missed by detections tuned for classic brute force or spray, making the attempts-per-user ratio and aggregate breadth across a single source the key signals.

MITRE ATT&CK

Tactic
Reconnaissance

KQL Detection Query

Microsoft Sentinel (KQL)
kusto
// THREAT: Credential Stuffing Validation Sweep (Pre-Attack Recon, T1589.001)
// Detects low-and-slow single-attempt-per-account testing of breached credential lists.
// Distinct from password spray (few passwords x many users) and brute force (many
// passwords x one user): here each account sees ~1 attempt with a unique attacker-supplied
// credential pair, spread thin to evade lockout/rate-limit thresholds.
// Sources: AADSignInLogs / SigninLogs (Entra ID)

// Alert 1: Single source testing many distinct accounts at ~1 attempt each
let SweepWindow = 6h;
let MinUniqueUsers = 50;
let MaxAttemptsPerUserRatio = 1.3;
AADSignInLogs
| where TimeGenerated > ago(SweepWindow)
| where ResultType != 0
| summarize
    TotalAttempts=count(),
    UniqueUsers=dcount(UserPrincipalName),
    UserNotFoundCount=countif(ResultType == 50034),
    InvalidPasswordCount=countif(ResultType == 50126),
    UserAgents=make_set(UserAgent),
    Apps=make_set(AppDisplayName)
  by IPAddress, bin(TimeGenerated, SweepWindow)
| extend AttemptsPerUser = round(TotalAttempts * 1.0 / UniqueUsers, 2)
| where UniqueUsers >= MinUniqueUsers and AttemptsPerUser <= MaxAttemptsPerUserRatio
| extend UserNotFoundRatio = round(UserNotFoundCount * 1.0 / TotalAttempts, 2)
| extend ThreatType = "CredentialValidationSweep_LowAndSlow"
| extend Severity = iff(UniqueUsers >= 500, "High", "Medium")
| sort by UniqueUsers desc;
// Alert 2: A validated (working) breached credential found within a sweep
let SweepIPs = AADSignInLogs
| where TimeGenerated > ago(SweepWindow)
| where ResultType != 0
| summarize TotalAttempts=count(), UniqueUsers=dcount(UserPrincipalName)
  by IPAddress, bin(TimeGenerated, SweepWindow)
| extend AttemptsPerUser = round(TotalAttempts * 1.0 / UniqueUsers, 2)
| where UniqueUsers >= MinUniqueUsers and AttemptsPerUser <= MaxAttemptsPerUserRatio
| distinct IPAddress;
AADSignInLogs
| where TimeGenerated > ago(SweepWindow)
| where ResultType == 0
| where IPAddress in (SweepIPs)
| project TimeGenerated, UserPrincipalName, IPAddress, Location, AppDisplayName, UserAgent
| extend ThreatType = "CredentialValidationSweep_ConfirmedValidCredential"
| extend Severity = "Critical"
high severity medium confidence

Two-stage detection: (1) a single source IP producing authentication failures against 50+ distinct accounts within a 6-hour window at an attempts-per-user ratio at or below 1.3 — the hallmark of one-shot credential-list validation rather than repeated guessing; (2) any successful sign-in from an IP already flagged as running a validation sweep, indicating a breached credential pair was confirmed valid and is now a live risk of account takeover.

Data Sources

Azure AD Sign-In Logs (AADSignInLogs)Microsoft 365 Defender Sign-In ActivityAzure Sentinel UEBA

Required Tables

AADSignInLogs

False Positives & Tuning

  • Bulk onboarding or contractor provisioning scripts that authenticate many new accounts once each from a shared automation host
  • Federation or identity-sync jobs (e.g. AD Connect health checks) that touch many accounts with a single validation call from one service IP
  • Security awareness or credential-hygiene audits run by the organisation's own IT/security team testing which employee passwords were exposed in a public breach
  • Load-balanced SaaS integration platforms authenticating on behalf of many tenant users from a shared egress IP

Other platforms for THREAT-Recon-CredentialStuffingValidationSweep


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1Low-and-Slow Credential Sweep Simulation via Python Requests

    Expected signal: Authentication logs record one failure per distinct username from the test source IP, spread across the run duration, with no repeated attempts against the same account.

  2. Test 2Credential Checker Tool Simulation (OpenBullet-style Config Replay)

    Expected signal: Web/IdP access logs show sequential single-attempt authentication requests from one source IP with a non-browser user agent string, one distinct username per request.

  3. Test 3Validated Credential Success Injection

    Expected signal: A successful authentication event is recorded from the same source IP that generated the preceding sweep failures.

Unlock playbooks & atomic tests with Pro

Get the full detection package for THREAT-Recon-CredentialStuffingValidationSweep — response playbook and atomic red team tests, plus investigation guidance and hunting queries.

df00tech Pro — £29/user/month

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections