Skip to content
Last updated

Custom detections: Specification

Custom detections let admins write their own detection rules. Use them to identify browser-based threats specific to your organisation.

Rules are written in YAML. A configuration file may contain one or more rules, separated by --- (standard YAML multi-document syntax). Push validates the configuration against this specification when you save a custom detection.

Rule structure

Each rule is a YAML document with the following top-level keys:

Key Required Description
inputYesThe data source the rule operates on.
metadataYesIndicator configuration for the rule.
conditionsYesLogic that determines when the rule fires.
descriptionNoA note for your own reference. Not used at runtime.
min_specNoMinimum specification version required to evaluate this rule.
extension_version_constraintsNoRestrict the rule to specific extension versions.

input

One of:

  • dom_content — Match against the page DOM (CSS selectors, HTML comments, page URL, document title, JavaScript-set cookies).
  • web_request — Match against outgoing HTTP requests.
  • web_response — Match against incoming HTTP responses.

metadata

Key Required Description
indicatorYesAn ENUM_STYLE string labelling the specific indicator matched by this rule. Must match ^[A-Z0-9_]+$. You may use any value, e.g. TORRENT_MAGNET_LINK.

conditions

Conditions define when the rule fires. The structure determines how they are combined:

  • A map (key-value pairs at the same level) combines conditions with logical AND — all must match.
  • A list combines conditions with logical OR — any must match.

These can be nested to express more complex logic. The following example requires method AND request_url, with request_url being evaluated as (path endswith /submit.php):

conditions:
  method: POST
  request_url:
    path|endswith: /submit.php

DOM content rules (input: dom_content)

Key Description
css_selectorsMatch elements in the page DOM.
html_commentsMatch HTML comments in the document.
urlMatch the page URL (window.location.href). See URL conditions.
document_titleMatch against document.title.
document_cookiesMatch cookies accessible via document.cookie (key-value test).

CSS selectors

A selector entry can be a plain string (used directly with querySelector()), or a map with the following keys:

Key Description
selectorCSS selector using querySelector() — matches the first element.
selector_allCSS selector using querySelectorAll() — matches all elements.
text_contentTest the element's textContent.
text_nodesTest the concatenated value of child text nodes.
inner_htmlTest the element's innerHTML.
outer_htmlTest the element's outerHTML.
conditionFor selector_all only. Use all to require every matched element to pass the test. Default is any.
# Match any <a> inside a <p> that contains "Create one!"
css_selectors:
  selector: p > a
  text_content|includes: Create one!
# All <script> elements must contain "atob("
css_selectors:
  selector_all: script
  text_content|includes: atob(
  condition: all

HTML comments

Match against HTML comment content. A plain string checks for exact equality. Use a named key with a modifier for other tests:

# Match either comment (OR)
html_comments:
  - ex1|includes: example text
  - ex2|startswith: another example

# Both comments must match (AND)
html_comments:
  ex1|includes: example text
  ex2|startswith: another example

HTTP request rules (input: web_request)

Key Description
methodHTTP method, e.g. GET, POST.
request_urlMatch the request URL. See URL conditions.
tab_urlMatch the URL of the browser tab at the time of the request. See URL conditions.
typeResource type, e.g. script, xmlhttprequest, main_frame.
bodyRaw request body.
form_dataParsed form data for multipart/form-data and application/x-www-form-urlencoded requests (key-value test).
request_headersHTTP request headers (key-value test).

Note: A rule that tests request_headers cannot also test body. These come from different browser extension events.

input: web_request
metadata:
  indicator: SUSPICIOUS_FORM_SUBMISSION
conditions:
  method: POST
  request_url:
    path|endswith: /collect
  form_data:
    - name: email
      value|exists: true

HTTP response rules (input: web_response)

Key Description
methodHTTP method.
request_urlMatch the request URL. See URL conditions.
tab_urlMatch the URL of the browser tab. See URL conditions.
typeResource type.
status_codeHTTP response status code.
response_headersHTTP response headers (key-value test).
cookiesCookies from set-cookie response headers (key-value test).
input: web_response
metadata:
  indicator: TRACKING_COOKIE_SET
conditions:
  cookies:
    - name: tracking_id
      value|exists: true

URL conditions

A URL condition can be:

  1. A plain string — tested against the full URL (exact equality after trimming, or with a modifier).
  2. A map targeting specific URL components.
Component Description Example value
hrefFull URLhttps://a.b.example.co.uk:8080/login?x=y#h
schemeProtocol, without :https
originScheme + host + porthttps://a.b.example.co.uk:8080
hostHostname + porta.b.example.co.uk:8080
hostnameFull hostnamea.b.example.co.uk
subdomainSubdomain parts onlya.b
sldSecond-level domainexample
tldTop-level domainco.uk
rootHostname without subdomainexample.co.uk
pathURL path/login
paramsFull query string?x=y
hashFragment#h
portPort number (blank if the default for the protocol)8080
search_paramsParsed query parameters (key-value test)
hostname_partsArray of hostname parts split on . — matches if any part matches
# Path ends with /login
request_url:
  path|endswith: /login

# Any part of the hostname equals "ipfs"
request_url:
  hostname_parts: ipfs

# Query parameter "token" exists
request_url:
  search_params:
    - name: token
      value|exists: true

Key-value tests

Conditions for search_params, form_data, request_headers, response_headers, cookies, and document_cookies are key-value tests. Use name and value sub-keys to match against entries:

# Any query parameter starting "user_" with a numeric value
request_url:
  search_params:
    - name|startswith: user_
      value|re: ^[\d-]+$
# Match a form submission containing an email at a specific domain
form_data:
  - name: email
    value|endswith: @example.com
  - name: password
    value|exists: true

Test modifiers

Append modifiers to a condition key with |:

Modifier Description
(none)Trim the value and check exact equality.
|includesString contains the match.
|startswithString starts with the match.
|endswithString ends with the match.
|reString matches the regular expression.
|normalizeCollapse whitespace, remove zero-width characters, and lowercase before testing.
|existsBoolean — whether the named property exists (true) or does not exist (false).
|lengthLength of a string, or count of items in cookies, form_data, or search_params.

Modifiers can be stacked. Unknown modifiers are ignored, which allows applying multiple tests of the same type to a single key — all must match:

# Normalize then check equality
text_content|normalize: example text

# All three includes tests must match
css_selectors:
  selector_all: script
  text_content|includes|a: fetch(
  text_content|includes|b: atob(
  text_content|includes|c: document.write(

Note: Wildcard tests (includes and re) are performed on values truncated to 500,000 characters.


Extension version constraints

Use extension_version_constraints to restrict a rule to specific extension versions — for example, to require a minimum version for a feature the rule depends on, or to avoid a version with a known bug.

Specify a list of version ranges. Items in the list are combined with OR. Multiple constraints within a single item are combined with AND.

extension_version_constraints:
  - ">=2.5.0"
  - ">=1.9.0 <2.0.0"

Supported operators: <, <=, >, >=, !=.


Full example

---
description: Detect requests using the magnet protocol
input: web_request
metadata:
  indicator: TORRENT_MAGNET_LINK_DETECTED
conditions:
  request_url:
    scheme: magnet
---
description: Detect form submissions to a known data collection endpoint
input: web_request
metadata:
  indicator: SUSPICIOUS_FORM_SUBMISSION
conditions:
  method: POST
  request_url:
    path|endswith: /collect
  form_data:
    - name: email
      value|exists: true