‹ Omar Yousef Project // Fragments
Network Security Platform 1st Place CTF · Hack the Bay 2026

Fragments

An AI tool that finds every device on a network, scores how risky each one is, and answers questions about the network in plain English. All AI runs locally.

Fragments scans a network, gives every device a 0 to 100 risk score you can trace point by point, and draws a live map that updates the moment something joins or changes. You can ask it questions about the network, watch a simulated attacker move through it, and export a full PDF security report. Built in six hours at Hack the Bay 2026, where it won 1st place in the CTF and placed 4th overall.

19
REST + WS endpoints
6
Backend subsystems
2
Data stores
23
Backend tests
100%
Local inference
01 Overview

What Fragments does

Fragments discovers every device on a local network, assigns each a 0 to 100 risk score, visualizes the topology in real time, and exposes the whole picture through a retrieval-augmented chat, an attack-path simulator, a compliance assessor, and exportable PDF reports. It ships with a mock mode that runs the entire product offline against a fixed 15-device fixture, so it can be demoed anywhere.

Highlights

  • Award winner. 1st place CTF and 4th place overall at Hack the Bay 2026.
  • Built in six hours as a complete, working product.
  • Explainable scores. Every device's risk score can be traced point by point, no black box.
  • Private by design. The AI runs on the local machine, so the network's weak points never leave it.

The stack

LayerTechnologyWhat it does
APIFastAPI · uvicorn · Python 3.11Async REST + a WebSocket event bus. One process, one background scan loop.
FrontendNext.js 16 · React 19 · TS · D3 v7App-Router dashboard; D3 force-directed topology graph; markdown chat.
RelationalSQLite (WAL)Devices, alerts, scans (+JSON snapshots), frameworks, assessments, CVE cache.
VectorChromaDB (persistent)Cosine HNSW over scan-derived text chunks for RAG retrieval.
LLMOllama · qwen3:30b-a3bLocal inference over HTTP. The network map never leaves the host.
Scannerscapy · python-nmap · icmplib · manufL2 ARP discovery, ICMP sweep fallback, service/OS scan, MAC-vendor lookup.
ReportingreportlabMulti-section security & compliance PDFs.

One decision shapes the whole product: inference runs on a local model through Ollama rather than a hosted API. The tool's entire output is a map of a network's weaknesses, and that map never leaves the host.

02 Architecture

How the pieces fit together

A single FastAPI process fronts six subsystems and two data stores. The browser talks to it over REST for commands and over one WebSocket for live events. Everything that could touch the network or an LLM is isolated behind the scanner and AI subsystems respectively.

