Skip to content

Odysafe/ODYSAFE-CVE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

odysafe-cve

Self-hosted vulnerability intelligence dashboard for security teams. A CVE monitoring tool that tracks vendor/product assets, syncs vulnerability data through ProjectDiscovery vulnx, and surfaces CVSS x EPSS analytics, CISA KEV tracking, BOD 26-04 remediation tiers, PoC/Nuclei coverage, and multi-channel alerting, all from a single Go binary with a React UI.

Keywords: vulnerability management, CVE tracker, CVSS, EPSS, CISA KEV, vulnerability intelligence, security dashboard, self-hosted, vulnx, Nuclei, patch prioritization, attack surface, security operations, RBAC, remediation tracking.

Part of the odysafe family (dark glassmorphism design language). All source code, comments, and UI strings are in English.


Screenshots

Dashboard Excel export
Dashboard overview Excel export sample

On GitHub, open the images directly: Dashboard.png · excel.png


Features

Dashboard

  • Scan now button to trigger a vulnx sync from the dashboard header.
  • Views: Assets (risk cards per equipment), Vulnerabilities (triage-first CVE list), Overview (heatmap, KPIs, charts).
  • Vulnerability tabs: Action required (default), Critical, KEV, New, Show all.
  • Fast search (kev, remote, status:, tag:) and multi-asset filter.
  • Bulk triage (ignore, snooze, accept risk) and one-click quick actions in the CVE modal.
  • CVE detail modal (3 levels): summary, scores/exploit signals, technical references; affected_equipment from API.
  • Load more pagination and scroll-to-results on the CVE list.
  • CVSS x EPSS heatmap with severity-aligned colors (#FF453A / #FF9F0A / #FFD60A / #30D158). Click a cell to filter the CVE table.
  • KPI pills: KEV count, new CVEs (24h / 7d / 30d) with trend percentage versus previous period, PoC/Nuclei ratios, EPSS mean, remote/OSS counts, exposed assets, critical CVEs on exposed assets (KEV or CVSS >= 9).
  • Average MTTR panel for CVE x equipment pairs marked remediated.
  • Composite risk score: (CVSS/10) x EPSS x (2 if KEV else 1), capped between 0 and 10.
  • BOD 26-04 remediation tier per CVE x equipment (simplified 2-variable model; see below).
  • Top vendors and products, EPSS 30-day trend, equipment exposure bars with Exposed / Internal and business criticality badges.
  • Global filters: equipment group and business criticality scope KPIs, heatmap, CVE list, and exposure charts.
  • CVE detail modal with live vulnx lookup, PoC links, Nuclei template ID, references, per-asset remediation status, and CVE notes.
  • Sticky data freshness banner on every page (sync status, vulnx health, rate-limit state).

BOD 26-04 remediation (simplified)

This app implements a 2-variable remediation window (is_exposed on equipment + is_kev on CVE), not the full 16-cell CISA SSVC matrix.

Exposed KEV Tier
Yes Yes 14d
Yes No 60d
No Yes 60d
No No Next upgrade
  • Deadline = CVE published_at (fallback: synced_at) + tier days.
  • Overdue filter = past deadline and status is not remediated.
  • Default CVE table sort: tier urgency first, then CVSS.

Search and filters

  • Cache filters: KEV, Exposed + KEV, Overdue, Remote, OSS, CVSS/EPSS/date ranges, has notes, sync run changes.
  • vulnx query syntax in the UI (for example cve_updated_at:>=2024-01-01, is_oss:true).
  • Dynamic filter metadata from GET /api/vulnx/filters.
  • Scoped filters: ?group_id=, ?business_criticality=, ?sync_run_id=, ?has_notes=true.

Executive Summary

  • Dedicated Executive page for leadership: exposed assets, critical overdue SLA, MTTR with trend, accepted risks, open CVEs by remediation tier (bar chart).

Settings

  • Equipment: name, vendor/product (vulnx CPE fields), Internet exposure, exposure justification, business criticality, group assignment, CSV bulk import (preview + confirm).
  • Groups: named equipment groups with color badges (many-to-many).
  • Users (admin): RBAC roles, temporary password on create, forced password change on first login.
  • Audit log (admin): read-only history with filters and CSV export.
  • Sync: cron schedule, per-source toggles (NVD, KEV, EPSS, CPE, Nuclei), manual sync, last sync change summary, rate-limit status.
  • API key: ProjectDiscovery PDCP key, encrypted at rest.
  • Alerts: Discord, Slack, SMTP with thresholds (CVSS, EPSS, KEV, exposed + KEV); digest notifications per sync cycle.
  • Export: formatted Excel workbook (.xlsx) with executive KPI sections, per-equipment metrics, and full CVE rows (see Export formats).
  • Authentication: RBAC (admin / analyst / viewer), password change, optional TOTP (API).

RBAC roles

Role Access
admin Full access: settings, API key, alerts, user management, equipment delete
analyst Remediation status, notes, equipment CRUD, manual sync, CSV import; no API key, alerts, or user management
viewer Read-only dashboard, CVE list, Excel export, Executive Summary

Operations

  • One-command install and update (install.sh).
  • Optional systemd service with paths generated for your user and install directory.
  • Offline and degraded mode: cached SQLite data when sync or vulnx is unavailable.
  • Schema migrations applied automatically on server start (001 through 009).
  • Sync change tracking: last 30 sync runs retained with per-CVE diffs (new_cve, became_kev, score_updated, poc_added).

Architecture

+--------------------------------------------------------------------+
|  Single Go binary (chi HTTP server)                                |
|  +-- /api/*           REST JSON API (session auth + RBAC)          |
|  +-- /*               React SPA (frontend-dist/)                    |
|  +-- SQLite cache     data/cve.db (WAL, modernc, no CGO)           |
|  +-- Encrypted config config/config.enc (AES-256-GCM)              |
|  +-- robfig/cron      scheduled sync per equipment                 |
|  +-- vulnx v2 client  github.com/projectdiscovery/vulnx/v2         |
+--------------------------------------------------------------------+
Layer Technology
Backend Go 1.22+, chi, modernc.org/sqlite
Frontend React 18, Vite, TypeScript, TailwindCSS, recharts (web/ sources, built to frontend-dist/)
Vulnerability data vulnx v2, ProjectDiscovery cloud API
Excel export excelize (in-process .xlsx, no external deps)
Auth bcrypt, HttpOnly cookies, RBAC, optional TOTP
Secrets AES-256-GCM (config.enc), log redaction

Database (key tables)

Table Purpose
users Accounts with role, must_change_password
equipment Monitored assets; is_exposed, business_criticality, justification
equipment_groups / equipment_group_members Named groups (many-to-many)
cves Cached vulnx records per equipment
equipment_cve_status Per CVE x equipment remediation_status, remediated_at (MTTR)
cve_equipment_notes Per CVE x equipment comment history
audit_log Immutable actions with old_value / new_value JSON
sync_runs / sync_run_changes Sync history and per-run diffs
dashboard_kpi_cache KPI snapshot refreshed after sync
alert_sent Alert deduplication per sync cycle

Requirements

Dependency Version Purpose
Go >= 1.22 Backend build
Node.js >= 20 Frontend build
npm >= 9 Frontend dependencies
openssl any Encryption key generation

Excel export requires no browser. On Debian/Ubuntu, Fedora, or Arch, install.sh can install missing packages via apt, dnf, or pacman.


Quick start

git clone <your-repo-url> odysafe-cve
cd odysafe-cve

# Optional: clone vulnx as sibling only when hacking the upstream client locally
# git clone https://github.com/projectdiscovery/vulnx ../vulnx
# echo 'replace github.com/projectdiscovery/vulnx/v2 => ../../vulnx' >> backend/go.mod

chmod +x install.sh start.sh stop.sh uninstall.sh
./install.sh
./start.sh

Default install listens on port 5000 with HTTPS (self-signed certificate) unless you choose HTTP during install.

  1. Open https://localhost:5000 (accept the browser certificate warning if using self-signed TLS).
  2. If authentication is disabled, go to Settings > Authentication and create an admin account, or log in with existing credentials.
  3. Go to Settings > Equipment and add monitored vendor/product pairs (or import via CSV).
  4. Click Scan now on the dashboard or run sync from Settings > Sync (default cron: every 6 hours).
  5. Review the CVE list (Tier, Exposure, Deadline columns); set remediation status in the detail modal.
  6. Optionally add a ProjectDiscovery API key for higher vulnx rate limits.

Scripts

Script Description
install.sh Install dependencies, build backend and web UI, init DB/config
start.sh Start via systemd (if installed) or background process with PID file
stop.sh Stop running instance
uninstall.sh Stop services, remove runtime data (interactive inventory)
scripts/build.sh Rebuild binaries and web UI without changing config/DB
scripts/smoke_test.sh Syntax checks, backend tests, config tool smoke test
scripts/fix-permissions.sh Restore ownership after a root-owned install
scripts/audit-equipment-tokens.sh List/fix invalid vendor/product CPE tokens in presets and DB
scripts/rewrite-git-history.sh Single-commit history rewrite after GitHub secret-scan push rejection
scripts/cleanup-legacy.sh Remove legacy frontend/ and deploy/ folders

Environment overrides: ODYSAFE_ROOT, DATA_DIR, PORT.


Directory layout

odysafe-cve/
+-- install.sh / start.sh / stop.sh / uninstall.sh
+-- scripts/
|   +-- build.sh              rebuild backend + web UI
|   +-- smoke_test.sh         integration smoke tests
|   +-- generate-ssl-cert.sh  TLS certificate helper
|   +-- fix-permissions.sh    ownership repair after root install
|   +-- cleanup-legacy.sh     remove old frontend/ and deploy/
+-- packaging/systemd/
|   +-- odysafe-cve.service   systemd unit template
+-- backend/
|   +-- cmd/server/           main HTTP server
|   +-- cmd/init/             DB bootstrap
|   +-- cmd/config/           encrypted config writer (used by install.sh)
|   +-- internal/api/         REST handlers, middleware, RBAC
|   +-- internal/vulnx/       vulnx client wrapper
|   +-- internal/store/       SQLite layer
|   +-- internal/scheduler/   cron sync, change tracking
|   +-- internal/alerts/      Discord / Slack / SMTP digest
|   +-- internal/export/      Excel export
|   +-- migrations/           versioned schema (001-009)
+-- web/                      React SPA sources, built to frontend-dist/
|   +-- src/                  Dashboard, Settings, Executive, Guide, ...
+-- config/                   .secret_key, config.enc, tls/ (gitignored)
+-- data/                     cve.db (gitignored)
+-- logs/                     server.log (gitignored)
+-- bin/                      odysafe-cve, odysafe-init, odysafe-config (gitignored)
+-- docs/
    +-- README.md             extended technical reference
    +-- Dashboard.png         dashboard screenshot
    +-- excel.png             Excel export screenshot
    +-- config.example.yaml   configuration schema reference

Legacy folders frontend/ and deploy/ from older installs can be removed with sudo ./scripts/cleanup-legacy.sh.


Configuration

Runtime settings live in config/config.enc (encrypted). The schema is documented in docs/config.example.yaml.

Setting Default Description
port 5000 (install) / 8080 (dev) HTTP(S) listen port
sync_cron 0 */6 * * * Automatic sync schedule
sync_sources all true NVD, KEV, EPSS, CPE, Nuclei toggles
age_alert_threshold 90 Highlight average CVE age above this (days)
secure_cookies true when HTTPS install Set for HTTPS deployments
pdcp_api_key none ProjectDiscovery API key (recommended)

During install, source toggles and port are persisted via bin/odysafe-config. Most other settings are editable in the Settings UI.

HTTPS and cookies

When exposing the app beyond localhost, use HTTPS (install option or reverse proxy) and enable Secure cookies in Settings. The UI warns when HTTP is used without secure_cookies.


vulnx integration

odysafe-cve uses the vulnx v2 Go client to search and fetch CVE records.

Capability Endpoint / location
Equipment sync Unquoted affected_products.vendor / product queries with fallbacks
Live search GET /api/cves?q=...
CVE by ID GET /api/cves/{id}, cache first, then live vulnx
Filter metadata GET /api/vulnx/filters
Date queries cve_updated_at:>=YYYY-MM-DD, operators >=, >, <, <=

Rate limits (without API key): approximately 10 requests per minute. The client adds inter-page delays, retries on HTTP 429 with backoff, and surfaces a sync temporarily disabled banner in the UI. Equipment syncs run sequentially; exposed assets are prioritized.

Example queries (Dashboard search bar or API ?q=):

is_oss:true
is_remote:true
cve_updated_at:>=2024-06-01
affected_products.product:mongodb

API reference

All routes except /api/healthcheck, /api/auth/login, and /api/auth/status require a session cookie when authentication is enabled. Write endpoints enforce RBAC (403 on denial).

Auth and users

Method Path Description
GET /api/healthcheck System, sync, and vulnx health
GET /api/auth/status Whether login is required
POST /api/auth/login Create session
POST /api/auth/logout Destroy session
GET /api/auth/me Current user (email, role, must_change_password)
POST /api/auth/change-password Change password
POST /api/auth/enable Bootstrap admin and enable login
POST /api/auth/totp/setup TOTP setup
POST /api/auth/totp/verify TOTP verify
GET/POST/PUT/DELETE /api/users User management (admin)

Dashboard and CVEs

Method Path Description
GET /api/dashboard/kpis KPIs (?compare=previous, ?group_id=, ?business_criticality=)
GET /api/dashboard/heatmap CVSS x EPSS grid (?group_id=, ?business_criticality=)
GET /api/cves CVE list; filters: kev, overdue, group_id, has_notes, sync_run_id, ?q=
GET /api/cves/{id} CVE detail (cache and live)
GET /api/vulnx/filters vulnx filter field metadata
PUT /api/equipment/{eqId}/cves/{cveId}/remediation Set remediation status

Equipment, groups, import

Method Path Description
GET/POST /api/equipment List / create equipment
PUT/DELETE /api/equipment/{id} Update / delete equipment (delete: admin)
POST /api/equipment/bulk-delete Bulk delete (admin)
GET /api/equipment/suggestions Vendor/product suggestions
GET/POST/PUT/DELETE /api/equipment-groups Equipment groups
POST /api/equipment/import/preview CSV import preview
POST /api/equipment/import/confirm CSV import confirm (duplicate_mode=skip|update)

Notes, audit, executive

Method Path Description
GET/POST /api/notes List / create CVE x equipment notes
DELETE /api/notes/{id} Delete note (author or admin)
GET /api/audit-log Paginated audit log (admin; filters: user, action, dates)
GET /api/audit-log/export.csv Audit log CSV export
GET /api/executive/summary Executive KPI summary (all roles)

Settings, sync, export

Method Path Description
GET/PUT /api/settings Read/update config (masked secrets)
POST /api/settings/test/{vulnx,discord,slack,smtp} Integration tests
GET /api/settings/storage DB size, source status
POST /api/settings/storage/clear Clear cache
POST /api/settings/storage/reload Reload sources
POST /api/sync Trigger manual sync (?failed_only=true for retries)
GET /api/sync/status Sync state, rate limit, last change summary
POST /api/export/xlsx Formatted Excel export

Security

Control Implementation
Password storage bcrypt
RBAC admin / analyst / viewer on all write endpoints
Session cookies HttpOnly, SameSite=Strict, optional Secure, sliding TTL
Config and secrets AES-256-GCM in config.enc, key in config/.secret_key (mode 600)
Webhook validation Regex check on save and test (Discord/Slack)
Log redaction Webhooks, API keys, passwords masked in access logs and error bodies
Rate limiting Per-IP token bucket, JSON 429 with retry_after
Audit log Login, settings, remediation, equipment CRUD, risk accepted, group assignments (read-only, no UI delete)

Never commit config/.secret_key, config/config.enc, or data/.


Development

# Backend tests
cd backend
go test ./...
CGO_ENABLED=0 go build -o ../bin/odysafe-cve ./cmd/server

# Frontend dev server (proxies /api to localhost:8080 via vite.config.ts)
cd web
npm install
npm run dev

# Full smoke test (scripts + unit tests + config tool)
bash scripts/smoke_test.sh

Local run without install

# Terminal 1: backend
cd backend && go run ./cmd/server -root .. -port 8080

# Terminal 2: frontend
cd web && npm run dev

Initialize admin user once:

go run ./cmd/init -root ..

UI changes: edit files under web/src/, then run ./scripts/build.sh or ./install.sh.


Updating

If config/config.enc already exists, ./install.sh detects an existing install and runs in update mode (rebuild binaries and web UI, preserve data and config).

git pull
./install.sh
./stop.sh && ./start.sh

Database migrations run automatically on server start (backend/migrations/, currently 001 through 009: notes nullable user, equipment product_version, triage fields).

For a quick rebuild:

./scripts/build.sh
./stop.sh && ./start.sh

If install was run as root:

sudo ./scripts/fix-permissions.sh
sudo ./scripts/cleanup-legacy.sh

Hard-refresh the browser (Ctrl+F5) after frontend updates.


Export formats

Format Description
Excel (.xlsx) On-demand via POST /api/export/xlsx or Settings > Export. Sheets: Summary (executive, risk, exposure, temporal, exploitable, and coverage KPI sections), Equipment (per-asset CVE/KEV/PoC/risk/sync metrics), CVEs (CVE ID, vendor, product, version, CVSS, severity, EPSS, KEV/PoC/Nuclei/Remote/OSS, dates, description, references, risk score, equipment). Styled headers and conditional formatting via excelize.
Audit CSV GET /api/audit-log/export.csv for compliance exports.

Legacy CSV, JSON, and PDF export endpoints have been removed.


systemd

install.sh can install a user-specific unit under /etc/systemd/system/odysafe-cve.service. The committed template is at packaging/systemd/odysafe-cve.service - do not copy it directly.

sudo systemctl start odysafe-cve
sudo systemctl status odysafe-cve
journalctl -u odysafe-cve -f

When systemd is enabled, use ./start.sh only (it delegates to systemctl; do not run both systemd and manual nohup).


Troubleshooting

Symptom Action
404 on / Run ./install.sh or ./scripts/build.sh, then ./stop.sh && ./start.sh
Empty dashboard Add equipment in Settings, then run Scan now or Sync
Empty Vendor column (live search) Broad text queries may omit vendor; use CPE-style queries or cached list after sync
Tier shows - CVE not linked to equipment (live vulnx results only)
MTTR is 0 Mark CVE x equipment pairs as remediated in the detail modal
"Rate limit reached" banner Add PDCP API key or wait for cooldown
Degraded / cached data banner Check logs/server.log, verify vulnx connectivity
Excel export fails / 404 Re-run ./install.sh or ./scripts/build.sh; use POST /api/export/xlsx
401 on API calls Session expired, log in again
403 on API calls Role lacks permission for this action
429 on API Per-IP rate limit, wait retry_after seconds
Permission errors after install sudo ./scripts/fix-permissions.sh
Dashboard missing triage tabs / asset cards Run ./scripts/build.sh then hard-refresh (Ctrl+F5)
Excel export outdated layout Rebuild backend (./scripts/build.sh) and re-export after upgrade

Documentation


Acknowledgements

Thanks to IT-Connect for bringing this project to my attention and for the existing coverage of ProjectDiscovery vulnx that helped shape the integration.

Vulnerability intelligence is powered by the vulnx API and CVE data ecosystem from ProjectDiscovery.


License

MIT

About

Odysafe-CVE is an open-source vulnerability management platform that aggregates CVE intelligence, vulnerability feeds, and security data into a unified dashboard. It helps security teams monitor, analyze, prioritize, and track vulnerabilities through a fast, self-hosted web interface.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages