siem-query — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited siem-query (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Performance discipline: a correct query that does not return in reasonable time is operationally unusable. A lot of SOC time is lost in queries that scan unnecessarily much data. The second half of this skill is performance discipline, not just syntax.
This skill is the tooling substrate underneath detection-engineer (rules), log-triage (incident investigation), threat-hunt (proactive), and ioc-hunter (enrichment queries).
Triggers on:
detection-engineer, alert-tuning. This skill provides query building blocks; those skills handle the lifecycle.log-triage. This skill provides the query; that one analyses the result.ioc-hunter.threat-hunt (command).forensics-assist.Six phases. Phase 3 (cross-translation) and phase 4 (performance) are where SIEM time really sits.
Three mainstream platforms in most organizations:
Other stacks: IBM QRadar (AQL), Sumo Logic, Chronicle (YARA-L), Devo. Concepts overlap, syntax differs.
For each query task, the first question: which platform is the target? Which retention window? Which data model? Which time zone in the events?
The canonical shapes per platform:
Splunk SPL:
index=cloudtrail eventName=ConsoleLogin
| where 'additionalEventData.MFAUsed'="No"
| stats count by userIdentity.userName, sourceIPAddress
| where count > 5Pipeline mindset: filter first (index=, sourcetype=), then transform (stats, eval, lookup), then present (table, chart).
Powerful features: tstats (data-model acceleration), transaction (event correlation), dedup, streamstats (running aggregates), lookup (CSV/KV-store enrichment), metasearch (metadata only, faster).
Sentinel/Defender KQL:
SigninLogs
| where ResultType == 0 and AppDisplayName == "Office 365"
| where ConditionalAccessStatus == "success"
| summarize SignInCount = count() by UserPrincipalName, IPAddress, bin(TimeGenerated, 1h)
| where SignInCount > 10Pipeline here too (|-style). Strengths: summarize with bin() for time bucketing, join kind= for different join types, let for variables, materialize for caching.
Multi-table join: union, join, lookup. ASIM (Advanced SIEM Information Model) for cross-source normalization.
Elastic EQL (sequence-aware):
sequence by host.id with maxspan=5m
[process where event.action == "fork" and process.name == "bash"]
[network where event.action == "connection_attempted" and destination.port == 4444]EQL is unique in its out-of-the-box support for event sequences. For ad-hoc searching, KQL/Lucene/ESQL is more practical.
Consistent ECS field names: event.action, process.name, host.id, user.name. Migration of non-ECS data is a separate task.
The three languages are semantically similar but differ in syntax. Pattern per category:
| Concept | SPL | KQL | EQL/KQL-Elastic | |
|---|---|---|---|---|
| Filter exact | field="value" | field == "value" | field == "value" | |
| Wildcard | field=value* | field has "value" | field : value* | |
| Negation | NOT field=val | field != "val" | not field == "val" | |
| Time bucket | bin _time span=1h | bin(TimeGenerated, 1h) | histogram(@timestamp, fixed_interval=1h) | |
| Group-by-count | stats count by field | summarize count() by field | aggregations API | |
| Distinct count | dc(field) | dcount(field) | cardinality | |
| Top-N | top N field | top N by count_ | top-hits | |
| Join | join field [...] | `T1 \ | join T2 on field` | enrich pipeline |
| Lookup | lookup file field | lookup table on field | enrich processor |
sigma-cli with the right backend (see detection-engineer) automates much of this. The reviewer role remains: check edge cases (field-name mapping, semantic difference between wildcard and contains).
A correct-but-slow query is operationally not usable. Top categories:
index= directly. KQL: table-specific (SigninLogs, not union *). Elastic: tighten the index pattern.extract on mass data is expensive — use regex-extracted fields at index time where possible.let with materialize is often more performant.tstats against an accelerated CIM data model is orders of magnitude faster than equivalent search-time extraction.join, order matters; smaller table on the left. Elastic's enrich pipeline at index time is often better than a query-time join.Profiling help:
Search Job Inspector shows per-stage time. tstats vs raw-search comparison.set notruncation=true debug, evaluate execute_query_stats(...).Well-built queries are reusable. Discipline to keep them that way:
function keyword), Elastic painless scripts. Reuse per common sub-pattern (define "what is a suspicious LSASS access" once, use it in N rules).sec_, hunt_, dashboard_) so the purpose is immediately clear.Layer 1: scope (query covers all relevant fields + time window, no unintended scope creep through wildcard table selection?), assumptions (data model up to date, schema fields exist?), gaps (FP path checked, not just the TP path?). Layer 2: function names against current platform docs (KQL and SPL add and deprecate functions), no invented table names or field syntax, time-bucket syntax correct, performance claims supported by profiling output.
Query package — <goal>
Platform target: <Splunk SPL | Sentinel KQL | Defender KQL | Elastic EQL/KQL | multi>
Data source(s): <indexes / tables / index patterns>
Time window: <default + customizable>
Query (primary):
<full query text>
Translations (multi-platform):
Splunk SPL: <...>
KQL: <...>
EQL: <...>
Performance profile:
Test run: <events scanned, runtime>
Bottleneck: <field extraction / subsearch / join / etc>
Optimization applied: <data model / summary / index filter>
Edge cases / FPs:
- <known FP pattern, how to filter>
- <field-name issues when translating between platforms>
Library integration:
Saved as: <macro/function/saved-search name>
Detection-as-code path: <repo path>
Handoffs:
detection-engineer: <if query becomes the basis for a rule>
log-triage: <if query is for incident investigation>
threat-hunt: <hunt context>
Verification-loop: ...~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.