Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sentinel banner

Typing SVG


C++ CMake WebGPU GLFW SQLite Ollama

Platform Status Stage License PRs


tech icons

Important

This is a personal-hardware security console, not a hardened EDR product. Sentinel was built to explore how much real endpoint visibility, detection, and response tooling can live in a small native GPU-rendered app instead of an Electron shell plus a heavyweight agent. It has not been audited, is Windows-only for every sensing/response feature, and its response actions (kill / block / quarantine) touch the live system. Read Security Model & Limitations before pointing it at anything you'd be upset to lose.


Table of Contents


What is Sentinel?

Sentinel is a small, native, GPU-accelerated security console for Windows (with a cross-platform UI shell that also runs on Linux). It's built on a from-scratch app shell — GLFW for windowing/input, wgpu-native for rendering (WebGPU → D3D12/Vulkan) — with no Electron, no Chromium, no garbage-collected runtime anywhere in the render path.

On top of that shell sits an actual endpoint-security stack:

Process/Network monitors  ─┐
Wi-Fi/Bluetooth/USB polls  ├──▶  EventQueue ──▶ SQLite store ──▶ RuleEngine ──▶ Alerts
Raw-socket packet capture ─┘                          │                          │
                                                        ▼                          ▼
                                              Response Executor          ATT&CK mapping
                                          (kill / block / quarantine)     + local AI analyst

Twelve navigation panels — Dashboard, Processes, Network, Packets, Wi-Fi, Bluetooth, USB, Alerts, Response, ATT&CK, AI Analyst, Settings — are all backed by real data paths, not placeholder screens.


Why This Project Exists

Most consumer-facing security tools either ship as a heavyweight Electron app (a second Chromium process idling in the background) or as a cloud-tethered agent that assumes always-on bandwidth and a SOC on the other end. Neither fits a single laptop with a fixed RAM budget that also wants to run a local LLM on demand.

Sentinel starts from the opposite constraint: what does real telemetry, detection, and response look like when the UI has to cost almost nothing at idle, so that budget can go to a 7B-parameter model instead? That question shapes nearly every decision in this repository — from the immediate-mode UI renderer, to SQLite and GLFW being built from source rather than installed, to raw sockets instead of a Npcap driver, to an AI analyst that's explicitly a button, never a background daemon.


🧩 Feature Matrix

Every row below was confirmed directly against the source in src/ — nothing here is aspirational.

Feature Where Platform
GPU-rendered UI shell (GLFW + wgpu-native, immediate-mode rects/text, no UI toolkit) src/window/, src/gpu/, src/ui/ Windows + Linux
Process telemetry (start/stop diffing, pid-reuse-safe) src/agent/process_monitor_win.h Windows only
Network connection telemetry (TCP/UDP owner-PID tables) src/agent/network_monitor_win.h Windows only
SQLite-backed event store (WAL mode, batched transactions) src/store/event_store.cpp Windows + Linux
Rule-based detection engine, 4 rules, 5-min per-(rule,pid) cooldown src/detection/rule_engine.cpp Windows + Linux (logic), Windows (data source)
MITRE ATT&CK reference panel (~33 curated techniques, per-rule tagging) src/attack/attack_knowledge.h Windows + Linux
On-demand LAN discovery (ICMP sweep → ARP → common-port check, no Nmap) src/network/network_scanner_win.h Windows only
Raw-socket IP packet capture (SOCK_RAW, no Npcap) src/network/packet_capture_win.h Windows only
Process CPU% / RAM / thread-count sampling src/agent/process_monitor_win.h Windows only
Wi-Fi monitoring (current connection + nearby networks, WLAN API) src/peripherals/wifi_monitor_win.h Windows only
Bluetooth monitoring (background poll + on-demand radio inquiry) src/peripherals/bluetooth_monitor_win.h Windows only
USB device-tree monitoring (SetupAPI) src/peripherals/usb_monitor_win.h Windows only
Response actions: kill process / block IP / quarantine file, two-step confirm, full audit log src/response/response_executor_win.h Windows only
On-demand local AI analyst over Ollama (WinHTTP, no libcurl) src/ai/ollama_client_win.h Windows only
Live-adjustable, store-persisted Settings (poll intervals, scan range, AI mode) src/store/event_store.cpp (settings table) Windows + Linux
Process/Alert drill-down detail views src/main.cpp Windows + Linux

Not yet implemented for Linux: src/agent/agent.h compiles to a documented no-op on any non-Windows target — the UI shell, store, and rule engine all run, but there's no telemetry to feed them. The seam for a process_monitor_linux.h/network_monitor_linux.h pair already exists (#elif __linux__), it just isn't filled in yet.


🏗 Architecture

Window (GLFW)  ──creates──▶  GpuContext (wgpu-native / D3D12 or Vulkan)
                                     │
                                     ▼
                              UiRenderer (immediate-mode rects + text)
                                     │
                                     ▼
                              src/main.cpp (12 nav panels, AppState)
                 ┌───────────────────┼────────────────────┐
                 ▼                   ▼                     ▼
          src/agent/           src/network/          src/peripherals/
     (process/network poll)  (scan, packet capture)  (Wi-Fi/BT/USB poll)
                 │                   │                     │
                 └─────────► EventQueue ◄───────────────────┘
                                     │
                                     ▼
                          src/store/event_store.cpp (SQLite)
                                     │
                                     ▼
                       src/detection/rule_engine.cpp
                          │                    │
                          ▼                    ▼
                  src/response/         src/attack/
              (kill/block/quarantine)  (ATT&CK tagging)
                                     │
                                     ▼
                         src/ai/ollama_client_win.h
                        (on-demand, local, no daemon)
  • Window (src/window/) — GLFW window + input callbacks (resize, key, mouse move/button, scroll, close).
  • GpuContext (src/gpu/) — one wgpu-native instance/adapter/device/surface bound to the window; owns the render-pass lifecycle.
  • UiRenderer (src/ui/) — one solid-color-triangle pipeline, a growable vertex buffer, and three primitives (DrawRect, DrawLabel via a compile-time 5×7 bitmap font, Button) — enough to build the full sidebar/titlebar/content/status-bar layout without a UI toolkit dependency.
  • Agent (src/agent/) — process and network monitors, each a background thread doing a poll-and-diff loop into one shared EventQueue. main.cpp drains it once per frame.
  • EventStore (src/store/) — SQLite (vendored amalgamation), WAL mode, synchronous=NORMAL, one transaction per drained batch — not an fsync per event.
  • RuleEngine (src/detection/) — polls whatever's new in the store on a fixed timer and emits Alert rows for matches.
  • Response executor (src/response/) — the only module that mutates the live system; re-validates every target itself rather than trusting the UI (see Response / IPS Actions).
  • AI analyst (src/ai/) — talks to a local Ollama server over WinHTTP; builds a small structured prompt from one alert's fields, not raw logs or the full event database.

🔎 Detection Pipeline

RuleEngine::Tick() runs on a 4-second timer against whatever's new in the event store, with a 5-minute cooldown per (rule, pid) so an ongoing condition doesn't spam the Alerts panel every tick. Four rules, each with a real reason to exist:

Rule Fires on Severity
SUSPICIOUS_PARENT_CHILD A script host (powershell.exe, cmd.exe, mshta.exe, regsvr32.exe, rundll32.exe, wscript.exe/cscript.exe) spawned by Office/a browser/a PDF reader — the classic macro-malware pattern Varies by binary
UNRESOLVED_OWNER_CONNECTION A TCP row GetExtendedTcpTable couldn't attribute to a PID Low
SUSPICIOUS_PORT A connection to a curated list of ports with a known malware/C2 association (common dev ports deliberately excluded) Medium
HIGH_CONNECTION_RATE One process reaching 12+ distinct remote hosts inside a minute High

Verified with a standalone test that inserts a simulated winword.exe → powershell.exe chain, a connection to a known C2 port, and a 12-host burst into a real SQLite database, and confirms all three fire while a benign Chrome connection doesn't, and the cooldown suppresses an immediate repeat.


🗺 MITRE ATT&CK Mapping

