## https://sploitus.com/exploit?id=C4C43757-15B5-5D3E-B518-F825D7611271
# VulnForge
Local-only, single-user CVE alert & patch-priority dashboard. Paste a CVE ID, get NVD/EPSS/KEV enrichment, an Ease-of-Exploitation score, an LLM-generated diff-to-exploit assessment, Akamai WAF rule suggestions, and a chat assistant scoped to that CVE.
See [`CVE-Dashboard-Product-Plan.md`](./CVE-Dashboard-Product-Plan.md) for the full design.
## Quick start
Prereqs: Python 3.11+, Node 20+, [`uv`](https://docs.astral.sh/uv/) (`brew install uv`), `pnpm` (`brew install pnpm`).
```sh
./dev.sh
```
This boots:
- Backend on http://localhost:8000 (FastAPI + SQLite)
- Frontend on http://localhost:5173 (Vite + React)
Open the frontend, go to **Settings**, and paste your API keys (Anthropic at minimum โ everything else is optional). Then paste a CVE ID into the search bar.
## Architecture
- **Backend:** FastAPI, SQLite + FTS5, async via `httpx`. No Docker, no Celery, no Redis.
- **Frontend:** Vite + React 19 + TypeScript + Tailwind v4 + shadcn/ui.
- **LLM:** Claude API (Sonnet 4.6 default, Opus 4.7 for deep analysis). Prompt caching enabled.
- **Plugins:** Drop a `.py` file in `backend/app/plugins/sources/` to add a new enrichment source. The Settings UI auto-renders required-key inputs.
- **Secrets:** Stored encrypted (AES-GCM) in SQLite; master key at `~/.vulnforge/master.key`. No keys in `.env`.
## Project layout
```
backend/
app/
api/routes/ FastAPI route modules
models/ SQLAlchemy ORM models
plugins/
sources/ Enrichment source plugins (auto-discovered)
llm/ LLM provider plugins
services/ Domain services (enrichment, scoring, briefing, chat)
alembic/ DB migrations
tests/
frontend/
src/
api/ Backend client
components/ Reusable UI
pages/ Route components
hooks/
lib/
types/
```
## Adding a new enrichment source
Create `backend/app/plugins/sources/yoursource.py`:
```python
from app.plugins.base import EnrichmentSource, SourceContext
class YourSource(EnrichmentSource):
name = "yoursource"
display_name = "Your Source"
required_secrets = ["yoursource_api_key"]
produces = ["yoursource_field"]
async def enrich(self, cve, ctx: SourceContext) -> dict:
key = ctx.secrets.get("yoursource_api_key")
# ... call API, return enriched fields
return {"yoursource_field": "..."}
```
Restart the backend. The Settings UI will show your plugin with an input field for `yoursource_api_key`. Paste your key, hit Save, and the next CVE lookup will include your data.