The theme was Let’s Dig In, and our first ideas were all about literal digging. We changed our minds a few times. We started on a project that turns Minecraft builds into real-world building estimates, then a history project about Madison, and we dropped both before landing here.

What made it click was roots. Underground, roots connect parts of a forest that look completely separate from above. Attacks work like that too. When someone steals one account, nothing screams. There’s one odd login, one server that account never touches, one quiet connection to somewhere outside. Each one is easy to shrug off. Spread across a few accounts and devices, they add up to something. Most tools look at events one at a time, so they miss it. We wanted to look at the connections instead, and to explain what we found in plain words that a tired analyst could check.

What RootNet does

It takes a company’s activity (accounts, devices, servers, outside addresses) and draws it as a network. At first everything looks normal, because it mostly is. Then you press Analyze Network, and RootNet compares the last three days with ten days of normal behavior. In about half a second a hidden group lights up in red.

Click any node and it tells you why in plain language, like “no activity for 10 days, then 15 events in 3 days, used by three different accounts, all at night.” You can replay the raw event feed and watch the attack assemble in the order it really happened, or flip to an orbital view where it arcs across every ring. A Databricks model writes up the investigation, and our code checks the write-up against the findings before you see it.

The data is simulated: 79 accounts, devices, servers and outside addresses, and about 2,150 events, with one attack hidden inside. The outside addresses are from the ranges reserved for documentation, so none belongs to a real machine. Hit New network and it builds a different company with the attack hidden somewhere new, then finds it again.

How we built it

We wrote the simulation first, including an attack and, on purpose, some decoys: an IT admin who works at night and touches sensitive servers all the time, a new hire whose activity is all “new”, and shared terminals. If the attack is the only strange thing in the network, any detector looks brilliant, and we didn’t want to fool ourselves.

The detector works out features from the events, scores every connection and every entity with an Isolation Forest, then spreads suspicion only along the unusual connections with personalized PageRank. The final score blends three signals:

100 * min(1, 0.5a + 0.3e + 0.2s)

where a is how odd an entity is on its own, e is the oddest connection it’s part of, and s is suspicion that reached it through the graph.

On Databricks, every run lands in Delta tables (raw events, scored entities, and views for analysts), Genie answers questions about them, MLflow records each run, and a Llama model writes the report. The interface is a FastAPI app with a graph console built on Cytoscape.js.

What we found, and what we didn’t

We grade it against the planted attack afterwards. The detector never sees the answer, and there’s a test that proves it.

RootNet Judging each event alone

Entities an analyst has to review: 6, 15 Precision: 100%, 47%

Over 10 different random networks, the ranking score (AUC) stayed between 0.996 and 0.998, and precision between 0.86 and 1.0.

The messy parts The first replay lit up 57 connections, not the 13 that mattered. It looked impressive and told no story. We had to decide what actually belongs to the attack and make the replay and the graph agree. Genie told us it had no data about access events. It was right: we’d left that table out of the space. Later we found that loading each run added another copy of the events, so we built a “latest run” view to stop it double-counting. The language model kept wanting to be dramatic. So the report can only mention accounts and addresses that really are in the findings, and anything claiming a named attacker, ransomware or stolen data gets thrown out.

What surprised us

If you just count who touched the finance database at night, the loudest person is the IT admin, who does that every week. The attackers touched it less. Only the relationships give them away: a device nobody had used for ten days, shared by three accounts, talking to an address nothing had contacted before. That’s why every flag in RootNet comes with its reasons, because a bare risk score of 93 doesn’t help anyone.

What’s next

We’d like to feed it real authentication and network logs instead of a collected dataset, run the detector as a Databricks job, deploy it as a Databricks App, and let analysts mark findings as confirmed or dismissed so the scores get better over time.

Built With

Share this project:

Updates

Submission history