CyberGuard AI

An agentic RAG platform for security advisory intelligence: natural-language answers over GitHub Security Advisories, grounded in sources and running fully local.

Visit cyberguard.lakshaycodes.dev← Back to all projects

What I built

CyberGuard AI is a question-answering platform for security advisories. It ingests GitHub Security Advisories (GHSA records with CVE IDs, CVSS scores, affected packages and ecosystems), indexes them, and lets you ask questions in plain English (“what are the most critical vulnerabilities this week?”), getting a sourced answer with citations you can click through.

It goes beyond the usual RAG demo: there’s an agentic mode where a LangGraph agent decides how to answer, advisory-scoped chat (click any advisory and the conversation is pinned to its chunks), PDF analysis over your own documents parsed into the same index, user accounts with OAuth and JWT, conversations, analytics, and an admin surface. The UI offers standard vs agentic answering and a Hybrid / BM25 / Vector search-mode selector, so you can feel the difference between retrieval strategies yourself.

Why I built it

Security advisories are dense, scattered and hard to search. The information you need usually exists (spread across vendor bulletins, CVE records and patches), but getting an answer means reading dozens of documents and stitching facts together yourself.

A general-purpose LLM is of limited help here: it will happily answer from stale training data, which is exactly what you can’t accept when the answer must reflect the current advisory corpus. That failure mode is why retrieval, grading and citations are the core of this system, not an afterthought. And because security data is sensitive, I wanted inference to run locally end to end: the default model is a 1B-parameter Llama served by Ollama, so nothing leaves the machine.

It started as an educational RAG codebase, then grew into a security-focused, multi-service platform: the agent graph, ingestion pipeline, gateway and UI all got rebuilt around real advisory data.

How the corpus gets in

How a question becomes an answer

How it’s bundled and hosted

The whole system ships as a Docker Compose stack: a .NET 8 API gateway, five FastAPI services sharing one Python core (advisory ingestion, embeddings, search, agentic RAG, PDF parsing), PostgreSQL, Redis, OpenSearch, Ollama, and a self-hosted Langfuse stack for tracing every agent step.

In production the frontend deploys to Cloudflare Pages, and the API sits behind Caddy on my server. Deploys are a zero-downtime rolling script that builds all images in parallel, recreates one service at a time against health checks, and if anything fails it re-tags the previous images and rolls back automatically, then posts the outcome to Slack. CI connects over Tailscale to run that same script on push to main.

The stack: who does what

Next.js 14
The dashboard: chat with streaming answers, a collapsible sources panel, advisory-scoped mode, analytics and admin pages.
.NET 8
The API gateway: JWT + OAuth auth, Hangfire job scheduling for daily ingestion, conversations and analytics, and the SSE bridge that streams answers to the UI.
LangGraph
The agent: a state graph of guardrail, retrieve, grade, rewrite and generate nodes with a per-thread memory checkpointer.
FastAPI
The Python core behind five services: advisory fetching, chunking/indexing, unified search, the agent itself and PDF parsing.
OpenSearch
Retrieval: one hybrid index (BM25 + HNSW kNN) fused with a native RRF search pipeline.
Jina embeddings v3
1024-dimension embeddings with task-specific passage and query modes, batched and retried with backoff.
Ollama
Local inference: a 1B Llama model for grading, guardrail and generation, so no data leaves the server.
PostgreSQL + Redis
Advisory storage, identity, Hangfire jobs, and a shared 6-hour response cache.
Docker
Packaging: a multi-service Compose stack deployed by a rolling script with automatic rollback and Slack notifications.