Generic Splunk queries from documentation and vendor blogs tend to fail the same way in real environments — they're written without knowing your field schema, your log sources, or what "normal" looks like for your user population. The queries below are built from production SOC environments and include the tuning notes that make the difference between a query that runs and a query that actually works.

Environment assumptions

These queries target index=win_* with Windows Security Event Log as the primary source (EventCode=4688 for process creation). Field names follow mixed PascalCase/snake_case as common in enterprise Splunk deployments. Adjust index names and field aliases for your environment.

1. Suspicious Process Creation (4688)

Process creation with command line logging is your highest-value data source for endpoint detection. The query below focuses on the parent-child relationships that matter most — scripting engines spawned from unexpected parents, compilers running outside dev machines, and processes with suspicious command line content.

Splunk SPL — Suspicious process creation
index=win_* (sourcetype="WinEventLog:Security"
  OR source="XmlWinEventLog:Security")
EventCode=4688 earliest=-24h latest=now
| eval parent=lower(coalesce(Parent_Process_Name,
    ParentProcessName, parent_process))
| eval image=lower(coalesce(New_Process_Name,
    ProcessName, process_name))
| eval cmdline=coalesce(Process_Command_Line,
    CommandLine, process)
/* Suspicious parents */
| where match(parent,
    "(winword|excel|outlook|powerpnt|onenote|
    chrome|msedge|firefox|iexplore|mshta|
    rundll32|wscript|cscript)\.exe$")
/* Suspicious children */
| where match(image,
    "(powershell|pwsh|cmd|wscript|cscript|
    mshta|certutil|bitsadmin|regsvr32|
    csc|vbc|cvtres)\.exe$")
/* Exclude known-good management tools */
| where NOT match(parent,
    "(taniumclient|ccmexec|msbuild|
    devenv|onexagentui)\.exe$")
| eval suspicion=case(
    match(cmdline, "(?i)(http|https|\\\\)"), "HIGH",
    match(cmdline, "(?i)Users\\\\.*Downloads"), "HIGH",
    match(cmdline, "(?i)-enc|-encodedcommand"), "HIGH",
    1==1, "MEDIUM")
| table _time host user parent image cmdline suspicion
| sort 0 -_time
Tuning note

The benign parent allowlist (taniumclient, ccmexec, msbuild) is a starting point — your environment will have additional management agents. Add them with ticket references, not just the process name.

2. Credential Access — Brute Force Detection

Splunk SPL — Account brute force (4625)
index=win_* sourcetype="WinEventLog:Security"
EventCode=4625 earliest=-1h latest=now
| eval account=lower(coalesce(Target_Account_Name,
    TargetUserName, user))
| eval src_ip=coalesce(Source_Network_Address,
    IpAddress, src_ip)
| stats
    count as FailedLogins
    dc(src_ip) as SourceIPs
    values(src_ip) as IPList
    values(Failure_Reason) as FailureReasons
    by account host
| where FailedLogins >= 20
| eval SprayIndicator=if(SourceIPs > 5,
    "POSSIBLE_SPRAY", "BRUTE_FORCE")
| sort - FailedLogins

3. Lateral Movement — Pass the Hash / PtT

Splunk SPL — NTLM lateral movement (4624)
index=win_* sourcetype="WinEventLog:Security"
EventCode=4624 Logon_Type=3
Authentication_Package=NTLM
earliest=-24h latest=now
| eval src=coalesce(Source_Network_Address,
    IpAddress, src_ip)
| eval account=lower(coalesce(Target_Account_Name,
    TargetUserName))
/* Exclude machine accounts */
| where NOT match(account, "\$$")
/* Exclude localhost */
| where src != "127.0.0.1"
    AND src != "::1"
    AND src != "-"
| stats
    count as AuthCount
    dc(host) as TargetHosts
    values(host) as TargetHostList
    by account src
| where TargetHosts >= 3
| sort - TargetHosts

4. Data Exfiltration — Large Volume Transfers

Splunk SPL — Outbound data volume anomaly
index=network* earliest=-1h latest=now
| eval bytes_out_mb=round(bytes_out/1048576, 2)
| where bytes_out_mb > 100
/* Exclude known backup/cloud sync destinations */
| where NOT match(dest_ip,
    "(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)")
| lookup geoip dest_ip OUTPUT Country as dest_country
| stats
    sum(bytes_out_mb) as TotalMB
    dc(dest_ip) as UniqueDestinations
    values(dest_country) as Countries
    by src_ip user
| sort - TotalMB

5. Persistence — Scheduled Task Creation

Splunk SPL — Suspicious scheduled task (4698)
index=win_* sourcetype="WinEventLog:Security"
EventCode=4698 earliest=-24h latest=now
| rex field=Task_Content
    "<Command>(?P<task_command>[^<]+)</Command>"
| rex field=Task_Content
    "<Arguments>(?P<task_args>[^<]+)</Arguments>"
| eval suspicious=case(
    match(task_command,
        "(?i)(powershell|cmd|wscript|mshta|regsvr32)"),
    "SUSPICIOUS_BINARY",
    match(task_args,
        "(?i)(http|https|-enc|-encodedcommand)"),
    "SUSPICIOUS_ARGS",
    match(task_command, "(?i)Users\\\\.*Temp"),
    "SUSPICIOUS_PATH",
    1==1, "REVIEW")
| where suspicious != "REVIEW"
| table _time host user
    Task_Name task_command task_args suspicious
| sort 0 -_time
Investigation tip

When a scheduled task fires this alert, immediately pull 4624/4625 events for the same account in the 30 minutes before task creation. Attackers who create persistence tasks almost always authenticate to the host first — that authentication event is often your best pivot for tracing the access path back.

Weekly Intelligence Pack
A new production SPL query every few weeks

The Intelligence Pack rotates across CrowdStrike, Sentinel, and Splunk. Every Splunk issue includes SPL with your exact environment assumptions baked in — index names, field aliases, benign parent allowlists, and the tuning notes that make it work in a real environment rather than a lab.

Join — $14.99/mo SOC Starter Kit — $39
30-day money back · founding member pricing locked for life