> For the complete documentation index, see [llms.txt](https://docs.dropzone.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.dropzone.ai/platform/settings/global-alert-project/writing-cel-expressions.md).

# Writing CEL Expressions

Every rule matches alerts using an expression written in [CEL](https://cel.dev/) (Common Expression Language).

The Expression Editor includes the following:

1. A field reference page, with a complete list of fields you can filter by
2. An example section, with a list of common CEL expressions to filter with
3. The CEL Filter Expression Tester, where you can validate an expression against a sample alert before creating the rule

<figure><img src="https://435022081-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmBVcKuiytGCsIDpL70BC%2Fuploads%2Fgit-blob-cf60f08a775dad29ba49ed4a4922b84eb12c4fe6%2Fui-gaf-expression-editor.png?alt=media" alt=""><figcaption><p>The Filter Expression Editor/p></p></figcaption></figure>

## Common Fields

Below is a selection of the most commonly used fields. The editor's field reference lists the complete set.

| Field                           | Description                                                              |
| ------------------------------- | ------------------------------------------------------------------------ |
| `alert.title`                   | Alert title                                                              |
| `alert.severity`                | Normalized severity level (e.g. `"high"`, `"low"`, `"info"`)             |
| `alert.alert_type`              | Alert type classification                                                |
| `alert.schema_key`              | Alert source / handler key (e.g. `msgraph_defender_alert`)               |
| `alert.entities`                | Extracted entities, each with a `type` and `value`                       |
| `alert.assets`                  | Extracted assets                                                         |
| `alert.raw`                     | The raw payload from the source. Its shape varies by source.             |
| `alert.enrichment`              | Enrichment data keyed by source (e.g. `related_alerts`, `query_results`) |
| `alert.tenant_label`            | Tenant display label                                                     |
| `alert.tenant_union.id`         | Tenant ID from the Multi-Tenant Map (nullable)                           |
| `alert.origin_integration.slug` | The integration the alert originated from                                |

{% hint style="warning" %}
`alert.raw` and `alert.enrichment` differ from alert to alert, so a field you expect may not always be present. The same is true of nullable objects such as `alert.tenant_union` and `alert.origin_integration`.

Accessing a field that isn't there can cause the expression to error. The safe pattern is to use the helper function `has_field()` and combine with `&&`, e.g.:

```
has_field(alert.raw.UserName) && alert.raw.UserName == "admin@example.com"
```

{% endhint %}

## Helper Functions

Below is a selection of helper functions most commonly used in expressions.

| Function            | Example                                           | What it does                                                                                   |
| ------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `has_field(...)`    | `has_field(alert.raw.event_id)`                   | Returns `true` if the nested field exists and is non-null. Use before accessing a nested field |
| `in_cidr(...)`      | `in_cidr(alert.raw.src_ip, "10.0.0.0/8")`         | Returns `true` if the IP falls within the CIDR range                                           |
| `now_ts()`          | `now_ts()`                                        | The current UTC time as epoch seconds                                                          |
| `to_timestamp(...)` | `to_timestamp(alert.raw.ts, "%Y-%m-%dT%H:%M:%S")` | Parses a date string into epoch seconds. The format is optional                                |

## Example CEL Expressions

Some common filters include filtering by:

* Severity: `alert.severity == "high"`, `alert.severity in ["low", "info"]`
* Keyword or title: `alert.title.contains("Login")`
* Containing specific fields: `has_field(alert.raw.event_id) && alert.raw.event_id == "abc"`
* When related alerts already exist: `has_field(alert.enrichment.related_alerts) && alert.enrichment.related_alerts[0].title.contains("failed")`

## Testing before you save

Use the Tester function in the expression editor to run your expression against a sample alert and confirm it matches as intended. A sample alert payload is provided, and you can edit it to reflect the alerts you're targeting.

## Errors

If an expression errors at evaluation time, the rule is treated as not matching. Evaluation will proceed to the next rule, and if nothing else matches, the Global Default Rule applies.

Errors are recorded in the [activity log](/platform/settings/global-alert-project/reviewing-filter-activity.md) with an "Error" outcome. Be sure to check it after changing any expression.
