The following is the PQL reference for Case Creation.
Rule Anatomy
Every rule contains these components:
| Component | Required? | Purpose |
|---|---|---|
| Rule Name | Yes | Human-readable identifier, unique per tenant (max 255 chars) |
| Enabled | Yes | Whether the rule is actively processing alerts (defaults to false) |
| Filter | No | Conditions that alerts must match. If omitted, the rule matches all alerts |
| Time Window | Yes | How alerts are bucketed in time (e.g., 1 hour, 30 minutes) |
| Group By | Yes | Which fields define a group (e.g., user, app, destination) |
| Case Creation Threshold | Yes | When a group becomes a case (e.g., evidence count >= 10) |
Writing Rules (Pipe Query Syntax)
Rules use a pipe query syntax where each stage is separated by |. The general format is:
filter <conditions> | time_window <duration> <type> | create_case group_by <fields> [when <threshold>]
Complete Examples
Simple rule — group all alerts by user in 4-hour windows:
time_window 4h hopping | create_case group_by incident.user
Filtered rule — detect rapid bulk downloads from sanctioned apps:
filter incident.dlp_user_activity = 'download' case_insensitive
AND incident.app_instance_is_sanctioned = true
| time_window 30m tumbling
| create_case group_by incident.user when group.evidence_count >= 30
Multi-condition rule — large file uploads to unsanctioned apps:
filter incident.file_size >= 104857600
AND incident.file_type in ['sql', 'bak', 'zip', 'dump'] case_insensitive
AND incident.dlp_user_activity in ['upload', 'share', 'send', 'uploadandshare'] case_insensitive
AND incident.app_instance_is_sanctioned != true
| time_window 1h tumbling
| create_case group_by incident.user
DLP policy match — detect PCI policy violations:
filter incident.dlp_policy_name contains 'PCI'
| create_case group_by incident.user when group.evidence_count >= 1
Combined conditions — high severity incidents matching a specific DLP rule:
filter incident.dlp_incident_severity = 'High'
AND incident.dlp_rule_names contains 'Name-CC-EXP'
| create_case group_by incident.user when group.evidence_count >= 1
Example Use Case
A user wants to write a Case Rule that excludes DLP incidents whose enforcement action is allow at the policy level (typically Real-Time Protection Inline policies that are informational/monitoring-only). The desired semantics lead to: don’t create a case if ALL DLP matches on the incident have action = ‘allow‘.
Problem:
- The enforcement action lives in the nested dlp_match_info[].dlp_action array, which is not exposed in the UDM as a top-level filterable field.
- Current PQL array operators express any-match (or its negation), not all-match.
Solution:
Expose dlp_action as a filterable UDM field and add only_contains operator to PQL grammar
incident.dlp_action only_contains ['allow', 'useralert', 'add_headers'] – lets you skip cases when every action is in any set you pick (e.g., all informational: allow / useralert / add_headers).
Solution Example:
filter NOT (incident.dlp_action only_contains ['allow'] case_insensitive)
| time_window 1h tumbling
| create_case group_by incident.user when group.evidence_count >= 1
Filter Conditions
Filters narrow down which alerts a rule processes. Filters are optional — omitting the filter stage means the rule matches all incoming alerts.
Operators
| Operator | Description | Example |
|---|---|---|
= | Exact equality | incident.dlp_user_activity = 'download' |
!= | Not equal | incident.app_instance_is_sanctioned != true |
> | Greater than | incident.file_size > 1000000 |
< | Less than | incident.file_size < 1024 |
>= | Greater than or equal | incident.file_size >= 104857600 |
<= | Less than or equal | incident.app_cci <= 50 |
contains | Substring match | incident.dlp_rule_names contains 'SSN' |
in | Value in list | incident.file_type in ['sql', 'zip', 'bak'] |
Modifiers
| Modifier | Description | Example |
|---|---|---|
case_insensitive | Case-insensitive comparison | incident.dlp_user_activity = 'download' case_insensitive |
Boolean Logic
Combine conditions with AND and OR. Use parentheses for grouping:
filter incident.dlp_incident_severity = 'High'
AND (incident.dlp_rule_names contains 'PCI'
OR incident.dlp_rule_names contains 'SSN')
Available Fields
All filterable and groupable fields use the incident. prefix. These fields are part of AISecOps’s Unified Data Model (UDM) and represent normalized DLP incident data.
File Fields
| Field | Type | Description |
|---|---|---|
incident.file_type | string | File type or MIME type (e.g., application/pdf, text/plain) |
incident.file_size | integer | File size in bytes |
incident.file_owner | string | Owner of the file |
incident.file_exposure | string | Exposure level: public, private, internal, external |
incident.file_md5 | string | MD5 hash of the file |
Application Fields
| Field | Type | Description |
|---|---|---|
incident.app_name | string | Application name (e.g., Google Gmail, Microsoft OneDrive) |
incident.app_instance | string | Application instance identifier |
incident.app_domain | string | Application domain or hostname |
incident.app_cci | integer | Cloud Confidence Index score (0-100) |
incident.app_ccl | string | Cloud Confidence Level: Excellent, Good, Fair, Poor |
incident.app_instance_is_sanctioned | boolean | Whether the app instance is sanctioned (true/false) |
incident.app_category | string | Application category (e.g., Collaboration, Storage, Email) |
User Fields
| Field | Type | Description |
|---|---|---|
incident.user | string | Primary user (email or username) |
incident.user_from | string | Source user (sender in email context) |
incident.user_to | string | Destination user (recipient in email context) |
DLP Policy Fields
| Field | Type | Description |
|---|---|---|
incident.dlp_rule_names | array | Names of triggered DLP rules |
incident.dlp_incident_severity | string | Severity level: High, Medium, Low |
incident.dlp_policy_name | array | Names of triggered DLP policies |
incident.dlp_profile_name | array | Names of DLP profiles used for scanning |
incident.dlp_user_activity | string | User activity: Upload, Download, Send, Share, Edit, etc. |
incident.dlp_policy_activity | string | CASB API Scan label when the incident comes from a CASB scan; NULL otherwise |
incident.dlp_src_country | string | Source country code |
incident.dlp_dst_country | string | Destination country code |
Device Fields
| Field | Type | Description |
|---|---|---|
incident.device_is_managed | boolean | Whether the device is managed by the organization |
Notes on Array Fields
Fields like dlp_rule_names, dlp_policy_name, and dlp_profile_name are arrays. When used with contains, the filter checks whether any element in the array matches the substring. For example:
filter incident.dlp_rule_names contains 'SSN'
This matches any incident where at least one triggered DLP rule name includes “SSN”.
Note: Array fields cannot be used in
group_byclauses.
Time Windows
The time window defines how alerts are bucketed into time periods for grouping.
Syntax:
time_window <duration> <type>
Duration
Specified as a number followed by a unit suffix:
| Format | Duration |
|---|---|
30m | 30 minutes |
1h | 1 hour |
4h | 4 hours |
24h | 24 hours |
1d | 1 day |
Window Types
| Type | Behavior |
|---|---|
| tumbling | Fixed, non-overlapping windows aligned to clock boundaries. An incident at 13:45 with a 1h tumbling window belongs to [13:00, 14:00). |
| hopping | Sliding windows. Similar to tumbling but can overlap depending on configuration. |
How It Works
- Each incoming alert’s timestamp is normalized to the window boundary
- Alerts in the same window with the same grouping key are combined
- Multiple windows can be active simultaneously (e.g., the current hour and the previous hour)
Example: With time_window 1h tumbling:
- Alert at 13:45:30 -> window [13:00:00, 14:00:00)
- Alert at 14:15:30 -> window [14:00:00, 15:00:00)
If the time window is omitted from the pipe query, the system uses a default time window.
Grouping (group_by)
The group_by clause defines which fields create distinct groups. Alerts with identical values for all group-by fields (within the same time window) are combined into one group.
Syntax:
create_case group_by <field1>, <field2>, ...
Examples
| Grouping | Behavior |
|---|---|
group_by incident.user | One group per user per time window |
group_by incident.user, incident.app_name | One group per user + app combination |
group_by incident.user, incident.dlp_src_country | One group per user + source country |
Choosing Grouping Fields:
- Broad grouping (fewer fields): Catches more related activity in each case but may be noisy. Example:
group_by incident.usercreates one case per user. - Narrow grouping (more fields): Creates more targeted cases. Example:
group_by incident.user, incident.app_name, incident.dlp_user_activityseparates upload activity on Dropbox from download activity on Google Drive for the same user.
Restrictions:
- At least one field is required
- Array fields (
dlp_rule_names,dlp_policy_name,dlp_profile_name) cannot be used ingroup_by - Derived fields (computed from expressions) cannot be used in
group_by
Case Creation Threshold
The threshold determines when a group has accumulated enough evidence to become a case.
Syntax:
create_case group_by <fields> when group.evidence_count >= <number>
If when is omitted, the default threshold is evidence_count >= 1 (a case is created as soon as the first matching alert arrives).
Examples
| Threshold | Behavior |
|---|---|
when group.evidence_count >= 1 | Case created on first matching alert |
when group.evidence_count >= 10 | Case created after 10 matching alerts |
when group.evidence_count >= 100 | Case created after 100 matching alerts (good for high-volume, low-severity patterns) |
Choosing a Threshold:
- Low thresholds (1-5): Best for high-severity scenarios where even a single incident warrants investigation. Example: any SSN detection should create a case.
- Medium thresholds (10-30): Good balance for moderate-severity patterns. Example: bulk download detection where occasional downloads are normal.
- High thresholds (50-100+): Best for noisy, low-severity patterns where volume is the signal. Example: many small file uploads to unsanctioned apps.
Group Lifecycle
Understanding how groups progress helps in tuning rules:
active --> ready --> promoted (case created)
^ |
| v
+---- need_update (late-arriving alerts after case creation)
- Active — Group is accumulating evidence (alerts are matching and being added)
- Ready — Group has met the case creation threshold
- Promoted — Group has been converted into a case for investigation
- Need Update — New alerts arrived after the group was already promoted; these are attached to the existing case
Default Rules
When a tenant is provisioned, AISecOps creates a default rule:
| Rule Name | Query | Status |
|---|---|---|
| Default: Group by User | time_window 4h hopping | group_by incident.user | create_case evidence_count >= 1 | Disabled |
This rule groups all DLP incidents by user in 4-hour windows and creates a case for each user with at least one incident. It is disabled by default and must be explicitly enabled.
Out-of-the-Box Rule Templates
AISecOps ships with several pre-built rule templates that address common DLP scenarios:
Exfiltration Preparation
| Rule | Description | Query |
|---|---|---|
| Rapid Bulk Download | Detects users downloading many files from sanctioned apps in a short window | filter incident.dlp_user_activity = 'download' case_insensitive AND incident.app_instance_is_sanctioned = true | time_window 30m tumbling | create_case group_by incident.user when group.evidence_count >= 30 |
Large File Movement
| Rule | Description | Query |
|---|---|---|
| Large File Upload/Share | Single large file (>=100MB) of sensitive types uploaded to unsanctioned apps | filter incident.file_size >= 104857600 AND incident.file_type in ['sql', 'bak', 'zip', 'dump'] case_insensitive AND incident.dlp_user_activity in ['upload', 'share', 'send', 'uploadandshare'] case_insensitive AND incident.app_instance_is_sanctioned != true | time_window 1h tumbling | create_case group_by incident.user |
| Large File External Edit | Large sensitive files edited with external exposure on unsanctioned apps | Similar to above but with dlp_user_activity in ['edit', 'modify'] and file_exposure = 'external' |
Small File Volume
| Rule | Description | Query |
|---|---|---|
| Multiple Small Files Upload/Share | High volume of small files (<1KB) uploaded to unsanctioned apps | filter incident.file_size < 1024 AND incident.dlp_user_activity in ['upload', 'share', 'send', 'uploadandshare'] case_insensitive AND incident.app_instance_is_sanctioned != true | time_window 1h tumbling | create_case group_by incident.user when group.evidence_count >= 100 |
DLP Policy Detection
| Rule | Description | Query |
|---|---|---|
| SSN Detection | Alerts where DLP rules mention SSN | filter incident.dlp_rule_names contains 'SSN' | create_case group_by incident.user when group.evidence_count >= 1 |
| High Severity Incidents | All high-severity DLP incidents | filter incident.dlp_incident_severity = 'High' | create_case group_by incident.user when group.evidence_count >= 1 |
| PCI Policy Violations | Alerts matching PCI-related policies | filter incident.dlp_policy_name contains 'PCI' | create_case group_by incident.user when group.evidence_count >= 1 |
| PII Profile Detections | Alerts from PII-related DLP profiles | filter incident.dlp_profile_name contains 'PII' | create_case group_by incident.user when group.evidence_count >= 1 |
Limits and Constraints
| Constraint | Value |
|---|---|
| Maximum enabled rules per tenant | 10 (configurable) |
| Rule name max length | 255 characters |
| Rule names | Must be unique per tenant |
| Minimum group_by fields | 1 |

