YARA-L 2.0 windowing logic
This guide helps Security Engineers choose the correct window type for queries to avoid "variable not bounded" compiler errors. Transitioning from sliding windows to tumbling windows lets you build logic that depends on the absence of events, such as a missing heartbeat or a failed log source.
Before you begin
Confirm your account has one of the following roles to create and modify YARA-L queries:
- Detection Engine Admin (
roles/chronicle.detectionEngineAdmin) - SecOps Editor (
roles/chronicle.editor)
Supported window types
YARA-L 2.0 uses different windowing behaviors to determine how time is sliced and how events group together. You can group event fields and placeholders in the match section by a specified time granularity using the following supported windows:
| Supported window type | Syntax | Description | Common use case |
|---|---|---|---|
| Hop | $key over <duration> |
Creates fixed, overlapping time intervals. The system defines the overlap and alignment to catch events near boundaries. | General correlation of multiple events, regardless of exact start times. |
| Tumbling | $key by <duration> |
Segments data into fixed-size, continuous, non-overlapping blocks. Evaluates independently of event arrival. | Quantifying activity in fixed slots (for example, $user by 30m) or detecting the absence of events. |
| Sliding | $key over <duration> [before|after] $pivot |
Anchors the window to a specific "pivot" event. Requires that pivot to exist to trigger a look back or look forward. |
Strict sequencing where event order is critical (for example, File Download after Login). |
Hop windows
A hop window creates overlapping time intervals so events happening near the boundaries of a window aren't missed.
- Use case: Best for detections where you need to catch a specific scenario regardless of exactly when the window interval starts or ends.
- Support: Supported for aggregation in Search and Dashboards.
YARA-L queries with a match section use hop windows to correlate multiple events over time. The system divides the time range of the query's execution into a set of fixed, overlapping hop windows. While you specify the duration of these windows in the match section, the system defines the overlap interval and window alignment. Events then correlate within each of these predetermined windows.
Learn more about the match section syntax.
Example: Overlapping hop windows for continuous correlation
The following example shows a query run over the time range [1:00, 2:00], with a match section $user over 30m. A possible set of overlapping hop windows the system generates is [1:00, 1:30], [1:03, 1:33], and [1:06, 1:36].
Rule
rule hop_window_brute_force_example {
meta:
description = "Detects multiple failed logins within a shifting 30-minute window."
severity = "Medium"
events:
$login.metadata.event_type = "USER_LOGIN"
$login.extensions.auth.auth_status = "FAILURE"
$login.principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
condition:
// This will trigger if 10 or more failures fall into any single 30m hop
#login >= 10
}
Search
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
```
Dashboard
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user
match:
// This creates the overlapping windows (e.g., 1:00-1:30, 1:03-1:33)
$user over 30m
Example: Multi-event correlation using a hop window
The following example captures events that occur within the same general timeframe:
Rule
rule hop_window_example {
meta:
description = "Detect a user with a failed login followed by a success within 30m"
events:
// Event 1: Capture failed login attempts
$fail.metadata.event_type = "USER_LOGIN"
$fail.security_result.action = "FAIL"
$fail.principal.user.userid = $user
// Event 2: Capture successful login attempts
$success.metadata.event_type = "USER_LOGIN"
$success.security_result.action = "ALLOW"
$success.principal.user.userid = $user
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
condition:
// Ensure both a failed ($fail) and a successful ($success) login event occurred for the same user within the 30m window.
$fail and $success
}
Search
// Event 1: Capture failed login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user // Assign user ID to a placeholder
// Event 2: Capture successful login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "ALLOW"
principal.user.userid = $user // Link to the same user placeholder
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
Dashboard
// Event 1: Capture failed login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
principal.user.userid = $user // Assign user ID to a placeholder
// Event 2: Capture successful login attempts
metadata.event_type = "USER_LOGIN"
security_result.action = "ALLOW"
principal.user.userid = $user // Link to the same user placeholder
match:
// Correlate events for the SAME $user within a rolling 30-minute window.
$user over 30m
Example: Hop window comparison
To identify a brute-force attempt, a 10m window groups all USER_LOGIN failures. The condition then evaluates if the count (#e) within that specific 10-minute bucket exceeds your threshold.
Rule
rule failed_logins
{
meta:
author = "Security Team"
description = "Detects multiple failed user logins within 10-minute windows."
severity = "HIGH"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.security_result.action = "FAIL"
$user = $e.target.user.userid
match:
$user over 10m
condition:
#e >= 5
}
Search
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
$user = target.user.userid
match:
$user over 10m
Dashboard
metadata.event_type = "USER_LOGIN"
security_result.action = "FAIL"
$user = target.user.userid
match:
$user over 10m
Tumbling windows
Note: This feature is not available to all customers in all regions.
A tumbling window segments data into fixed-size, non-overlapping, and continuous time intervals. Each event's timestamp falls into exactly one window. There is no overlap between tumbling windows. This contrasts with a hop window or a sliding window, which can have overlapping time intervals.
To implement a tumbling window, use the by operator in the match section. Tumbling windows divide time into continuous, back-to-back blocks, for example:
by 1h: Creates windows for each hour (for example,[00:00:00-00:59:59],[01:00:00-01:59:59]).by 10m: Creates windows for each 10-minute interval (for example,[00:00:00-00:09:59],[00:10:00-00:19:59]).
Common use cases
Use tumbling windows when you need to:
- Analyze events in distinct, non-overlapping time blocks.
- Produce only one detection for a given entity (as defined by the match variables) within each fixed time interval, regardless of how many times the event occurs.
- Count unique entities over fixed periods.
Deduplication behavior
A key characteristic of tumbling windows is how the engine handles detections within each window for the same set of match variables:
- One detection per window: For a given set of values for the match variables (for example, a specific
$userid), the engine generates at most one detection for any single tumbling window. - First arrival wins: The first events ingested that satisfy the rule conditions for that set of match variables within a specific window triggers the detection.
- Deduplication: Any subsequent events matching the criteria within that same window instance won't generate additional detections.
Syntax
The syntax in the match section is: match: $variable by <duration>
$variableis the placeholder variable that you are matching on.durationis a number followed by a time unit:m(minute),h(hour),d(day).- Specify a minimum of one minute and a maximum of 72 hours or three days.
Example: Fixed-interval grouping
The following rule groups logins by $userid within 1-hour non-overlapping windows.
Rule
rule TumblingWindowExample {
meta:
description = "Example using a 1-hour tumbling window"
events:
$e.metadata.event_type = "USER_LOGIN"
$e.principal.user.userid = $userid
match:
$userid by 1h
condition:
$e
}
Search
metadata.event_type = "USER_LOGIN"
principal.user.userid = $userid
match:
$userid by 1h
Dashboard
metadata.event_type = "USER_LOGIN"
principal.user.userid = $userid
match:
$userid by 1h
Example: Detection behavior (user = "Alex")
- Event 1: Alex logs in at 00:30. This falls into the
[00:00:00-00:59:59]window. The engine generates a detection for Alex for this window. - Event 2: Another user, "Taylor", logs in at 00:45. This also falls into
[00:00:00-00:59:59], but because the$useridis different, the engine generates a separate detection for Taylor. - Event 3: Alex logs in again at 00:40. This is still within the
[00:00:00-00:59:59]window. Because a detection for Alex already exists, this event is deduplicated. No new detection is generated. - Event 4: Alex logs in at 01:20. This falls into the next window,
[01:00:00-01:59:59]. The engine generates a new detection for Alex.
Even though Event 1 and Event 4 for Alex occurred less than an hour apart, they fall into separate detections because Event 4 crosses the fixed window boundary.
Configure tumbling windows for absence detections
To alert on a count of zero and avoid compiler failures, complete the following steps:
- Identify the detection goal. Determine if you are searching for high frequency or a lack of activity.
- Select the
windowkeyword. Useoverfor frequency andbyfor absence. - Reference window boundaries. Use
window_startandwindow_endkeywords to reference specific boundaries of the time bucket.
Context: Use outcome: $ext_window_end = window_end to include the exact end-time of a missed heartbeat in alert metadata.
Sliding windows
A sliding window is anchored to a specific pivot event and looks either forward (after) or backward (before).
Common use cases
Use sliding windows when event sequencing is critical:
- Strict sequencing: Detect an attack chain (for example,
e1occurs up to two minutes aftere2). - Relative timing: Find an event that occurs within a specific offset of a trigger (for example, a
Network Connectionwithin 30 seconds of aProcess Start). - Absence detection: Identify when a required "cleanup" or "heartbeat" event fails to occur after a start event.
Syntax
match: <grouping_keys> over <duration> [before|after] <$pivot_event>
| Component | Description | Example |
|---|---|---|
| Grouping keys | Common fields used to link events together. | $host, $user |
| Duration | The time offset from the pivot event. | 5m, 1h, 30s |
| Direction | Whether the window extends forward or backward. | after, before |
| Pivot event | The event variable that anchors the window. | $proc, $alert |
The following are valid sliding window examples:
$var1, $var2 over 5m after $e1$user over 1h before $e2$host, $ip over 1h before $e2
Requirements and limitations
- Performance: Sliding windows require more processing power than hop windows. Only use them when event order is strictly required (for example, where one event must happen within five minutes after another event).
- Single-event queries: Don't use sliding windows for single-event logic. Use multiple event variables in the
conditionsection instead.
Example: Forward-looking correlation (after)
Rule
rule sliding_window_after_example {
meta:
description = "Detect a network connection occurring within 1 minute after a suspicious process launch."
severity = "High"
events:
$proc.metadata.event_type = "PROCESS_LAUNCH"
$proc.principal.hostname = $host
$net.metadata.event_type = "NETWORK_HTTP"
$net.principal.hostname = $host
match:
// $proc is the pivot; the 1-minute window starts at the $proc timestamp
$host over 1m after $proc
condition:
$proc and $net
}
Search
after is unsupported for Search.
Dashboard
after is unsupported for Dashboards.
Example: Backward-looking correlation (before)
Use a "before" sliding window to investigate activity leading up to a specific alert. This is often used in root-cause analysis to identify what happened immediately preceding a critical detection.
Rule
rule sliding_window_before_example {
meta:
description = "Identify file modifications occurring in the 5 minutes before a ransomware alert."
severity = "Critical"
events:
$file.metadata.event_type = "FILE_MODIFICATION"
$file.principal.hostname = $host
$alert.metadata.event_type = "ANTIVIRUS_DETECTION"
$alert.metadata.product_name = "Premium_AV"
$alert.principal.hostname = $host
match:
// $alert is the pivot; the 5-minute window ends at the $alert timestamp
$host over 5m before $alert
condition:
$file and $alert
}
Search
before is unsupported for Search.
Dashboard
before is unsupported for Dashboards.
Troubleshooting
Use this section to understand latency, limits, and fixes for common windowing issues in YARA-L.
Latency and limits
- Rules that use tumbling windows (
by) only trigger at the end of the fixed time block. For example, a rule withmatch: $user by 24honly evaluates once the 24-hour window has fully elapsed. - Alert latency: Rules that use
by(tumbling) only trigger after the fixed time block elapses. Aby 24hrule won't alert mid-window.
Error remediation
| Error code | Description | Fix |
|---|---|---|
| Variable Not Bounded | The rule uses over (sliding window) with a $count = 0 condition. |
Change the windowing keyword to by (tumbling window). Sliding windows require an event to exist to anchor the window, whereas tumbling windows don't. |
| UI Header Mismatch | The user sees TIME_BUCKET in the UI instead of window_start. |
No fix required. Filtering and ordering logic still function correctly using the keywords. |
What's next
Need more help? Get answers from Community members and Google SecOps professionals.