Not a synced copy of the ATT&CK framework — a curated ~33-technique reference list (src/attack/attack_knowledge.h) spanning most tactics, with per-rule tagging so an alert's detail view and a dedicated ATT&CK panel show which technique it maps to and how much of the reference list this app can currently detect. The full ATT&CK Enterprise matrix has 600+ techniques distributed as a multi-megabyte STIX corpus — embedding that for four detection rules would be the kind of heavy dependency this project avoids everywhere else.

Mapping is done honestly rather than force-fit:

  • SUSPICIOUS_PARENT_CHILD maps per spawned binary — PowerShell/cmd map to Execution (T1059.001 / T1059.003), while Mshta/Regsvr32/Rundll32 map to Defense Evasion (T1218.005/.010/.011), since ATT&CK itself splits these across tactics.
  • SUSPICIOUS_PORTT1571 (Non-Standard Port) — a direct, confident fit.
  • HIGH_CONNECTION_RATET1071 (Application Layer Protocol) — flagged in code as a heuristic best-fit, not a precise signature match.
  • UNRESOLVED_OWNER_CONNECTION gets no technique at all — it's a visibility gap in the tool itself, not observed adversary behavior, and tagging it just to fill the field would be a false claim of precision.

Verified with an integration test running synthetic attack chains through the real RuleEngine against real SQLite and confirming each alert's attack_technique field lands exactly where the mapping says — including that a Word→Mshta chain lands in a different tactic than an Excel→PowerShell chain, and that the unattributed-connection alert's technique field comes back empty rather than guessed.


🚨 Response / IPS Actions

The one part of this app that acts on the live system, built with that taken seriously:

  • Every action requires a two-step confirm, app-wide, via a ConfirmButton helper — first click arms it (relabels, tints red), second click within 8 seconds executes it. There is no single click anywhere in this codebase that kills a process, blocks an IP, or moves a file.
  • The executor re-validates every target itself (response_executor_win.h) rather than trusting the UI — a process's name is re-resolved from the live process at kill time, checked against a denylist of core OS processes (csrss.exe, lsass.exe, services.exe, svchost.exe, this app's own process) plus pid ≤ 4. Quarantine refuses any path inside System32/SysWOW64/WinSxS.
  • Kill/Block/Quarantine are wired into an alert's detail view, grounded in data the rule engine already populated (target_ip/target_path), not invented UI state.
  • Block IP and Quarantine File are reversible; Kill Process isn't. Blocking uses netsh advfirewall (ships with Windows) rather than the COM-based WFP API. Quarantine moves the file into this app's own local-data folder with a .quarantined suffix.
  • A RESPONSE nav panel is the full audit log — every attempted action is recorded whether it succeeds, fails, or gets refused by a safety check, with reversible entries getting their own Unblock/Restore button.
  • Deliberately no automatic mode. Every action is a human decision made through a confirm button.

Validation logic (IPv4 format checks, including shell/SQL-injection-shaped strings like "1.2.3.4; rm -rf /"; the protected-process-name set; the protected-path-prefix check) is extracted and tested directly, not just eyeballed — along with a schema-migration test confirming EventStore::EnsureColumn correctly backfills target_ip/target_path on a database created before this feature existed.


⚙ Hardware Budget & Design Constraints

Sentinel was built against a specific machine (11th-gen i5-1135G7, 11.7GB RAM, NVMe, no discrete GPU), and that budget shapes the whole roadmap, not just the UI framework choice:

  • The shell itself: a few MB resident, no GC pauses, presentation paced by vsync (WGPUPresentMode_Fifo) — leaves essentially the whole RAM budget free.
  • Local models via Ollama: qwen2.5:7b (~4.7GB at Q4) for real investigations, llama3.2:3b (~2GB at Q4) for cheap triage. Never both loaded at once; never run as a background daemon — loaded on demand from the AI Analyst panel, unloaded by Ollama's own idle timeout.
  • Endpoint agent: polling/eventing, not continuous packet capture — no headroom for Suricata/Zeek-style full inspection running 24/7 alongside an LLM.
  • Network scanning and packet capture: strictly button-triggered, never a background timer, and only intended for networks/devices you own or are authorized to test.

🛠 Tech Stack & Rationale

Layer Choice Why
Windowing/input GLFW 3.4 Fetched and built from source via CMake FetchContent — nothing to preinstall
Rendering wgpu-native (WebGPU → D3D12/Vulkan) One pipeline, direct GPU access, no browser engine in the loop
UI Hand-rolled immediate-mode renderer No per-frame allocations beyond one growable vertex buffer; no text-shaping at runtime
Persistence SQLite (vendored amalgamation) Built from source as its own static lib; WAL mode + batched transactions
Network scanning Raw ICMP/ARP/Winsock calls Avoids a Nmap/Npcap install dependency
Packet capture Windows raw sockets (SOCK_RAW + SIO_RCVALL) Native IP-layer capture, no kernel driver
Local AI Ollama over WinHTTP Built-in Windows HTTP stack, no libcurl to vendor
Peripherals WLAN API / classic Bluetooth API / SetupAPI Native Win32, no WMI/COM round trips

📁 Repository Structure

Sentinel/
├── CMakeLists.txt              # GLFW fetched, SQLite vendored & built, wgpu-native linked
├── README.md
├── src/
│   ├── main.cpp                 # UI shell: nav, all 12 panels, AppState
│   ├── window/                  # GLFW window + input
│   ├── gpu/                     # wgpu-native device/surface/render-pass
│   ├── ui/                      # Immediate-mode renderer + bitmap font
│   ├── agent/                   # Process/network monitors (Windows), EventQueue
│   ├── network/                 # LAN scanner, raw-socket packet capture (Windows)
│   ├── peripherals/             # Wi-Fi / Bluetooth / USB monitors (Windows)
│   ├── detection/                # RuleEngine (4 rules, cooldown logic)
│   ├── attack/                   # Curated MITRE ATT&CK reference + technique struct
│   ├── response/                 # Kill/Block/Quarantine executor + safety checks
│   ├── ai/                       # Ollama client (WinHTTP) + lightweight JSON extractor
│   └── store/                    # SQLite-backed EventStore (events/alerts/settings/responses)
└── third_party/
    ├── sqlite/                   # Vendored SQLite amalgamation
    └── wgpu_native/               # wgpu-native headers (binary downloaded separately)

🚀 Getting Started

One-time setup

  1. Download the wgpu-native binary for your platform and drop it in third_party/wgpu_native/lib/ — see third_party/wgpu_native/README.md for exact filenames and the release link.
  2. GLFW is fetched and built from source automatically — nothing else to install on Windows.
  3. On Linux, install the X11 development headers GLFW's build needs:
sudo apt install libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libgl1-mesa-dev

Warning

CMakeLists.txt currently defaults WGPU_NATIVE_LIB_DIR to a hardcoded personal path (see Verified Findings). Override it explicitly on your own machine — don't rely on the default.

Build

cmake -B build -DCMAKE_BUILD_TYPE=Release -DWGPU_NATIVE_LIB_DIR=/path/to/wgpu-native/lib
cmake --build build --config Release

Run the sentinel (or sentinel.exe) binary produced in build/.

Running the full feature set

The UI shell builds and runs on Linux, but process/network telemetry, the LAN scanner, packet capture, Wi-Fi/Bluetooth/USB monitoring, response actions, and the AI analyst are all Windows-only today (see Feature Matrix). For the AI Analyst panel specifically, you'll also need Ollama running locally with at least one of qwen2.5:7b / llama3.2:3b pulled.


🔒 Security Model & Limitations

What this is not

  • ❌ Not an audited or certified EDR/IPS product
  • ❌ Not resilient against an attacker with SYSTEM/kernel-level access — it's user-mode telemetry, same trust boundary as Task Manager
  • ❌ Not a promiscuous network tap — packet capture sees only this host's own traffic, and requires Administrator
  • ❌ Not a live-synced ATT&CK matrix — the reference list is a checked-but-static snapshot (~33 of 600+ techniques)

