Filters, rules and taint API

These endpoints manage what the dashboard shows and what your machines watch: event filters, machine rules, taint source settings, and the definition of what makes two detections the same event. Every change here is a write; every read is allowed to a read-only key.

Filters

A filter is a standing pattern applied to every events query on a product's Filters page: a blacklist filter hides matching events, a whitelist filter shows only them. These endpoints manage the filters listed on the Filters page.

List filters

GET /api/filters/ lists your event filters.

GET /api/filters/?engine=python
{ "filters": [ { "id": 7, "pattern": "^healthcheck$", "label": "noise",
                 "mode": "blacklist", "target": "where", "enabled": true,
                 "engine": "any" } ] }

engine is optional. With it you get only the filters shown on that product's Filters page: those for that product plus those set to any. It takes the event lists' view values (python or browser); an unknown value is a 400, and a product your account does not have is a 403.

Create a filter

POST /api/filters/create/ adds an event filter and answers 201 with it.

POST /api/filters/create/

JSON body:

Field Meaning
pattern Required. A regex, at most 512 characters (or an impact class, see target).
mode Required. blacklist (hide matches) or whitelist (show only matches).
target What the pattern is matched against: where (the default, the sink label), origin (where the data came in), or tag, which takes an impact class such as xss as its pattern instead of a regex.
engine any (the default, every product) or one product's view value.
label Your description, at most 128 characters.
enabled Defaults to true.

An empty or too-long pattern, or an unknown mode, target, engine or impact class, is a 400. An engine your account does not have is a 403.

curl -s https://eyalsec.com/api/filters/create/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"pattern":"^healthcheck$","mode":"blacklist","label":"noise"}'

Update a filter

PATCH /api/filters/{id}/update/ changes a filter. Send only the fields you want to change; the answer is 200 with the filter (without engine).

PATCH /api/filters/{id}/update/

The pattern cannot be emptied, mode must stay blacklist or whitelist, and a tag target needs a known impact class as its pattern. A filter that is not yours is a 404.

curl -s -X PATCH https://eyalsec.com/api/filters/7/update/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'

Delete a filter

DELETE /api/filters/{id}/delete/ removes a filter and answers 204. A filter that is not yours is a 404.

DELETE /api/filters/{id}/delete/

Machine rules

A rule matches events by pattern, source and sanitizer verdict, and then hides them, shows only them, raises on them, or stops them being sent. These endpoints manage the rules described in Rules. Rules live in a scope: your global rules, or one machine's.

In every call below, machine is a machine's public_id, or an empty string "" (or nothing) for the global scope.

List rules

GET /api/machine_rules/ lists the rules in one scope.

GET /api/machine_rules/?machine=3f6c1a52-8e0b-4d2a-9c1e-5b7d2f0a9e41
{
  "rules": [
    { "ID": 12, "Source": "any", "EventPattern": ".*eval.*",
      "Mode": 3, "Action": "raise", "Polarity": "whitelist",
      "Label": "block eval", "Enabled": true, "sanitize_scope": "any" }
  ]
}

Rule fields are capitalized, all but sanitize_scope. Mode decides what the rule does: 1 Hide, 2 Show, 3 Raise, 4 Don't send (see modes). Action is always raise and Polarity follows the mode (blacklist for mode 4, whitelist otherwise); both are kept for older scripts. The first read of your global scope creates the default rules. A machine that is not yours is a 404.

Create a rule

POST /api/machine_rules/create/ adds a rule to a scope and answers 201 with it, in the same shape as the list.

POST /api/machine_rules/create/

JSON body:

Field Meaning
machine A public_id, or "" for global.
event_pattern A regex matched against the sink label. Empty or omitted means all events. See pattern.
mode 1 Hide, 2 Show (the default), 3 Raise, 4 Don't send.
source any (the default), a source name such as socket or weak-random, or a number for one of your own sources. See source and the note on spelling.
sanitize_scope any (the default), unsanitized, sanitized, conditional, or sanitized:<class>, to match by what the sanitizer decided. See sanitize.
label Your description.
enabled Defaults to true.
polarity Accepted for older scripts and checked (whitelist or blacklist), but the stored value always follows the mode.

An invalid regex, mode, source or sanitize_scope is a 400.

curl -s https://eyalsec.com/api/machine_rules/create/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"machine":"","event_pattern":"noise","mode":1,"label":"hide noise"}'

Raise rules (mode 3) have to be enabled for your account. Without that, a mode 3 rule is refused with 403 and a message saying who to ask. Check grant_raise on GET /api/account/ first, and see the Raise gate.

Raise and Don't send only take effect on es-python. es-chromium does not act on either, so for it only Hide and Show rules have an effect, on what the dashboard shows. See Who can use it.

Update a rule

PATCH /api/machine_rules/{id}/update/ changes a rule and answers 200 with it. Send any of event_pattern, mode, source, sanitize_scope, label, enabled and polarity; the rest stay as they are.

