top of page

We Shipped a Threat Intelligence Graph. 20 Minutes Later, France Tested It.

  • Writer: Patrick Duggan
    Patrick Duggan
  • Mar 3
  • 4 min read

# We Shipped a Threat Intelligence Graph. 20 Minutes Later, France Tested It.


At 2:36 PM Central on March 3, 2026, we deployed threat intelligence graph traversal to the Butterbot analytics platform. Five new API endpoints. Zero new infrastructure. One POST request can now answer "show me everything 2 hops from Fancy Bear" against 952K IOCs, 350 named adversaries, 16K threat intelligence pulses, 1.2M firewall block events, and 1,500 CISA Known Exploited Vulnerabilities.


By 2:55 PM, someone in France volunteered to be the first real-world test case.


The Architecture



Our ICIJ offshore graph has explicit edges — 3.3 million relationship records that say "Entity A connects to Entity B." Simple. You store the edge, you traverse the edge.


Threat intelligence doesn't work that way. The connections are implicit. A malware family name links an IOC to an adversary. That adversary appears in threat pulses. Those pulses share indicators with firewall block events. The edges exist, but nobody stored them. They're scattered across five indexes with different schemas, different naming conventions, and different levels of confidence.


Until today, answering "what is connected to this IP" meant running dozens of manual searches and stitching the results together in your head. Now it's one API call. The system builds a graph on demand from those implicit edges, runs centrality analysis via graphology, caches the result for five minutes, and garbage collects it. No graph database. No pre-computed edge store. Meilisearch IS the graph store.


The edge confidence model ranges from 90 (direct IP match between an IOC and a block event) down to 40 (loose ransomware campaign attribution from CISA KEV data). Every edge in the response carries its confidence score. We don't pretend all connections are equal.


The Uninvited Guest



Twenty minutes after deployment, Cloudflare lit up. 2,091 requests in one hour. 1,351 flagged as threats. 65% threat traffic ratio.


The source: a single IP — 185.177.72.52 — on ASN BUCKLOG, a French hosting provider. Ninety-six requests in two hours, every single one a credential probe.


> /frontendfinaltest/.env


> /grems-frontend/.env


> /InstantCV/server/.env


> /docker/database/.env


> /backend/config.php


> /private/secret.txt


> /vendor/autoload.php


> /phpinfo-preprod


Classic .env spray. The attacker assumes you're running a Node.js or Laravel app with a misconfigured web server that serves dotfiles. They want your database credentials, your API keys, your JWT secrets. It's the digital equivalent of jiggling every door handle on the block at 3 AM.


Against a Wix frontend behind Cloudflare, this does absolutely nothing. Wix doesn't serve dotfiles. Cloudflare ate most of it before it even reached us.


First Blood



So we pointed the new threat graph at the scanner.


> POST /api/v1/graph/threat/traverse

> {"ioc": "185.177.72.52", "depth": 2}


Result: 15 nodes, 30 edges, 1 connected component. Five IOCs (the IP appears in our threat feeds), five pulses connected via malware family, five block events from prior encounters. Graph density of 0.29. Betweenness centrality of 0.63 on the origin node — meaning this IP is the sole broker connecting everything in its subgraph.


Translation: solo operator, single-purpose scanner, no ties to any named APT group, not part of a larger campaign. A mosquito, not a wasp.


The entire trace took under two seconds. The second query hit cache and returned instantly.


What This Means



Before today, we had 952,000 indicators of compromise sitting in an index with implicit edges that nobody could traverse. A researcher asking "show me everything related to Fancy Bear" would get a search result — a flat list of documents. Now they get a graph. Thirty nodes. Thirty-eight edges. Centrality scores identifying which entities are structural brokers. Connected component analysis showing whether the threat landscape fragments into clusters or forms a unified campaign.


The Fancy Bear traversal at depth 2 reveals connections to Cobalt Strike C2 campaigns, Kimsuky overlaps, SloppyMIO malware hashes, and phishing infrastructure — all linked through shared malware families and attributed IOCs. That's not a search result. That's an intelligence product.


Five endpoints, no new dependencies, no new infrastructure, zero incremental monthly cost. The graph exists only when someone asks for it, lives in memory for five minutes, then disappears. The 200-node cap and 30-edge-per-node limit prevent hub explosion — Emotet alone has tens of thousands of IOCs, and without caps, a single depth-2 query could trigger 900 searches.


The Confidence Problem



Every edge in the threat graph carries a confidence score, and we publish the model openly.


A direct IP match between an IOC and a block event gets 90. A CISA KEV CVE chain to an IOC gets 80. A malware family linking an IOC to a named adversary via STIX standards gets 70. Peer IOCs sharing the same malware family get 55. A loose ransomware campaign attribution gets 40.


We cap confidence at 95% across the platform. We guarantee 5% bullshit exists. This is honest. Claiming 100% confidence in threat attribution is either lying or ignorance, and both are worse than admitting uncertainty.


The French Connection



BUCKLOG isn't in any of our adversary databases. They're not APT28. They're not a named threat actor. They're a French hosting provider whose customers run automated vulnerability scanners against every domain they can find, hoping someone left a .env file exposed with production database credentials.


It happens every day. It will happen tomorrow. Cloudflare handles it. The interesting part isn't the attack — it's that we can now graph it in two seconds and confirm it's nothing, instead of spending twenty minutes checking five different indexes manually.


That's the whole point. Not catching sophisticated nation-state actors (though the graph handles those too). Making the boring stuff fast so you can spend your time on what matters.


The threat intelligence graph traversal API is live at analytics.dugganusa.com for Professional+ tier subscribers. Documentation at /api/v1/graph/help.





*Her name was Renee Nicole Good.*


*His name was Alex Jeffery Pretti.*

 
 
 

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page