TLQL (Threadlinqs Query Language) is a compact, SPL-inspired query language built specifically for filtering threat intelligence. It powers the global search bar on intel.threadlinqs.com and the filter engine behind My Feeds. This guide is the canonical reference for every field, operator, and keyword TLQL supports.
TL;DR — TLQL lets you write expressions like
Threat.Severity = "CRITICAL" AND Category IN ("MALWARE", "SUPPLY_CHAIN") AND Threat.Detection.Count > 0 AND NOT Threat.MITRE = T1566
to instantly filter the platform's 500+ threats and save the result as a recurring feed.
Where TLQL Works
You can use TLQL in two places today:
- Main feed search box — Click
$ searchin the threat feed header. Anything that contains an operator like=,IN,AND, or starts with|is parsed as TLQL; otherwise it falls back to plain keyword search. - My Feeds builder modal — When you create or edit a feed at /my-feeds, an auto-generated TLQL string appears below the structured filter controls. You can edit it directly to express logic the dropdowns can't (parenthesised OR groups, exclusions, comparisons).
The query you write in either place doesn't just narrow the threat list — it also drives every feed-view module you enable on the feed (IOCs, detections, CVEs, threat actors, tags, MITRE techniques, timeline, etc.). The modules aggregate data from the threats that match your TLQL. See TLQL and feed-view modules below for the per-module field mapping.
Grammar at a Glance
tlql// Optional pipe prefix (SPL-style, ignored by the parser)
| search <expression>
// expression = a tree of comparisons combined by AND / OR / NOT
<expression> := <term> ( (AND | OR) <term> )*
<term> := NOT <term> | <primary>
<primary> := "(" <expression> ")"
| <field> <op> <value>
| <field> IN "(" <value-list> ")"
| <field> NOT IN "(" <value-list> ")"
| "<bare-string>"
<op> := = != > >= < <= LIKE CONTAINS
<value> := "string" | number | identifier
Implicit AND is allowed between adjacent terms — these are equivalent:
tlqlSeverity = "HIGH" AND Category = "MALWARE"
Severity = "HIGH" Category = "MALWARE"
Operators
| Operator | Meaning | Example |
|---|---|---|
= | Equals (case-insensitive for strings/enums; numeric for numbers) | Severity = "CRITICAL" |
!= | Not equals | Status != "PATCHED" |
> >= < <= | Numeric comparison | Threat.CVSS >= 7 |
IN ( ... ) | Membership against a list | Category IN ("MALWARE", "SUPPLY_CHAIN") |
NOT IN ( ... ) | Negative membership | Severity NOT IN ("LOW", "INFO") |
CONTAINS | Substring match (case-insensitive) | Threat.Title CONTAINS "ClickFix" |
LIKE | Wildcard pattern. * and % match any run; _ matches one char | Threat.CVE LIKE "CVE-2026-*" |
Logical Composition
| Keyword | Meaning |
|---|---|
AND | Both sides must match |
OR | Either side may match |
NOT | Inverts the next term. Wraps a single comparison or a parenthesised expression. |
( ) | Grouping. Use parentheses to override default precedence. |
Precedence: NOT binds tightest, then AND, then OR. Always use parentheses when mixing AND and OR — it makes intent explicit.
tlql// "Critical or High severity, but not patched"
(Severity = "CRITICAL" OR Severity = "HIGH") AND Status != "PATCHED"
// Same query, more concisely
Severity IN ("CRITICAL", "HIGH") AND Status != "PATCHED"
Bare Strings
A quoted string without a field on the left becomes a free-text match — it scans the threat's title, summary, description, tags, CVE list, threat actor name, and actor aliases. This is the easiest way to "track every mention of X":
tlql"ClickFix" // track every ClickFix variant or write-up
"ClickFix" AND Severity = "HIGH" // narrow to high-severity ClickFix threats
"Cobalt Strike" OR "BloodHound" // tool-mentions across description & tags
Field Reference
Every field is case-insensitive — Severity, severity, and SEVERITY are equivalent. Many fields have short aliases (e.g. Tag for Threat.Tag).
Threat metadata
| Field | Type | Description & example |
|---|---|---|
| Threat.ID | string | Threadlinqs threat identifier — Threat.ID = "TL-2026-0507" |
| Threat.Title | string | Headline — Threat.Title CONTAINS "NPM" |
| Threat.Summary | string | Short summary — Summary CONTAINS "zero-day" |
| Threat.Description | string | Full description body — Description CONTAINS "lateral movement" |
| Threat.Created | date | ISO 8601 creation timestamp — Created > "2026-05-01" |
| Threat.CreatedDays | number | Days since creation (numeric) — CreatedDays < 7 for "this week" |
| Threat.Updated | date | Last-updated timestamp |
Severity, category, and status
| Field | Type | Allowed values |
|---|---|---|
Threat.Severity (alias: Severity) | enum | CRITICAL, HIGH, MEDIUM, LOW, INFO |
Threat.Category (alias: Category) | enum | MALWARE, VULNERABILITY, PHISHING, SUPPLY_CHAIN, DATA_BREACH, THREAT_INTEL, APT, ICS_SCADA |
Threat.Status (alias: Status) | enum | ACTIVE, MONITORING, TRACKING, PATCHED, RESOLVED |
Threat.Exploitability (alias: Exploitability) | enum | ACTIVE (in-the-wild), WEAPONIZED, POC_PUBLIC, CONFIRMED, THEORETICAL, N/A |
Threat.CVSS (alias: CVSS) | number | CVSS base score 0–10 — CVSS >= 9 |
Attribution & targeting
| Field | Type | Example |
|---|---|---|
Threat.Actor (alias: Actor) | string | Actor CONTAINS "Lazarus" |
Threat.NationState (alias: NationState) | string | NationState IN ("Russia", "China", "DPRK") |
| Threat.Motivation | string | Motivation = "FINANCIAL" |
Threat.Sector (alias: Sectors) | array | Sector IN ("financial", "healthcare") |
Threat.Region (alias: Region) | array | Region = "EMEA" |
Tags, identifiers, MITRE
| Field | Type | Example |
|---|---|---|
Threat.Tag (alias: Tag, Tags) | array | Tag IN ("clickfix", "fake-captcha") |
Threat.CVE (alias: CVE) | array | CVE LIKE "CVE-2026-*" |
Threat.CWE (alias: CWE) | array | CWE = "CWE-94" |
Threat.MITRE (alias: MITRE) | array | MITRE = "T1566" — matches the technique ID anywhere on the threat |
Threat.MITRE.Tactic (alias: Tactic) | array | Tactic = "initial-access" |
Detections & IOCs
| Field | Type | Example |
|---|---|---|
Threat.Detection.Count (alias: Detections) | number | Number of detection rules on the threat — Detections > 2 |
| Threat.Detection.Type | array | Rule formats: spl, kql, sigma, cql, yara — Detection.Type = "sigma" |
Threat.IOC.Count (alias: IOCs) | number | Total IOCs on the threat — IOCs > 0 |
| Threat.IOC.Type | array | IOC types: ip, domain, url, hash, email, etc. — IOC.Type = "domain" |
| Threat.IOC.Value | array | Match raw IOC values — IOC.Value LIKE "*.tor2web.io" |
TLQL and Feed-View Modules
A saved feed renders matching threats through one or more modules. TLQL filters which threats feed every module, so any expression below scopes every section of the feed view simultaneously. The 11 modules currently available, and the TLQL fields you'd use to filter their data, are:
| Module | What it shows | Relevant TLQL fields | Min tier |
|---|---|---|---|
| threats | Threat cards (default) | All Threat.* fields | 0 / Blue |
| detections | Flat list of detection rules (SPL / KQL / Sigma / YARA) | Threat.Detection.Count, Threat.Detection.Type, Threat.Detection.Severity | 1 / Blue |
| iocs | Deduped IOCs grouped by category (network / file / behavioural) with sub-type pills | Threat.IOC.Count, Threat.IOC.Type, Threat.IOC.Value | 2 / Red |
| simulations | Lab simulations for the matched threats | (derivative — scoped by any Threat.* filter) | 3 / Purple |
| references | External write-ups (deduped by host) | (derivative — bare-string searches scan reference titles) | 0 / Blue |
| affected_products | Vendor / product / vulnerable + fixed version lists | (derivative — use Threat.CVE or bare strings against vendor names) | 0 / Blue |
| mitre_techniques | Frequency table of MITRE techniques + tactic filters | Threat.MITRE, Threat.MITRE.Tactic | 0 / Blue |
| timeline (new) | Chronological events across matched threats with event-key pills | (derivative — narrow by any Threat.* filter; e.g. CreatedDays < 7 for recent activity) | 1 / Blue |
| threat_actors (new) | Deduped actor cards with nation-state + motivation pills | Threat.Actor, Threat.NationState, Threat.Motivation | 1 / Blue |
| cves (new) | CVE catalogue with CVSS bands, EPSS%, and CISA KEV flags | Threat.CVE, Threat.CVSS (EPSS / KEV are display-only badges today) | 2 / Red |
| tags (new) | Tag frequency table across matched threats | Threat.Tag | 1 / Blue |
Toggle modules on or off when editing a feed at /my-feeds. Click any row inside a module to expand it inline — IOCs reveal a copy button + all source threats, detection rows reveal the full rule body, CVEs link to NVD, MITRE rows link to attack.mitre.org. The → TL-XXXX chip on each row jumps to the threat detail (back-button returns to your feed).
Worked Examples
Track every ClickFix variant or campaign
tlql"ClickFix"
// or, narrower:
"ClickFix" AND Severity IN ("CRITICAL", "HIGH")
Save this as a feed named ClickFix Tracker. Every time a new ClickFix-related threat is published, it shows up in your sidebar with an unread badge.
Every campaign attributed to a specific actor
tlqlActor CONTAINS "Lazarus" OR Actor CONTAINS "TraderTraitor"
NPM/Node supply-chain compromises with detections
tlqlThreat.Title IN ("NPM", "Node") AND Category IN ("SUPPLY_CHAIN") AND Threat.Detection.Count > 2 AND Severity IN ("HIGH", "CRITICAL") AND NOT Threat.MITRE = T1566 AND "TeamPCP"
This is the example from the launch post — read it left-to-right: "NPM or Node threats classified as supply chain with more than 2 detection rules, severity High or Critical, that do not use T1566 phishing, and somewhere mention TeamPCP".
Active, weaponized, high-CVSS vulnerabilities in your stack
tlqlCategory = "VULNERABILITY"
AND Exploitability IN ("ACTIVE", "WEAPONIZED")
AND CVSS >= 8
AND (Threat.Title CONTAINS "Apache" OR Threat.Title CONTAINS "Tomcat" OR "log4j")
Newly disclosed Russian APT activity, this week
tlqlNationState = "Russia" AND Category IN ("APT", "THREAT_INTEL") AND CreatedDays < 7
Sigma-rule-covered ransomware
tlql"ransomware" AND Detection.Type = "sigma"
Anything affecting healthcare in EMEA without an active patch
tlqlSector = "healthcare" AND Region = "EMEA" AND Status != "PATCHED"
External write-ups + exploit code for threats with public PoCs — feeds the references module
tlqlExploitability = "POC_PUBLIC"
Enable the references + threats modules on the feed. Any GitHub, exploit-db, gist, or vendor write-up on a PoC threat surfaces in the references list grouped by host. Pair with the cves + affected_products modules to see CVSS / EPSS and which vendor versions are affected.
Critical CVEs with active exploitation — feeds the cves module
tlqlCategory = "VULNERABILITY" AND CVSS >= 9 AND Exploitability IN ("ACTIVE", "WEAPONIZED")
Enable the cves module on the feed. Each CVE row shows its CVSS band, EPSS%, and a CISA KEV badge when applicable; clicking opens an NVD link.
State-sponsored activity in the last 30 days — drives threat_actors, timeline, tags
tlqlNationState IN ("Russia", "China", "DPRK", "Iran") AND CreatedDays < 30
Pair with the threat_actors module to see deduped actor cards with motivation / nation-state pills, the timeline module for chronological events across all matches, and tags for the most common labels used across this slice.
Tips & Gotchas
- Strings should be quoted. Use double quotes for safety:
"CRITICAL". Identifiers likeT1566work bare, but quoting everything is the safe habit. - Wildcard
*works only withLIKE.Title CONTAINS "click*"looks for the literal stringclick*. UseTitle LIKE "click*"for wildcards. - Beware of
!=with enums.Severity != "LOW" OR Severity != "MEDIUM"is always true (every severity is unequal to at least one). UseSeverity NOT IN ("LOW", "MEDIUM")orNOT (Severity IN ("LOW", "MEDIUM")). - The bare-string trick works on title, summary, description, tags, CVE, and actor name. Useful for "track every mention of X regardless of category."
- Combine with manual pins. When saved as a My Feed, you can still manually pin a threat that doesn't match, or exclude a false positive. The feed is auto-filter + manual override.
- Live preview. The builder modal at /my-feeds shows the current match count as you type. If it says
0unexpectedly, your TLQL probably has a logic error.
How TLQL Maps to the Platform
Every TLQL query is parsed into an abstract syntax tree (AST) and evaluated against each threat object. The same parser runs in the browser (live search, modal preview) and on the Cloudflare Worker that powers feed notifications and the sidebar count badges — so what you see in the preview is exactly what the server uses to compute notifications when a new threat is published.
The TLQL engine lives at /scripts/tlql.js (frontend) and is mirrored inside the worker. Field accessors normalize values (uppercase severity/category enums, lowercase tags, JSON parsing for arrays), so you don't have to think about case or representation.
What TLQL Isn't (Yet)
TLQL is intentionally small. Some things not in scope:
- Joins or pipes like
... | stats count by Severity— that's planned but not shipping today. - Regular expressions on arbitrary fields — use
LIKEwith*wildcards. - Time arithmetic like
now() - 7d— for "last 7 days," useCreatedDays < 7. - Custom field aliases per user — the built-in aliases cover the common cases.
If you find yourself wanting one of these, tell us — we add fields and operators based on demand.
Quick Reference
// quick_ref
tlql// Operators: = != > >= < <= IN NOT IN CONTAINS LIKE
// Logical: AND OR NOT ( )
// Strings: "double-quoted"
// Wildcards: LIKE "click*" or LIKE "%click%"
// Bare: "ClickFix" — matches title/summary/desc/tags/CVE/actor
// Optional: | search ... (Splunk-style prefix, ignored)
// Top-used fields
Threat.Severity Threat.Category Threat.Status
Threat.Title Threat.Summary Threat.Description
Threat.Actor Threat.NationState Threat.Motivation
Threat.Tag Threat.CVE Threat.CWE
Threat.MITRE Threat.MITRE.Tactic
Threat.CVSS Threat.Detection.Count Threat.IOC.Count
Threat.Sector Threat.Region
Threat.Created Threat.CreatedDays