Reflex Query Language (RQL)

Reflex Query Language (RQL) is a query language designed to query events within Case-Hub. RQL is used while creating Event Rules to query the Event data and match certain criteria.

Event Fields

  • observables|observables.*

  • value

  • tlp

  • tags

  • spotted

  • safe

  • source_field

  • data_type

  • ioc

  • original_source_field

  • title

  • description

  • tlp

  • severity

  • status,

  • reference

  • source

  • signature

  • tags

  • raw_log|raw_log.*

Supported Expressions

The following Expressions are used to compare target field data to intended data:



The item has a value that matches a regular expression

title RegExp "^Event.*"


The item has a value in a list of values in ["malware"]


The target value contains a specific string

description Contains "malware"


Same as Contains but will make the target value and checked value the same case


Equal to (strings or numbers)


Not equal to (strings or numbers)


Greater than (> or gt)


Greater than or equal to (>= or gte)


Less than (< or lt)


Less than or equal to (<= or lte)


The IP address is in a specific CIDR network InCIDR


Use for boolean operations like "Is True"

ioc Is True


The field exists at all, useful if you don't care what the target value


The item has a value between a given range

tlp Between "1,3"


The item has a value that starts with a certain string

url StartsWith "https"


The item has a value that ends with a certain string

domain EndsWith ".tk"


When you want two conditions on a nested object to be true use each statement.

For example, The observable should have a value of and safe is True, the query would look like Expand observables (value = "" and safe Is True)


Allows RQL to check the value of a field against a Case-Hub Intel List (threat lists)


The expression within this block should not match. Note: Can only be used on eq, in, InCIDR, contains, between AND regexp.

title Not Eq "Suspicious DNS Query"

Note that the Items that don't have a specified field may match a Not expression e.g. ip NOT InCIDR "" may match on an event not having an ip field, pair this with ip exists AND ip NOT InCIDR ""


Mutators take a field and perform an extra operation on it to make it digestible by the downstream comparison. Assume you want to find any Event with a domain observable where the length of the domain is longer than 20 characters

  • |length - How long a string is e.g. url.domain|length > 20

  • |count - The number of items in an array value observables|count > 2

  • |lowercase - Lowercase a string (redundant for ContainsCIS but can be used for other fields)

  • |refang - If for some reason the target value has been defanged, think hXXps[:]// instead of https:// this will refang the value to perform a proper comparison e.g. url.full|refang eq ""

  • |b64decode - If the target value is base64 encoded and you want to write rules using the terms within it, first base64 decode it, e.g. command|b64decode Contains "Invoke-Mimikatz"

  • |b64extract - Will attempt to find base64 encoded data in a string and extract it for comparison later in the query e.g. an event contains a command powershell -encodedCommand SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AaQBwAGkAbgBmAG8ALgBpAG8ALwBpAHAA would extract and decode SQBuAHYAbwBrAGUALQBXAGUAYgBSAGUAcQB1AGUAcwB0ACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AaQBwAGkAbgBmAG8ALgBpAG8ALwBpAHAA to Invoke-WebRequest An analyst could then use a query like command|b64extract Contains ""

  • |urldecode - Unescapes an escaped URL so that direct comparisons can be made

  • |any - Force the following condition to match any item in the array (Can only be used on Contains and In expressions)

  • |all - Force the condition to match all items in the array (Can only be used on Contains and In expressions)

  • |avg - Calculates the average value given a list of values e.g. observables.risk_score|avg > 7

  • |max - Finds the max value given a list of values e.g. vulnerablities.cvss_score|max > 7

  • |min - Finds the minimum value given a list of values

  • |sum - Add up all the values in a list of integer or float values

  • |split - Splits a string that contains spaces into an array

  • |geo_country - Returns the ISO Code for the country an IP resides in

  • |geo_continent - Returns the ISO Code for the content an IP resides in

  • |geo_timezone - Returns the timezone an IP resides in

  • |reverse_lookup - Takes an IP and attempts to return the associated hostname

  • |nslookup_a - Fetches the A record for a domain name

  • |nslookup_aaaa - Fetches the AAAA record for a domain name

  • |nslookup_mx - Fetches the MX records for a domain name

  • |nslookup_ns - Fetches the NS records for a domain name

  • |nslookup_ptr- Fetches the PTR records for a domain

  • |is_private - Returns True if an IP is RFC1918

  • |is_global - Returns True if an IP is routable on the internet

  • |is_multicast - Returns True if an IP is multicast

  • |is_ipv6 - Returns True if an IP is IPv6

Query Examples

# Match any Suspicious DNS query only if it came from the Administrator on a domain joined machine and the target observable is
title = "Suspicious DNS Query" and user Contains "Administrator" and hostname EndsWith "" and (observables.data_type = "domain" and observables.value = "")
# Match any cases referencing malware or with a severity higher than 3
description Contains "malware" or severity > 3
# Match any event that has a domain with or an IP with
(observables.data_type = "domain" and observables.value = "") or (observables.data_type = "ip" and observables.value = "")
# Match any Event that has all of the below observables
observables.values|all in ["",""]
# Match any event that contains a base64 encoded command that once decoded contains the following phrases
command exists and command|b64decode|lowercase Contains ["invoke-mimikatz","invoke-bloodhound","invoke-powerdump","invoke-kerberoast"]
# Match any suspicious DNS query for a specific domain that originates from a specific user and source process 
# Should always be this event title
title = "Suspicious DNS Query"

# Observables should always exist
and observables exists

# Brian must be the source user of the event
and expand observables (value Contains "Brian" and source_field|lowercase = "winlog.event_data.user")

# And the DNS resolution should always be for
and expand observables (value = "" and source_field|lowercase = "")

# And should originate from Slack
and raw_log.process.executable EndsWith "slack.exe"
# Check to see if the user in the event is in the Allowed Users intel list
expand observables ( data_type = "user" and intel(value|uppercase, 'Allowed Users'))

Last updated