Condition Syntax

Learn how to write conditions for a Falco Rule

A Falco rule’s condition defines the filter that determines which events are detected by the rule. This condition is a boolean expression that evaluates to true or false for each event. If it evaluates to true, the rule triggers and generates an alert.

A condition can be viewed as a sequence of comparisons, each joined by logical operators. Parentheses can be used to define precedence. Each comparison uses a comparison operator between a field (on the left side), extracted from the input event, and a static or computed value (on the right side). You can also apply transformers to the field to modify its extracted values before comparison.

The set of fields available depends on the data source. For simplicity, this page focuses on syscalls, as they are among the most common.

For example, the following condition triggers for each execution of cat or grep:

evt.type = execve and evt.dir = < and (proc.name = cat or proc.name = grep)

Operators

You can use the below operators in Falco rule conditions.

Logical operators

OperatorsDescription
andLogical AND operator to connect two or more comparisons (ie. evt.type = open and fd.typechar='f').
orLogical OR operator to connect two or more comparisons (ie. proc.name = bash or proc.name = zsh).
notLogical NOT operator to negate a comparison (ie. not proc.name = bash).

Comparison operators

OperatorsDescription
=, !=Equality and inequality operators.
<=, <, >=, >Comparison operators for numeric values.
contains, bcontains, icontainsStrings are evaluated to be true if a string contains another. For flags, contains evaluates to true if the specified flag is set. For example: proc.cmdline contains "-jar", evt.arg.flags contains O_TRUNC. The icontains variant works similarly but is case-insensitive. The bcontains variant allows byte matching against a raw string of bytes, taking a hexadecimal string as input. For example: evt.buffer bcontains CAFEBABE
endswithChecks if a string ends with a given suffix.
existsChecks whether a field is set. Example: k8s.pod.name exists.
globEvaluates standard glob patterns. Example: fd.name glob "/home/*/.ssh/*".
inEvaluates whether the first set is completely contained in the second set. Example: (b,c,d) in (a,b,c) is FALSE because d is not found in (a,b,c).
intersectsEvaluates whether the first set has at least one element in common with the second set. Example: (b,c,d) intersects (a,b,c) is TRUE because both sets contain b and c.
pmatchCompares a file path against a set of file or directory prefixes. Example: fd.name pmatch (/tmp/hello) evaluates to true for /tmp/hello, /tmp/hello/world but not /tmp/hello_world. More details in the below section.
regexChecks whether a string field matches a Google RE2-compatible regular expression. Note that regex can be considerably slower than simpler string operations. Example: fd.name regex '[a-z]*/proc/[0-9]+/cmdline'.
startswith, bstartswithChecks if a string starts with a given prefix. The bstartswith variant allows byte matching against a raw string of bytes, taking a hexadecimal string as input. For example: evt.buffer bstartswith 012AB3CC.

pmatch operator

pmatch checks if any given path prefix matches a filesystem path in Falco fields like fd.name, evt.rawarg.path, or fs.path.name. For example:

fd.name pmatch (/var/run, /var/spool, /etc, /boot)

If fd.name is /var/spool/maillog, this expression is true; if it is /opt/data/file.txt, it is false. Internally, pmatch builds a tree-like structure from the right-hand side paths and traverses it with the left-hand side path components, returning true at the first matching leaf.

pmatch can also include glob wildcards:

fd.name pmatch (/var/*/*.txt, /etc, /boot)

This still performs a prefix match. Unlike glob, which must fully match the path, pmatch succeeds if the path starts with one of the specified prefixes. Hence, fd.name pmatch (/var/*) matches /var/run/file.txt, while fd.name glob /var/* does not. Wildcards do not cross directory separators (see glob.7).

Transformers

Falco supports basic transformations on fields within rule conditions. For instance, if you want to check for a case-insensitive process name, you can use:

tolower(proc.name) = bash

The following transform operators are supported:

TransformerDescription
tolower(<field>)Converts the input field to lowercase.
toupper(<field>)Converts the input field to uppercase.
b64(<field>)Decodes the input field from Base64.
basename(<field>)Extracts the filename without its directory path from the input field. Unlike the Unix basename program, basename() in Falco returns "" if no filename is present. For example, basename(proc.exepath) is "cat" for /usr/bin/cat but "" for /usr/bin/.
len(<field>)Returns the length of the field: for LIST fields, the number of elements; for CHARBUF fields, the number of characters; and for BYTEBUF fields, the number of bytes.

Field evaluation (for right-hand side of comparisons)

Falco also lets you compare field values with other field values by using the val() special transformer on the right-hand side of a comparison. For instance, to detect processes that have the same name as their parent:

proc.name = val(proc.pname)

Similarly, using transformations on both sides is supported:

tolower(proc.name) = tolower(proc.pname)

Syscall event types, direction, and args

Every syscall event includes the evt field class. Each condition you write for these events typically begins with an evt.type expression or macro. This is practical because security rules often focus on one syscall type at a time. For instance, you might consider open or openat to detect suspicious activity when files are opened, or execve to inspect newly spawned processes. You do not have to guess the syscall name—simply refer to the complete list of supported system call events for an overview of what you can use.

Each syscall has an entry event and an exit event, tracked by the evt.dir field, also referred to as the "direction" of the system call. A value of > indicates entry (when the syscall is invoked), while < marks exit (when the call has returned). By looking at the supported system call list, you will see that events have both entry and exit forms. For example:

> setuid(UID uid)
< setuid(ERRNO res)

In many cases, it is most useful to filter on exit events, because you want to know the outcome of the syscall once it has completed. For example, consider the file-opening events:

> open()
< open(FD fd, FSPATH name, FLAGS32 flags, UINT32 mode, UINT32 dev)
> openat()
< openat(FD fd, FD dirfd, FSRELPATH name, FLAGS32 flags, UINT32 mode, UINT32 dev)

Each event has a list of arguments that you can access through evt.arg.<argname>. For instance, if you want to detect a process opening a file to overwrite it, check if the list of flags contains O_TRUNC:

evt.type in (open, openat) and evt.dir = < and evt.arg.flags contains O_TRUNC

Note that arguments do not necessarily match the raw parameters used in the Linux kernel; Falco may parse them in ways that make rule-writing more straightforward. By using the evt fields, you can inspect many other aspects common across different events.

Syscall event context and metadata

While the evt fields allow you to write expressive conditions, arguments and common fields alone are often insufficient for complete security rules. You might also need to consider the process context in which the event occurred, whether or not it happened inside a container, or how it correlates with Kubernetes metadata. To enable this, Falco enriches many events with additional field classes. Not all field classes are available for all events, and the list grows over time. Each field class’s documentation clarifies when those fields are expected to be present, but some are so common that rules often rely on them.

The proc field class gives you context about the process and thread generating a specific syscall. This information is frequently very important. For example, you can use proc.name and proc.pid, or even traverse the process hierarchy with proc.aname[<n>] and proc.apid[<n>]. You can also see which user performed the action with the user field class.

An example rule that detects whenever bash is executed inside a container could look like this:

evt.type = execve and evt.dir = < and container.id != host and proc.name = bash

Notice that you do not need to check the execve arguments. Once execve has returned, Falco updates the process context, so all proc. fields refer to the new process that was just spawned, including command line, executable path, arguments, and so on.