You don’t query a threat graph in SQL
When the only data you had was rows in a table, SQL was the right tool. Threat intel hasn’t lived in rows for a long time. Adversaries, infrastructure, indicators, campaigns: they form a graph. You need a query language that walks.
ICDB ships with one. It’s called ICQL (Intel Consortium Query Language), it lives in the search bar at the top of every page, and the entire syntax fits on a single screen. This post is the five-minute tour.
The simplest query is a noun
Type a node type. Get every node of that type:
clusterThat’s it. Every cluster in your graph, rendered in the canvas. Now narrow with a property filter:
nbi.value="1.2.3.4"Network-based indicator, value exactly 1.2.3.4. The query bar takes eight comparison operators (=, !=, ~=, !~=, >, <, >=, <=), so the same shape covers exact IPs, substring searches on hashes (hbi.sha256~="a1b2c3"), and date ranges (hbi.first_seen>="2026-01-01").
String values quoted, numbers bare. That’s the only rule.
Then you start walking
The real point of a graph query language is the arrow:
nbi.value="1.2.3.4" >+forms> clusterRead this left to right: “Start at the NBI 1.2.3.4, follow every outgoing forms edge, return the clusters you land on.” One keystroke and you’ve turned an IOC into the threat actor it belongs to.
Chain arrows to go further:
nbi.value="1.2.3.4" >+forms> cluster >+related_to> clusterIP → cluster → related cluster, in one line. Flip the arrows to walk backwards (<+forms<) and you’ll go the other way: “Show me every NBI that forms APT29.”
When you don’t know what you’re looking for
Sometimes the question isn’t “where does this edge go,” it’s “show me everything connected to this thing.” That’s from:
from nbi.value="malware.example.com" limit 200Recursive traversal. ICDB walks outward from your starting node, following any edge type, until it runs out of neighbors or hits the limit. The result is the whole neighborhood: every cluster, indicator, detection, or label that touches your starting node.
This is the query you reach for when triage hands you a single artifact and asks “what is this connected to?”
You can write data too
ICQL isn’t read-only. Wrap a statement in mutation { ... } and you’re creating nodes:
mutation { cluster.name="Scattered Spider" cluster.+label.sector="crime" }Every mutation lands in the audit log. TLP rules apply at write time. The same query bar that ran your last traversal can stand up a new cluster, label it, and link it, without ever clicking into a form.
A workflow, end to end
Here’s the move you’ll do a hundred times. An analyst hands you a domain. You drop it in the bar:
from nbi.value="malware.example.com" limit 100The canvas blooms. You see three clusters connected by forms edges, a related cluster two hops out, an HBI sample at the bottom. You squint at the cluster names. One of them is the actor you’ve been tracking for a quarter. Save the query so you can re-run it tomorrow, and attach the subgraph to an Insight if you want to write up what you found and ship it to the consortium.
Three keystrokes. Real work.
Where to go from here
- Press
?on the Explore page to see every keyboard shortcut, includingCmd+Enterto run the query you’ve typed. - Open the in-app ICQL guide (Docs → ICQL Query Language) for the full reference: every operator, every traversal shape, mutation forms, union queries with
;, and TLP scoping via aconsortium="<uuid>"filter on any node type. - Try a union in your next session:
hbi limit 10; nbi limit 10shows you ten host indicators and ten network indicators side by side in one render.
The graph was always there. ICQL is how you talk to it.