Project pausedOperational costs exceeded runway. Live ingest is offline; historical data shown may be stale. Contact research@boarnet.io for status.

Query DSL

A single syntax drives the Explore editor, Alert Triggers, and the /api/query endpoint. Splunk/Kibana-flavored, single-line, safe to paste into a URL.

Last updated · 2026-04-17

Overview

Queries are composed of predicates (field:value) combined with boolean operators (AND, OR, NOT) and parenthesized groups. Whitespace between predicates is an implicit AND.

tag:credential-stuffing AND fleet:core NOT country:US

Grammar

EBNF
expr       ::= or_expr
or_expr    ::= and_expr ("OR" and_expr)*
and_expr   ::= not_expr (("AND" | implicit) not_expr)*
not_expr   ::= "NOT" atom | atom
atom       ::= "(" expr ")" | predicate
predicate  ::= FIELD (":" | ":" OP) VALUE
OP         ::= "=" | "!=" | ">" | ">=" | "<" | "<=" | "~"
VALUE      ::= bareword | "(" csv ")" | quoted-string

Fields

FieldTypeNotes
ipstringIPv4 address
idstringRecord ID (thr_…)
asnstringASN number, e.g. AS14001
asn_namestringASN operator name
countrystringISO 3166-1 alpha-2
tagstring[]Behavioral tag; matches any element
fleetenumcore or mesh
sensorstring[]Sensor id that observed this IP; supports wildcards (e.g. sensor:mesh-*)
confidencenumber0.0 to 1.0
first_seen, last_seentimeUnix ms or relative (24h, 7d)
noveltimeSugar for “first-seen within the last N”. Bareword form, no operator — novel:24hmatches IPs we’d never seen before today.
ja3, ja4stringTLS fingerprints · paywalled
portnumberAny sighting port
actionenumdrop, rate_limit, monitor

Operators

OpMeaningExample
=Equals (default when omitted)country:RU
!=Not equalcountry:!=US
>, >=Greater thanconfidence:>0.7
<, <=Less thanlast_seen:<24h
~Substring / containsasn_name:~CHOOPA
*Glob wildcard inside the value (anchored). Use with = or !=.tag:tool:sliver*

Wildcards

A literal * anywhere in the value of an = or != predicate is a glob. The pattern is anchored tool:sliver* means "starts with tool:sliver", not "contains it anywhere" (that's ~'s job). Every other regex metachar is treated as a literal, so a tag with a .in it doesn't accidentally match through as regex any-char.

tag:tool:sliver*              # any sliver variant (starts-with)
tag:tool:*-golang             # all golang-family tools (ends-with)
tag:tool:sliver*golang        # middle wildcard
tag:*sliver*                  # contains (same result as tag:~sliver)
asn_name:*DIGITAL*            # fuzzy ASN lookup
tag:(tool:sliver*,tool:chrome*)  # comma-list + wildcard works

Booleans & grouping

AND, OR, and NOT are case-insensitive. Parentheses override default precedence. Adjacent predicates without an operator are implicit AND.

(tag:mirai-variant OR tag:iot-botnet) AND NOT country:US
tag:credential-stuffing  fleet:core    # implicit AND

Values

Three value forms are accepted:

  • Bareword — anything without whitespace or parens: country:RU
  • Quoted — for values with spaces or special chars: asn_name:"Digital Ocean"
  • List — match any of several values: country:(RU,CN,NL)

Relative time

Time fields accept relative shortcuts ending in s, m, h, d, w. They expand to a Unix ms timestamp relative to “now”.

last_seen:<24h          # last 24 hours
first_seen:>7d          # records first seen more than 7 days ago
last_seen:>=30m         # last 30 minutes or older

Paywalled fields

Examples

SSH bruteforce from specific ASN
tag:ssh-bruteforce AND asn_name:~CHOOPA
High-confidence recent activity
confidence:>=0.8 AND last_seen:<1h
IoT botnet outside a known region
(tag:mirai-variant OR tag:iot-botnet) NOT country:(US,CA,GB,DE)
Pro key: pivot by TLS fingerprint
ja4:~t13d0111h2 AND fleet:core
Elasticsearch enumeration across the fleet
tag:probe-family:elasticsearch AND last_seen:<24h
WordPress login scanners, excluding cloud providers
tag:probe-family:wordpress-scan NOT (tag:asn-abuse AND country:US)
Novel attackers in the last 24h (no prior history)
novel:24h AND tag:probe

Probe families

Scan-probe events (synsink captures on our honeypot ports) carry a single probe-family:* tag derived from the raw banner the scanner sent. Facet on it to see what scanners are actually hunting for across the fleet:

probe-family:http                     HTTP request on a web-like port
probe-family:http-on-nonstd           HTTP against a non-web port (signal of a scanner, not a misrouted client)
probe-family:elasticsearch            Hit /_cat, /_cluster, /_nodes
probe-family:java-admin-scan          Tomcat manager, JBoss jmx-console, WebLogic console
probe-family:solr                     /solr/* enumeration
probe-family:wordpress-scan           wp-login, wp-admin, xmlrpc.php
probe-family:phpmyadmin-scan          phpMyAdmin / Adminer hunters
probe-family:secret-hunter            .env / .git / .aws / wp-config leak hunters
probe-family:iot-rce-chain            HNAP / GponForm / boaform / soap.cgi (Mirai family)
probe-family:log4shell                ${jndi:ldap://...} markers anywhere in the request
probe-family:open-proxy-check         CONNECT host:443 HTTP/1.1
probe-family:webdav-scan              PROPFIND
probe-family:tls-on-nontls            TLS ClientHello cipher-suite signature on a non-TLS port
probe-family:ssh-stray                SSH-2.0-... banner on a non-SSH port
probe-family:rdp                      Contains "Cookie: mstshash=" (RDP credential scanner payload, any port)
probe-family:mongodb                  admin.$cmd + isMaster/buildinfo BSON payload
probe-family:mysql                    HandshakeResponse w/ mysql_native_password / libmysql markers
probe-family:redis                    Inline RESP (PING, INFO, CONFIG GET *)
probe-family:memcached                stats / version / get (ASCII protocol)
probe-family:smtp                     EHLO, STARTTLS, MAIL FROM:
probe-family:ftp                      AUTH TLS, FEAT, SYST
probe-family:pop3                     APOP, STLS
probe-family:vnc                      RFB 003.00x
probe-family:postgres                 StartupMessage w/ user= field
probe-family:syn-only                 Client sent zero bytes — pure SYN probe
probe-family:unknown                  Bytes sent but no matcher hit — worth a hex look

Errors

Parse errors are positional — the response includes the character offset of the offending token so an editor can underline it:

{
  "error": "invalid_query",
  "message": "Unknown field \"contry\"",
  "position": 0
}

Paywall errors carry a blocked_fields list so clients can show a targeted upgrade prompt:

{
  "error": "invalid_query",
  "message": "These fields require a Pro key: ja4",
  "blocked_fields": ["ja4"],
  "upgrade_url": "/pricing"
}