Identity Reuse and Payroll-Fraud Indicators
Identity / cloud
Behavioral Hunt low DPRK IT Worker FraudLaptop Farm
Shared bank details across employees who should have nothing in common, plus rapid post-hire direct-deposit changes, corroborated against sign-in geography.
What this hunt looks for
Facilitator-run schemes use stolen or knowingly loaned United States identities to pass background and employment-eligibility checks, then route payroll through facilitator-controlled accounts and reuse a small set of financial and mailing details across what appear to the employer as distinct hired individuals. Christina Chapman's operation alone used sixty-eight stolen American identities to place workers at 309 companies.
This is an HR and IT-operations correlation hunt rather than an endpoint or network one. It looks for shared routing and account numbers across distinct employee records and rapid post-hire direct-deposit changes, corroborated by sign-in telemetry inconsistent with the claimed location. Mandiant's related control, requiring a United States bank account, raises the verification bar.
- Technique
- Fraudulently obtained employment and valid-account misuse (MITRE ATT&CK T1078) combined with financial-identity reuse; not a file or network indicator hunt.
- Data sources
- HRIS and payroll records, Identity provider sign-in logs
- Last updated
- 2026-10-04
Logic
Every query below implements these steps, so the same hunt returns the same result in each product.
- Collect: HRIS and payroll records per employee, and successful identity-provider sign-ins from the last 30 days
- Match: two or more employee records share one bank routing and account number
- Match: or two or more employee records share a mailing address
- Match: or the direct-deposit account was changed within 45 days of the hire date
- Report: each flagged employee with the signals hit and sign-in countries other than the claimed country, shared bank details first
Queries
Defender / Sentinel KQL
Written for this site, from indicators reported by Department of Justice, MandiantEmployees returned either share bank details with a colleague or changed deposit details within 45 days of hire, and OtherCountries shows where else they signed in, so verify the identity manually.
// HRPayroll is a placeholder for the HRIS table you ingest: EmployeeId, UserPrincipalName, HireDate, ClaimedLocationCountry, BankRouting, BankAccount, MailingAddress, DirectDepositChangedOn.
let Payroll = HRPayroll
| extend BankKey = strcat(BankRouting, ":", BankAccount), AddressKey = tolower(trim(@"\s+", MailingAddress));
let Countries = SigninLogs
| where TimeGenerated > ago(30d) and ResultType == "0"
| summarize SignInCountries = make_set(tostring(LocationDetails.countryOrRegion)) by UserPrincipalName;
Payroll
| lookup kind=leftouter (Payroll | summarize BankEmployees = dcount(EmployeeId) by BankKey) on BankKey
// optional: shared mailing address, the line below and the matching line in the where clause
| lookup kind=leftouter (Payroll | summarize AddressEmployees = dcount(EmployeeId) by AddressKey) on AddressKey
| extend EarlyDepositChange = DirectDepositChangedOn between (HireDate .. (HireDate + 45d))
| where BankEmployees > 1 or EarlyDepositChange
// optional: shared mailing address, the line below
or AddressEmployees > 1
| lookup kind=leftouter Countries on UserPrincipalName
| extend OtherCountries = set_difference(SignInCountries, pack_array(ClaimedLocationCountry))
| project-away BankRouting, BankAccount, MailingAddress, BankKey, AddressKey, SignInCountries
| order by BankEmployees desc, HireDate desc
Lower-fidelity parts (2)
- the shared mailing address clause (KQL) — family members, flatmates and apartment blocks legitimately share an address, so it raises more noise than bank details do. Remove: delete each // optional: comment line together with the single line beneath it (the AddressEmployees lookup and the or AddressEmployees > 1 line)
- the 45-day direct-deposit window — a new hire who moves or opens a local account changes deposit details early without any fraud. Remove: delete the EarlyDepositChange extend line and change the where clause to start with where BankEmployees > 1
Splunk SPL
Written for this site, from indicators reported by Department of Justice, MandiantThe same signals from the payroll lookup, with sign-in countries taken from the Authentication data model and compared to the claimed country.
```Placeholders: payroll_records.csv is the HRIS export (employee_id, user, hire_time, claimed_country, bank_routing_number, bank_account_number, mailing_address, direct_deposit_changed_time, all epoch times). Sign-ins come from the Authentication data model.```
| inputlookup payroll_records.csv
| eventstats dc(employee_id) AS bank_employees BY bank_routing_number, bank_account_number
```optional: shared mailing address, the line below and the matching line in the where clause```
| eventstats dc(employee_id) AS address_employees BY mailing_address
| eval early_deposit_change=if(isnotnull(direct_deposit_changed_time) AND direct_deposit_changed_time>=hire_time AND direct_deposit_changed_time<=hire_time+45*86400, 1, 0)
| where bank_employees>1 OR early_deposit_change=1
```optional: shared mailing address, the line below```
OR address_employees>1
| join type=left user
[| tstats count FROM datamodel=Authentication.Authentication WHERE Authentication.action=success earliest=-30d BY Authentication.user, Authentication.src
| rename Authentication.user AS user, Authentication.src AS src_ip
| iplocation src_ip
| stats values(Country) AS signin_countries BY user]
| eval other_countries=mvmap(signin_countries, if(signin_countries!=claimed_country, signin_countries, null()))
| fields - bank_routing_number, bank_account_number, mailing_address, signin_countries
| sort - bank_employees, - hire_time
Lower-fidelity parts (2)
- the shared mailing address clause (SPL) — family members, flatmates and apartment blocks legitimately share an address, so it raises more noise than bank details do. Remove: delete each optional comment line together with the single line beneath it (the address_employees eventstats and the OR address_employees>1 line)
- the 45-day direct-deposit window — a new hire who moves or opens a local account changes deposit details early without any fraud. Remove: delete the early_deposit_change eval line and change the where clause to start with where bank_employees>1
False positives and tuning
Shared bank details occur legitimately between family members and on joint accounts, and an early direct-deposit change is often a local account opened after moving. Every match needs manual identity verification.
The queries assume a custom HR table or lookup with the columns named in their first comment; adapt them to the HRIS export actually ingested. Handling payroll data this way carries jurisdiction-specific privacy obligations; settle them with counsel first.
Sources
- Arizona Woman Sentenced for $17M Information Technology Worker Fraud Scheme that Illegally Generated Revenue for North Korea — U.S. Department of Justice, U.S. Attorney's Office for the District of Columbia, 2025-07-24
- Two North Korean Nationals and Three Facilitators Indicted for Multi-Year Fraudulent Remote Information Technology Worker Scheme that Generated Revenue for the Democratic People's Republic of Korea — U.S. Department of Justice, Office of Public Affairs, 2025-01-23
- Staying a Step Ahead: Mitigating the DPRK IT Worker Threat — Google Cloud (Mandiant), 2024-09-23