PATCH /api/machine_rules/{id}/update/

The same checks as create apply, and changing mode to 3 checks again that Raise is enabled for your account. A rule that is not yours is a 404.

curl -s -X PATCH https://eyalsec.com/api/machine_rules/12/update/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'

Delete a rule

DELETE /api/machine_rules/{id}/delete/ removes a rule and answers 204. A rule that is not yours is a 404.

DELETE /api/machine_rules/{id}/delete/

Taint sources

Taint settings decide which kinds of incoming data a machine treats as untrusted and follows. Each setting is on, off or unset, and an unset setting inherits from the level above it (see unset and Taint sources).

Read taint settings

GET /api/machine_taint/ returns every taint setting for one scope. machine is a public_id, or empty for global.

GET /api/machine_taint/?machine=3f6c1a52-8e0b-4d2a-9c1e-5b7d2f0a9e41

The answer always carries every key, for every product, including ones the machine's product does not use. It is shortened here:

{ "taint": { "socket": "on", "file": "unset", "stdin": "unset",
             "foreign": "off", "env": "unset", "make_vuln": "unset",
             "argv": "unset", "weak_random": "unset", "hardcoded": "unset",
             "db_rows": "unset", "report_cmdline": "unset", "...": "unset" } }

Set a taint source

PUT /api/machine_taint/ sets one setting in one scope and answers 204.

PUT /api/machine_taint/

JSON body: machine (a public_id, or "" for global), source (a key the read returns) and state (on, off or unset). An unknown key or state is a 400.

curl -s -X PUT https://eyalsec.com/api/machine_taint/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"machine":"3f6c1a52-8e0b-4d2a-9c1e-5b7d2f0a9e41","source":"socket","state":"on"}'

When a change reaches a running program depends on the product: es-python applies taint changes when the program next starts. See when it applies. es-chromium does not fetch this configuration at all, so nothing set here reaches it.

Which keys a product uses

The API accepts every key for every scope, but each product reads only its own, and ignores the rest rather than treating them as something else. Each product's Filters page shows the keys that product offers.

For es-python the keys are socket, file, stdin, foreign, env, make_vuln, argv, weak_random, hardcoded, identity, db_rows and handoff, plus three that decide what is sent with each event rather than what is tracked: report_cmdline (the command line), report_env (environment variables) and report_code (source code). See Taint sources for what each one watches.

Two keys are spelled differently in a rule. The value you send here is a setting key, with underscores; a rule's source field takes a source name. They differ in two places: the setting weak_random is the rule source weak-random, and the setting db_rows is the rule source db. A rule written with the setting spelling is refused. See spelling.

Unique events

The unique-event definition decides which differences make two detections separate events. Detections that match on every field of the definition land on one event row whose count goes up. See Unique event.

The definition always includes a fixed baseline you cannot switch off: your account, the product, and the sink. On top of it you choose any of these fields:

Field Splits events by
source The taint chain: the same sink reached by a different path.
detail The detail line, such as the page URL or origin token.
trace The stack trace: one sink reached from different call paths.
machine The reporting machine, instead of merging your machines into one row.
origin The taint source's origin block.

The built-in default is source and detail.

Read the definition

GET /api/event_uniqueness/ returns the definition in force for one product and scope. agent_kind is required; machine is a public_id, or empty for your account default.

GET /api/event_uniqueness/?agent_kind=python
{ "agent_kind": "python", "machine": "", "axes": ["source", "detail"],
  "inherited": true,
  "available": ["source", "detail", "trace", "machine", "origin"],
  "baseline": ["account", "agent", "sink"] }

axes is what applies after resolving: the machine's own setting, else your account default for that product, else the built-in default. inherited is true when this exact scope has no setting of its own.

Set the definition

PUT /api/event_uniqueness/ sets the definition for one product and scope and answers 204.

PUT /api/event_uniqueness/

JSON body: agent_kind (required, such as python), machine (a public_id, or "" for your account default) and axes (any of source, detail, trace, machine, origin). An empty list [] keeps only the baseline. Leave axes out entirely to remove this scope's own setting so it inherits again; that is how you reset a machine to your account default.

curl -s -X PUT https://eyalsec.com/api/event_uniqueness/ \
  -H "X-API-Key: es2_EXAMPLEKEYdoNotUse0000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"agent_kind":"python","axes":["source","detail","trace"]}'

The change applies to detections from now on; it does not regroup what is already stored. A field that was not part of the definition was not kept for each detection: when detections merged, only the latest one's trace and origin were kept. So turning a field on later cannot split events that already merged. Your event quota counts events, so a finer definition, which turns the same detections into more events, reaches the quota sooner.

Something unclear or missing on this page? Email support@eyalsec.com.

EyalSec Pricing Docs Security Contact Login Book a live demo