Intake Filters
An intake filter is a CEL expression evaluated on Stairwell's side that blocks a file from being stored, whatever uploaded it: forwarder, API, or console.
An intake filter is a rule, written as a CEL expression, that Stairwell evaluates on every incoming file for an environment. If the expression evaluates to true, the file is not stored. Because the rule runs on Stairwell's side rather than on the host, it applies to every upload path there is: forwarders, the API, and manual uploads from the console.
Use an intake filter when the requirement is "this must never be stored". Use an exclusion when the requirement is "this host should not spend effort on that path". They are not alternatives so much as different halves of a decision, and the section below is the distinction in full.
How is an intake filter different from an exclusion?
| Intake filter | Exclusion | |
|---|---|---|
| Where it runs | On Stairwell's side, at upload | On the host, in the forwarder |
| What it covers | Every upload source: forwarders, API, console upload | Forwarder uploads only |
| Written as | A CEL expression on asset and object fields | A path glob |
| Scoped by | Environment | Policy, and therefore group |
| Host cost saved | None. The forwarder still opens and hashes the file, then the upload is refused | The file is never opened |
| Sighting recorded | The forwarder still sights the file | No |
Two consequences follow from that table, and both surprise people.
An intake filter does not make a host quieter. The forwarder does not know about it, so it does the local work of finding, opening, and hashing the file, and only then is the upload turned away. If your problem is disk contention or CPU on a busy host, an exclusion is the tool and an intake filter will not help.
An intake filter is the stronger guarantee. An exclusion is a rule you are asking forwarders to honor. An intake filter is enforced where the storage decision is made, so it also covers the file someone uploads by hand from the console and the file an integration pushes through the API.
What can I filter on?
Three fields, plus the asset the upload came from.
| Field | Type | What it holds |
|---|---|---|
asset.id | string | The asset ID of the machine the file came from |
object.path | string | The directory portion of the file's path, including the trailing separator |
object.name | string | The filename, with no directory portion |
object.size | integer | The uncompressed size of the file in bytes |
The split between path and name is the detail to get right. A file at C:\Tanium\Client\helper.exe has object.path of C:\Tanium\Client\ and object.name of helper.exe. A filter written as object.path == "C:\\Tanium\\Client\\helper.exe" will never match anything, because the full path never appears in object.path.
How do I create an intake filter?
- In Settings, under Environments, open Intake filters.
- Select the environment with the environment filter at the top of the list.
- Click Create filter.
- Enter a Filter Name. It is the identity of the filter and cannot be changed later, only deleted and recreated.
- Enter the CEL Expression.
- Click Validate. This compiles the expression and reports the line and column of a syntax or type error. You cannot submit until validation passes on the exact text in the box, so an edit after a successful validation requires validating again.
- Click Submit.
The dialog also has a Filter cheat sheet with examples. One thing to know when reading it: the boolean "or" in CEL is ||.
An expression must evaluate to a boolean. object.size on its own is a compile error, not a filter that matches large files.
What expressions actually work?
Exact comparison, boolean composition, regular expression matching, prefix matching, and numeric comparison on size.
Block one named file anywhere:
object.name == "internal_secret_program.dmg"
Block several names, or a name on a specific asset:
object.name == "passwords.txt" || object.name == "company_confidential_file.bin"
object.name == "passwords.txt" || (asset.id == "1A2B3C-4D5E6F-G7H8I9-STUVWXYZ" && object.path == "/secret-dir/")
Match a path by regular expression, which is what to use when you want part of a path rather than the whole of it:
object.path.matches("secret")
Match a path prefix, and combine it with a size bound:
object.path.startsWith("C:\\Tanium\\") && object.size < 10000
Match a size band:
object.size >= 1024 && object.size <= 5120
Note that object.size is zero when the size is not known, so object.size > 0 does not match an upload with no size reported. If a filter has to catch those, do not gate it on size.
When should I use one, and what does it cost?
Good reasons to reach for an intake filter:
- A named file must not be stored. A credentials file, an internal tool with a distribution restriction, an artifact covered by a data handling agreement. This is the case an exclusion cannot fully close, because an exclusion does not stop a console upload.
- A specific asset's uploads must be constrained.
asset.idin the expression scopes the rule to one machine without needing a group for it. - A size band is the right discriminator. Sizes are awkward to express as a glob and natural to express here.
The cost is the same cost as an exclusion, in the same direction: a filtered file is a file Stairwell has no record of. It will not be scanned by a YARA rule, will not appear in prevalence, and will not match a threat report. Read the tradeoff section in Exclusions before you write a broad one; it applies here identically, and a CEL expression makes it easier to write something broad by accident than a path glob does.
One hard limit that is not a filter: Stairwell's intake accepts files up to 512 MiB. A larger file is rejected regardless of your filters, so if you were about to write a size filter to keep enormous files out, the ceiling is already there.
What should I read next?
- Exclusions, for the host-side control and the honest cost of both.
- CEL Query Language, for the expression language itself. Note that the search environment exposes a much larger set of fields than intake does; the four in the table above are all an intake filter can see.
- Groups and Policies, if the rule is really about a set of machines rather than about what may be stored.
Updated 19 days ago