%%{init: {'theme':'base','themeVariables':{'background':'#0c0c0e','primaryColor':'#151517','primaryTextColor':'#e6e6e6','primaryBorderColor':'#00ff41','lineColor':'#555','secondaryColor':'#111','tertiaryColor':'#0a0a0a','clusterBkg':'#0c0c0e','clusterBorder':'#262626','fontFamily':'JetBrains Mono, monospace','fontSize':'13px','textColor':'#c0c0c0'}}}%%
flowchart TB
  subgraph CLIENT["Browser · Next.js 16"]
    UI["Dashboard · Devices · Threats
Simulate · Chat · Compliance · Report"] WSH["useWebSocket hook
(auto-reconnect)"] end subgraph API["FastAPI process (async)"] REST["REST router
/api/*"] WS["WebSocket /ws
ConnectionManager"] BG["Background scan loop
every SCAN_INTERVAL"] end subgraph SUB["Subsystems"] SCAN["scanner/
ARP · nmap · OUI · OS"] THREAT["threat/
risk_scorer · cve_lookup"] AI["ai/
analyzer · attack_sim · RAG"] COMP["compliance/
parser · assessor · report"] RPT["report.py
PDF builder"] end subgraph DATA["State"] SQL[("SQLite · WAL")] VEC[("ChromaDB · cosine")] end subgraph EXT["Outside the host"] NET["LAN
(scan target)"] LLM["Ollama :11434
qwen3:30b-a3b"] NVD["NVD API
(enrichment)"] end UI -->|"fetch"| REST WSH -->|"events"| WS REST --> SCAN & THREAT & AI & COMP & RPT BG --> SCAN SCAN --> NET SCAN --> THREAT THREAT -.->|"optional"| NVD AI --> VEC AI --> LLM COMP --> AI REST --> SQL SCAN --> SQL SCAN -->|"auto-ingest"| VEC WS -.->|"broadcast"| WSH

Fig. 1 · Component architecture. One async process fronts six subsystems.

The core loop: scan → score → store → ingest → broadcast

A scan is the spine of the system. Every other feature reads what a scan produces. The sequence below is the live path; mock mode swaps the first step for a fixture load and skips the network entirely.

%%{init: {'theme':'base','themeVariables':{'background':'#0c0c0e','primaryColor':'#151517','primaryTextColor':'#e6e6e6','primaryBorderColor':'#00ff41','lineColor':'#555','actorBkg':'#151517','actorBorder':'#00ff41','actorTextColor':'#e6e6e6','signalColor':'#666','signalTextColor':'#c0c0c0','noteBkgColor':'#111','noteTextColor':'#c0c0c0','noteBorderColor':'#333','fontFamily':'JetBrains Mono, monospace','fontSize':'12px'}}}%%
sequenceDiagram
  participant U as Browser
  participant A as FastAPI
  participant S as Scanner
  participant R as Risk scorer
  participant DB as SQLite
  participant C as ChromaDB
  participant O as Ollama

  U->>A: POST /api/scan
  A->>S: run_scan()
  S->>S: ARP sweep + ICMP fallback + nmap -sV
  S->>R: score_device() per host
  R-->>S: 0–100 risk
  A->>DB: upsert devices + scan record
  A->>A: rogue check → insert alerts
  A->>C: ingest_scan_data() (chunk + embed)
  A-->>U: WS "scan_complete" / "alert"
  Note over U,A: later, the analyst asks a question
  U->>A: POST /api/rag/query
  A->>C: retrieve(top_k=10, cosine)
  C-->>A: ranked chunks
  A->>O: chat(system + context + question)
  O-->>A: grounded answer
  A-->>U: response + sources

Fig. 2 · Scan and RAG data flow. Answers are grounded only in retrieved scan chunks.

03 Technical Design

The engineering behind it

Discovery: ARP first, then ICMP

Live discovery leads with a scapy ARP broadcast because ARP operates at layer 2 and returns real MAC addresses, the stable identity the whole system keys on. Two details make the discovery engine solid:

  • Self-inclusion. ARP never returns the scanning host's own interface, so the scanner adds itself explicitly from conf.iface. Without this, the scanner is invisible to itself.
  • ICMP sweep fallback. On NAT-isolated networks like phone hotspots, ARP broadcasts don't reach peers. An icmplib ping sweep catches them, bounded to 1024 addresses so a large subnet can't blow up scan time. Hosts found this way get their MAC from the kernel ARP cache.

Port and service detection is nmap (-sV -T4 --top-ports 100 --host-timeout 30s), run inside asyncio.to_thread because python-nmap is blocking. The event loop stays responsive while a scan runs.

Risk scoring: a transparent weighted model

The 0 to 100 score is a deterministic additive model across five capped bands. It is intentionally simple and explainable: you can point at any device and reproduce its score by hand, which is what makes people trust the number.

BandMaxBasis
Open ports30Per-port danger weights (Telnet 8, SMB 6, RDP 5…), summed then capped.
Identity gaps15+5 each for missing hostname, missing vendor, unknown type.
OS currency20EOL keyword match → 20; unknown → 10; current → 0.
CVEs258 points per CVE, capped.
Insecure protocols10Telnet/FTP/SNMP and friends, by service name and port.

RAG: retrieval that can't hallucinate the inventory

Each device becomes a summary chunk plus one chunk per open port; alerts become their own chunks. These are upserted into ChromaDB using its default embedding model, all-MiniLM-L6-v2, over cosine space. At query time the analyzer retrieves the top matches, builds a character-budgeted context, and instructs the local LLM to answer only from that context and cite devices by IP and MAC. If ChromaDB or the LLM is unreachable, it degrades to a deterministic rule-based summary rather than failing.

Attack simulation: deterministic by design

The attack simulator makes no LLM call, on purpose. It is a greedy graph traversal: from a chosen origin it walks up to five hops, at each step picking the highest-value reachable target (servers and databases weighted up) where a lateral method exists, such as an open SSH/SMB/RDP/DB port, a shared CVE, or an untrusted host. The result is deterministic, reproducible, and incapable of inventing an attack path that isn't there.

Data model

Seven SQLite tables, all accessed through parameterized queries with a row-factory helper; WAL mode for concurrent reads during a scan; device writes are idempotent upserts keyed on MAC that deliberately preserve the manually-set is_trusted flag across rescans.

devices

MAC-keyed inventory; ports/services/CVEs as JSON.

alerts

Typed, severity-tagged, ack-able.

scans

Run records with full JSON device snapshot.

compliance_frameworks

Parsed controls per uploaded framework.

compliance_assessments

Verdicts + report path per run.

cve_cache

24-hour NVD result cache for enrichment.

04 Security Design

A security tool built like one

A scanner that holds a complete map of a network's weaknesses is itself a high-value target, so the security decisions are baked into the design rather than bolted on.

Local inference only

The chat runs on a local Qwen 3 model through Ollama. The scan data, the crown jewels, never leaves the host for a third-party API.

No injection surface in the query layer

Every SQLite access goes through parameterized queries with a shared row-factory helper. There is no string-built SQL anywhere in the codebase.

Bounded, polite scanning

The ICMP sweep is capped at 1024 addresses and nmap runs with host timeouts, so a scan can't hammer a network or hang the tool.

Offline demo mode

Mock mode runs the full product with no root, no network access, and no external services. Nothing sensitive is touched to show the tool working.

Grounded AI answers

The chat can only answer from retrieved scan chunks and cites devices by IP and MAC. It cannot invent hosts that aren't in the inventory.

Deterministic attack paths

Attack simulation is a reproducible graph walk over real scan data, so it never fabricates a plausible-but-fake intrusion path.

05 Running It

Two modes: offline demo and live scan

Mock mode: the demo path

# Backend: offline, deterministic 15-device fixture
cd backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
FRAGMENTS_MOCK=1 uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload

# Frontend
cd frontend && npm install && npm run dev   # http://localhost:3000

Mock mode exercises every feature (scoring, topology, attack sim, RAG chat, compliance, PDF) with zero external dependencies. If Ollama isn't running, the AI endpoints fall back to deterministic summaries, so a demo never dead-ends.

Live mode: real scanning

# Requires root for scapy/nmap raw sockets; Ollama for AI
export SCAN_SUBNET=192.168.1.0/24
sudo -E .venv/bin/uvicorn backend.main:app --host 127.0.0.1 --port 8000

Environment variables that matter

VARDefaultEffect
FRAGMENTS_MOCK01 = offline fixture mode.
SCAN_SUBNET192.168.1.0/24CIDR scanned in live mode.
SCAN_INTERVAL60Seconds between background scans.
OLLAMA_BASE_URLlocalhost:11434LLM endpoint, kept local.
LLM_MODELqwen3:30b-a3bOllama model tag.
06 Testing

Deterministic tests, no network required

The backend has 23 pytest tests across five files, all forced into mock mode, each with an isolated temp database via an autouse fixture. No test touches the network and no test pollutes another's state.

SuiteTestsCovers
test_risk_scorer5Band math, clamping, EOL detection.
test_rag_pipeline6Chunking, ingestion, retrieval shape.
test_compliance5Parser normalization, verdict heuristics.
test_database4Upsert, trust preservation, queries.
test_arp_scanner3Parsing and self-inclusion logic.
07 Demo

Six minutes, fully offline

The demo runs in mock mode, so nothing depends on the network or a model server. The fixture includes two deliberately risky hosts: an unknown device with Telnet and FTP open (risk 88) and an IoT camera exposing RTSP and Telnet (risk 78).

  • 0:00The dashboard opens on 15 devices in a star topology: node color is risk, node size is open-port count, with live stat tiles for average risk and open alerts.
  • 0:30A scan kicks off. Nodes pulse as WebSocket events land, and rogue device alerts fire for the untrusted hosts.
  • 1:15Clicking the risky host shows the risk breakdown: dangerous ports, identity gaps, unknown OS, a CVE, and insecure protocols adding up to 88. Every point is traceable.
  • 2:15Attack simulation walks a path from that host toward the database server on 3306.
  • 3:15Chat: "Which devices are riskiest and why?" gets a grounded answer with device citations from the local model.
  • 4:15Compliance: an uploaded framework is assessed into a Compliant / Partial / Non-Compliant split tied to real findings, like Telnet failing an encryption control.
  • 5:15The security report PDF generates: executive summary, inventory, vulnerability findings, and a remediation checklist.