VulnForge
Container security insights for your homelab
What is VulnForge?
VulnForge is a self-hosted dashboard that keeps homelab operators on top of container security. It combines Trivy scanning, a native compliance checker, Dockle linting, and Dive layer analysis to surface vulnerabilities, configuration drift, and image hygiene issues in one place -- all without relying on external SaaS services.
The project focuses on reliability and clarity for home environments: simple deployment, a lightweight SQLite datastore, multi-service notifications (ntfy, Gotify, Pushover, Slack, Discord, Telegram, Email), offline-friendly scanners, and tooling that explains what to fix next. Whether you are running a single-node lab or a rack of services, VulnForge turns nightly scans into actionable chores instead of noisy reports.
Technology Stack
Backend
- → Python 3.14 + FastAPI + Granian ASGI server
- → SQLAlchemy 2.x + aiosqlite with WAL mode
- → Docker SDK, APScheduler, and Pydantic 2.x
- → Trivy, Docker Bench, Dockle, Dive integrations
- → Multi-service notifications and CISA KEV enrichment
Frontend
- → React 19 + TypeScript 5.9 with Vite 7
- → TanStack Query for server state and caching
- → React Router v7 single-page navigation
- → Tailwind CSS 4 + Zod schema validation
- → Recharts, Lucide icons, and Sonner toasts
Project Statistics
Version History
Track the evolution of VulnForge through its version releases. Each release includes new features, improvements, and bug fixes.
v4.3.0 2026-02-26
📝 Dev Dependencies
- • **@tailwindcss/vite**: 4.1.18 → 4.2.1
- • **@typescript-eslint/eslint-plugin**: 8.55.0 → 8.56.1
- • **@typescript-eslint/parser**: 8.55.0 → 8.56.1
- • **autoprefixer**: 10.4.24 → 10.4.27
- • **eslint**: 10.0.0 → 10.0.2
- • **eslint-plugin-react-refresh**: 0.5.0 → 0.5.2
- • **jsdom**: 28.0.0 → 28.1.0
- • **ruff**: 0.15.1 → 0.15.4
- • **tailwindcss**: 4.1.18 → 4.2.1
- • **typescript-eslint**: 8.55.0 → 8.56.1
📝 App Dependencies
- • **fastapi**: 0.129.0 → 0.133.1
- • **lucide-react**: 0.564.0 → 0.575.0
- • **pydantic-settings**: 2.12.0 → 2.13.1
- • **react-router-dom**: 7.13.0 → 7.13.1
- • **sqlalchemy**: 2.0.46 → 2.0.47
- • **tailwind-merge**: 3.4.0 → 3.5.0
📝 Dockerfile Dependencies
- • **oven/bun**: 1.3.9-alpine → 1.3.10-alpine
📝 HTTP Servers
- • **granian**: 2.7.1 → 2.7.2
🔒 Security
- • Redact raw Trivy output in error logs (Match/Content JSON keys, 7 logging sites)
- • Defensive redaction at API/export boundaries for secret match values
- • Redact sensitive ENV/ARG assignments in misconfig code snippets
🔄 Changed
- • Redesigned About page: hero, Why VulnForge section, Learn More links, refreshed Built with AI attribution
🐛 Fixed
- • Notification event toggles were non-interactive (clicks on the visible track had no effect due to missing input overlay)
- • Advanced retry settings (attempts, delay) were never saved — missing state and auto-save payload entries
- • False positive key too broad — added `start_line` for precise matching (NULL = wildcard for legacy)
- • Secret status accepted arbitrary strings — now validated against enum
- • Audit log hardcoded `old_status="active"` — now captures actual prior status
- • Severity sort was lexicographic — now uses CRITICAL > HIGH > MEDIUM > LOW ordering
- • Bulk status update did N queries — replaced with single `WHERE id IN (...)` query
✨ Added
- • FP pattern deletion unsuppresses affected secrets (with overlap guard)
- • Audit logging for FP pattern deletion with unsuppress count
- • Migration 009: FP table rebuild for `start_line` column + invalid status cleanup
v4.2.1 2026-02-14
📝 Dev Dependencies
- • **@eslint/js**: 9.39.2 → 10.0.1
- • **@types/react**: 19.2.10 → 19.2.14
- • **@typescript-eslint/eslint-plugin**: 8.54.0 → 8.55.0
- • **@typescript-eslint/parser**: 8.54.0 → 8.55.0
- • **@vitejs/plugin-react-swc**: 4.2.2 → 4.2.3
- • **eslint**: 9.39.2 → 10.0.0
- • **jsdom**: 27.4.0 → 28.0.0
- • **ruff**: 0.15.0 → 0.15.1
- • **typescript-eslint**: 8.54.0 → 8.55.0
📝 App Dependencies
- • **@tanstack/react-query**: 5.90.20 → 5.90.21
- • **authlib**: 1.6.6 → 1.6.8
- • **fastapi**: 0.128.2 → 0.129.0
- • **lucide-react**: 0.563.0 → 0.564.0
📝 Dockerfile Dependencies
- • **oven/bun**: 1.3.8-alpine → 1.3.9-alpine
📝 HTTP Servers
- • **granian**: 2.7.0 → 2.7.1
✨ Added
- • **ScanOrchestrator Service** — Extracts the two-phase commit pattern (create ScanJob → commit → enqueue) into a reusable service used by both the API and scheduler
- • **GET /api/v1/containers/by-image** — Image-based container lookup with registry-agnostic matching for TideWatch integration
- • **GET /api/v1/containers/by-name/{name}** — O(1) container lookup by name
- • **GET /api/v1/scans/jobs/{job_id}** — Poll scan job status and retrieve linked scan_id on completion
- • **Scan Correlation Tracking** — New `scan_jobs` table links API-triggered scan requests to completed scans via job IDs
- • **`scan_id` filter on GET /api/v1/scans/cve-delta** — Deterministic CVE delta retrieval instead of relying on time windows
- • **ScanJob Retention Cleanup** — Automatically deletes completed/failed jobs older than 30 days and marks orphaned queued jobs as failed
- • **37 new tests** covering scan orchestrator, container by-image endpoints, and regression scenarios
🔄 Changed
- • **Scheduler uses ScanOrchestrator** — All scheduled scans now go through the priority queue with ScanJob tracking, CVE delta, and batch notifications
- • **Additive batch registration** — Overlapping scheduler + API batches no longer destroy each other's notification counters
- • **POST /api/v1/scans/scan** — Now returns `job_ids` array; refactored to use ScanOrchestrator
- • **Queue worker links ScanJob to Scan** — Includes retry with backoff for WAL checkpoint delay edge cases
🐛 Fixed
- • **`scan_id` + `since_hours` filter collision** — Time window is now skipped when `scan_id` is provided
- • **Orphan ScanJob rows** — Failed enqueue operations now immediately mark the job as failed
📝 Deprecated
- • **`perform_scan()`** — Legacy scan function; no callers remain after scheduler refactor
🗑️ Removed
- • **`run_scans_sequentially()` dead code** from scans.py
v4.2.0 2026-02-08
✨ Added
- • **System Info Endpoint** — `/api/v1/system/info` returns app name and version dynamically
- • **Frontend Unit Tests** — 110 new tests covering API client, utilities, error handling, and shared components
- • **Backend Tests** — 122 new tests covering API keys, scan queue, OIDC, dispatcher, scanner health, and Docker Bench
- • **Playwright E2E Tests** — 17 end-to-end tests covering auth, dashboard, navigation, settings, containers, and compliance
- • **CI Quality Gates** — Comprehensive pipeline with ruff lint/format, pyright type checking, pytest + Codecov, frontend coverage, and E2E with Playwright artifacts
- • **Shared Components** — Toggle switch, TestConnectionButton, and ContainerCard extracted as reusable components
- • **Typed Notification Settings** — Replaced `Record<string, unknown>` with proper `NotificationSettings` interface across all notification components
- • **API Client Namespaces** — Consolidated all `fetch()` calls into typed `api.ts` with compliance, image compliance, maintenance, and secrets namespaces
- • **Auto-Save Hook** — Debounced auto-save with initialization guard and payload diffing
🔄 Changed
- • **Settings Page Decomposed** — Extracted into 5 tab components (System, Scanning, Notifications, Security, Data), each with scoped state and auto-save
- • **Compliance Page Decomposed** — Extracted into 7 sub-components (ScanProgress, ScoreCard, CategoryBreakdown, TrendChart, FindingsFilters, FindingsTable, IgnoreModal)
- • **Containers Page** — Extracted ContainerCard component for cleaner rendering
- • **scan_queue._process_scan() Decomposed** — Extracted vulnerability storage, secret detection, Dive analysis, and logging into focused helper methods
- • **Version Sourcing** — Switched from `tomllib` to `importlib.metadata.version()` to fix crash in Docker/installed environments
- • **Migration 006 Fixed** — Replaced synchronous `create_engine` with async `upgrade(connection)` pattern
- • **Pyright Clean** — Resolved all 193 errors at `standard` mode (0 remaining)
- • **Image Compliance Summary API** — Fixed field names to match frontend interface expectations
- • **Dependency floors bumped** — Updated fastapi, granian, sqlalchemy, httpx, apscheduler, and other backend dependencies to latest stable versions
- • **Bun** — Updated to 1.3.8-alpine in both Dockerfile and CI
🐛 Fixed
- • **Image Security Dashboard** — Critical and Failures tiles were showing empty due to mismatched field names between backend and frontend
- • **VulnerabilityCharts** — Wrong field names for compliance data (pre-existing bug)
- • **Duplicate formatRelativeTime** — Consolidated to shared utility
- • **Dead computation in scan_queue** — Removed unused fixable_count aggregation
- • **ESLint/Vite conflicts** — Fixed coverage directory and cache permission issues
🗑️ Removed
- • Dead legacy migration code from database.py (~150 lines)
- • Duplicate vulnerability building logic in containers.py (extracted to shared helpers)
- • Inline toggle CSS replaced by Toggle component
- • Redundant Loader2 imports replaced by TestConnectionButton
🔒 Security
- • **CodeQL Remediation** — Resolved 48 CodeQL security alerts (16 false positives dismissed with justification) → Log injection prevention across backend logging calls → Path injection hardening for directory-listing lookup → Stack trace exposure fixes (generic messages to users, details in logs only) → SSRF validation strengthening → Clear-text logging remediation
v4.1.0 2025-01-27
✨ Added
- • **Native Compliance Checker** — Replaced Docker Bench with a Python-based compliance checker that runs directly via Docker API → 20 homelab-relevant checks across 4 categories: Daemon Configuration, Container Runtime, Image Security, Host Configuration → Built-in remediation guidance with copy-paste snippets → Per-container findings with actual/expected values → ~0.4 second scan time (vs Docker Bench container overhead)
- • **Grouped Compliance Findings View** — Aggregates findings by check ID with expandable rows showing per-container results, reducing 400+ rows to ~20 grouped checks
🔄 Changed
- • **Compliance Page** — Updated to use native checker with grouped view; tab renamed from "Docker Bench" to "VulnForge Checker"
- • **Dependencies** — Bumped oven/bun, react, react-dom, typescript-eslint, and globals to latest versions
🗑️ Removed
- • **Docker Bench dependency** — No longer requires `docker-bench-security` container; native checker provides equivalent functionality with better performance
v4.0.1 2025-12-25
🔄 Changed
- • **Single-User Model Clarification** — Removed vestigial multi-user RBAC references (unused `groups` field, related settings, and documentation). No functional changes.
v4.0.0 2025-12-22
✨ Added
- • **User Authentication System** — Single-user model with admin account → Local authentication (username/password with Argon2id hashing) → OIDC/SSO authentication (Authentik integration via OAuth2 authorization code flow) → JWT session management (httpOnly cookies, 24-hour expiry) → Auto-migration system, protected routes, setup page, login page, profile management → Security features: CSRF protection, SSRF prevention, nonce validation
- • **Backend Test Coverage** — 116 new tests across image compliance, notifications, Trivy misconfiguration, Docker client, KEV service, and notifier modules (489 → 605 total)
🔄 Changed
- • **API Authentication Simplified** — Replaced complex multi-provider system (Authentik ForwardAuth, Custom Headers, Basic Auth) with database-backed API keys using `vf_` prefix and SHA256 hashing
- • **Authentication Architecture** — Separated user auth (JWT cookies for browsers) from API auth (ForwardAuth + API keys for integrations)
- • **Settings UI** — Refactored to TideWatch-style user profile with action button grid and self-contained modals
- • **Settings Security Tab** — Replaced 4-provider auth card with clean API Keys manager (generate/list/revoke)
- • **Test Infrastructure** — Fixed fixtures, migrated to Pydantic V2 ConfigDict, updated datetime calls for Python 3.13+
🐛 Fixed
- • **Critical SQL Query Bug** — Fixed ignored findings filter in Image Compliance API that was filtering out all non-ignored findings
- • **Settings Auto-Save Race Condition** — Fixed spurious save on initial page load due to initialization timing
- • **SPA Routing** — Fixed catch-all route intercepting API endpoints
- • **Test Warnings** — Eliminated all 56 test suite warnings (Pydantic V2, datetime deprecation, unawaited coroutines)
🔒 Security
- • **Password Security** — Argon2id hashing (time_cost=2, memory_cost=102400, parallelism=8)
- • **JWT Security** — HS256 with 256-bit secret, httpOnly + SameSite=Lax cookies
- • **CSRF/SSRF/Nonce Protection** — State tokens with 10-minute TTL, private IP blocking, ID token replay prevention
- • **CodeQL Improvements** — 53% reduction in security warnings (119 → 56) with log injection prevention, path traversal protection, and stack trace exposure fixes
v3.3.0 2025-11-28
✨ Added
- • **Multi-Service Notification System** — Expanded from ntfy-only to 7 services: ntfy, Gotify, Pushover, Slack, Discord, Telegram, and Email (SMTP)
- • **Notification Dispatcher** — Centralized event routing with priority-based retry logic and service-specific delay multipliers
- • **Frontend Notification UI** — Per-service configuration forms with test buttons and event notification toggles organized by category
🔄 Changed
- • **Notification Architecture** — Migrated from single NtfyService to NotificationDispatcher with backward-compatible settings migration
v3.2.0 2025-11-26
✨ Added
- • **Frontend Error Handling** — New `errorHandler.ts` utilities, typed `ApiError` class, and enhanced ErrorBoundary with dev/prod mode, copy-to-clipboard error reports, and retryable indicators
- • **Zod Validation Schemas** — Reusable validators for settings with safe integer parsing
🔄 Changed
- • **Error Handling Standardization** — Replaced generic `except Exception` handlers with specific exception types across all API endpoints; structured error responses with `detail`, `suggestions`, and `is_retryable` fields
🐛 Fixed
- • **Safe Integer Parsing in Settings** — Replaced 12 unsafe `parseInt()` calls with `parseSettingInt()` to prevent NaN values in numeric settings fields
v3.1.0 2025-11-26
✨ Added
- • **Light/Dark Theme Support** — Theme context with dual persistence (localStorage + backend API), FOUC prevention, and Tailwind v4 CSS custom properties
- • **CVE Delta Tracking** — New `cves_fixed` and `cves_introduced` columns with automatic delta calculation and `GET /api/v1/scans/cve-delta` endpoint for TideWatch integration
🔄 Changed
- • **Larger Header & Navigation** — Improved visual hierarchy with larger title, nav tabs, and shield icon
- • **Standardized Button Colors** — All primary buttons now use consistent blue theme
- • **Docker Connection** — Simplified to use `DOCKER_HOST` environment variable; removed Docker Connection card from Settings
🐛 Fixed
- • **Light Mode Visibility** — Fixed hardcoded `text-white` throughout UI with proper theme-aware colors
🗑️ Removed
- • Docker Socket Proxy setting from Settings Manager defaults
v3.0.0 2025-11-15
🔄 Changed
- • **Granian ASGI Server** — Migrated from uvicorn to Granian for ~15-20% memory reduction and better async handling
- • **Tailwind CSS v4** — Migrated from v3 with CSS-based `@theme` directive replacing JavaScript config
- • **Python 3.14** — Updated to latest Python release
- • **React 19.2** — Updated to latest React with concurrent features
- • **Backend/Frontend Dependencies** — Bumped all dependencies to latest stable versions
⚡ Performance
- • **79% reduction in initial bundle size** (885 KB → 187 KB) through route-based code splitting, vendor chunking, and memoization
- • **70% reduction in network requests** via React Query staleTime configuration
- • **60% faster Time to Interactive** (2.5s → <1s)
- • Sub-5ms health check response times with 159 MiB average memory footprint
v2.7.0 2025-11-12
✨ Added
- • **CHANGELOG.md** — Version history tracking in Keep a Changelog format
- • **README.md** — Project documentation with quick start guide
🔄 Changed
- • **Trivy-Only Scanning** — Simplified vulnerability scanning by removing redundant Grype scanner; faster scan times and cleaner codebase
🗑️ Removed
- • **Grype vulnerability scanner** — Provided 100% overlapping functionality with Trivy; all related services, endpoints, UI components, and consensus logic removed
🐛 Fixed
- • **Frontend build script** — Removed `tsc &&` prefix that was blocking CI/CD builds
v2.6.0 2025-11-XX
Key Features
● Scanning & Detection
- → Trivy vulnerability scanning with CISA KEV tagging, CVSS scoring, and per-container history
- → Secret detection workflow with false-positive pattern management, automatic unsuppression, and accepted-risk tracking
- → Security-hardened output with Trivy match redaction, API boundary sanitization, and ENV/ARG scrubbing
- → Real-time SSE scan progress, retry controls, and classified error guidance for every job
● Compliance & Image Hygiene
- → Docker Bench scheduling with weekly reports, CSV export, and historical trend charts
- → Dockle image compliance dashboard with on-demand scans and remediation tips
- → Dive integration for layer efficiency analysis and wasted-byte insights per image
● Automation for Homelabs
- → Cron-style scheduling, automatic container discovery, and image batch scanning
- → Multi-service notifications (ntfy, Gotify, Pushover, Slack, Discord, Telegram, Email) with priority-based routing
- → Offline resilience with cached scanner databases and intelligent fallbacks
● Data & Workflow
- → SQLite WAL persistence with backup/restore, download, and safety snapshots
- → CSV exports, drill-down findings, and timeline of homelab activity
- → Responsive dashboard widgets tuned for desktop dashboards and tablet control rooms
Dashboard & Insights
Visual Analytics
7 interactive Recharts including severity distribution, fixable vs non-fixable comparison, top vulnerable containers, and scan & remediation trends
Remediation Groups
Package-based grouping showing which updates fix multiple CVEs with impact visualization and severity breakdowns
Real-time Progress
Live streaming scan updates over Server-Sent Events with container-level feedback and auto-refresh when scans complete
Homepage Widgets
Four API endpoints for Homepage dashboard integration: summary, critical focus, top containers, and remediation actions
Use Cases
Vulnerability Management
Scan 50-60+ Docker containers, prioritize fixable vulnerabilities, and track remediation progress with historical trends
Compliance Monitoring
Weekly Docker Bench reports for CIS benchmark compliance with pass/fail breakdowns and Dockle image hygiene checks
Automated Scanning
Cron-based scheduled scans with multi-service notifications, container discovery, and intelligent retry controls for failed jobs
Secret Detection
Identify exposed secrets in containers with triage workflow for false positives and accepted-risk tracking
Screenshots
Dashboard
At-a-glance security posture with severity breakdown, scan trends, KEV alerts, and remediation priorities.
Containers
All running containers with vulnerability counts, last scan time, and quick-scan controls.
Container Overview
Individual container detail with image info, vulnerability summary, and navigation to detailed findings.
Container Vulnerabilities
Detailed CVE listing with severity, CVSS scores, fix versions, and KEV tagging for exploited vulnerabilities.
Scan History
Historical scan results with trend visualization showing vulnerability counts over time.
Secret Detection
Exposed secrets found in container images with triage workflow for false positives and accepted risks.
Docker Bench Compliance
CIS Docker Benchmark compliance checks with pass/fail breakdown and historical trends.