Known gaps, stated plainly

  • Linux telemetry doesn't exist yet. Agent::available() returns false on non-Windows builds; the Dashboard is honest about this rather than showing a silently empty view.
  • Packet capture is IP-layer only — no Ethernet/802.11 frames, no ARP, no non-IP protocols, and results are an in-memory 300-packet rolling buffer, never persisted.
  • Bluetooth monitoring is classic Bluetooth only — BLE-only devices need the WinRT Windows.Devices.Bluetooth APIs, a materially bigger integration left as a documented gap.
  • CPU% is unclamped past 100% (matching Task Manager's convention, one core fully busy = 100%) — a 4-core box can show ~400% for one process, by design, not a bug.
  • No automatic response mode. Every kill/block/quarantine requires a human two-step confirm; there is deliberately no unattended mode in this codebase.

🔎 Verified Findings From Code Review

Concrete observations from reading the actual source — not general prototype disclaimers.

  1. CMakeLists.txt hardcodes a personal Windows path as the default for WGPU_NATIVE_LIB_DIR (C:/Users/<username>/Downloads/Project/...). This will silently fail to configure on anyone else's machine unless overridden with -DWGPU_NATIVE_LIB_DIR=..., and it's a minor local-path disclosure worth scrubbing before treating this as a public template.
  2. No .gitignore ships with the project, so a fresh cmake -B build will happily let build artifacts get tracked if committed carelessly.
  3. No CI configuration exists — there's no automated compile/test gate on changes.
  4. third_party/sqlite/ and third_party/wgpu_native/ are vendored (a full SQLite amalgamation and wgpu-native headers) — both are permissively licensed (public domain and MIT/Apache-2.0 respectively), which is compatible with this repo's MIT license, but worth double-checking against the versions actually vendored here if that ever matters for your use case.

🧭 Extending This

  • New screens: replace/extend DrawFrame() in src/main.cppDrawSidebar/DrawTitleBar/DrawContent/DrawStatusBar are just functions calling UiRenderer; copy the pattern.
  • Reskinning: every color lives in the palette namespace at the top of main.cpp.
  • More UI primitives: add methods to UiRenderer alongside DrawRect/DrawLabel/Button — they all push vertices into the same buffer.
  • A real UI toolkit instead: once you outgrow immediate-mode rects (scrolling lists, text input, images), GpuContext already exposes the raw device()/queue()/surface_format() a Dear ImGui WebGPU backend needs.
  • Linux telemetry: implement process_monitor_linux.h/network_monitor_linux.h (e.g. /proc diffing + /proc/net/tcp) with the same Start()/Stop() shape and wire into src/agent/agent.h's #elif __linux__main.cpp doesn't need to change.
  • macOS: GLFW already supports it; add a WGPUSurfaceSourceMetalLayer branch to gpu_context.cpp.

🗺 Roadmap

  • Repository hygiene. Add a .gitignore and remove the hardcoded personal path from CMakeLists.txt's default WGPU_NATIVE_LIB_DIR.
  • Linux telemetry. Implement the Linux process/network monitors behind the existing agent.h seam — the biggest functional gap between platforms.
  • Linux network scanner / AI client. Port network_scanner_win.h and ollama_client_win.h to POSIX equivalents (getifaddrs, libcurl or raw sockets).
  • CI. A basic compile-on-PR workflow for at least the Windows target.
  • BLE support. WinRT Windows.Devices.Bluetooth integration alongside the existing classic-Bluetooth monitor.
  • Larger design directions (explicitly out of scope for the current single-host build): purple-team exercises, RAG over ATT&CK/detection-rule knowledge, cross-host telemetry aggregation.

🤝 Contributing

Issues, pull requests, and design discussions are welcome. If you spot something incorrect in this README or in the security-relevant code (validation logic, the ATT&CK mapping, the response executor), please open an issue — for a security tool, an inaccurate claim in its own documentation is worth treating as a bug.


📜 License

Licensed under the MIT License. Vendored third-party code (third_party/sqlite, third_party/wgpu_native) retains its own upstream license — see Verified Findings.


🙏 Acknowledgements

Built on GLFW, wgpu-native, SQLite, and Ollama. MITRE ATT&CK technique IDs and names are sourced from attack.mitre.org.


footer

Every action confirms twice. Every claim in this README was checked against the source.

About

A native GPU-rendered security console — process/network telemetry, rule-based detection, ATT&CK mapping, two-step-confirm response actions, and an on-demand local LLM analyst. No Electron, no background daemons.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages