jramos 9893460b64 feat(reporting): add Finding ID column
ID was already stored in the cache from f.id; exposed as a sortable
column (filterable: false — too many unique values to be useful as a filter).
Existing users get it appended to the end of their saved column order
via the loadColumnOrder merge logic; new users see it first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 14:23:50 -06:00

CVE Dashboard

A self-hosted vulnerability management dashboard for tracking CVE remediation status, maintaining vendor documentation, and managing risk acceptance workflows.


Table of Contents


Overview

The CVE Dashboard answers a common problem in vulnerability management: before requesting false positive designations, you need to know whether a CVE has already been addressed, and whether the supporting vendor documentation exists. This application provides:

  • A searchable, filterable CVE list with per-vendor tracking
  • Document storage attached to each CVE/vendor pair (advisories, emails, screenshots, patches)
  • NVD API integration to auto-populate CVE metadata
  • Archer risk acceptance ticket tracking (EXC numbers)
  • Weekly vulnerability report upload and processing
  • A knowledge base for internal documentation and policies
  • Role-based access control with a full audit trail

Tech Stack

Layer Technology
Backend Node.js, Express 5
Database SQLite3
File uploads Multer 2
Auth bcryptjs, cookie-based sessions
Frontend React 19, lucide-react, react-markdown
Report processing Python 3 (pandas, openpyxl)

Prerequisites

  • Node.js 18 or later
  • npm
  • Python 3 with pip (required only for weekly report processing)

Installation

1. Clone the repository

git clone <repo-url>
cd cve-dashboard

2. Install backend dependencies

cd backend
npm install

The root package.json lists the backend dependencies. Install them from the backend/ directory where server.js lives.

3. Install frontend dependencies

cd frontend
npm install

4. Install Python dependencies (for weekly report upload feature)

cd backend/scripts
pip install -r requirements.txt

Required packages: pandas>=2.0.0, openpyxl>=3.0.0

5. Initialize the database

Run this once from the backend/ directory to create the SQLite database, all tables, indexes, the uploads directory, and a default admin user:

cd backend
node setup.js

This creates backend/cve_database.db and a default admin account:

  • Username: admin
  • Password: admin123

Change the admin password immediately after first login.

6. Run database migrations

After the initial setup, apply the feature migrations in order:

cd backend
node migrations/add_weekly_reports_table.js
node migrations/add_knowledge_base_table.js
node migrations/add_archer_tickets_table.js

Configuration

The application is configured via .env files. These files are gitignored and must be created manually per environment.

Backend: backend/.env

PORT=3001
API_HOST=localhost
CORS_ORIGINS=http://YOUR_IP:3000
SESSION_SECRET=change-this-to-a-random-secret
NODE_ENV=development

# Optional: NVD API key for higher rate limits
# Register at https://nvd.nist.gov/developers/request-an-api-key
NVD_API_KEY=your-key-here

Frontend: frontend/.env

REACT_APP_API_BASE=http://YOUR_IP:3001/api
REACT_APP_API_HOST=http://YOUR_IP:3001

Replace YOUR_IP with the machine's IP address or localhost for local development.

Important: React caches environment variables at build/start time. After changing frontend/.env, you must fully restart the frontend process. A page refresh alone is not sufficient.


Running the Application

From the project root:

./start-servers.sh   # Starts backend and frontend in the background
./stop-servers.sh    # Stops all servers

The start script saves PIDs to backend.pid and frontend.pid. Logs are written to backend/backend.log and frontend/frontend.log.

Running manually

# Terminal 1 - backend
cd backend
node server.js

# Terminal 2 - frontend
cd frontend
npm start

Default ports


Features

Authentication and User Roles

All routes require authentication. Three roles are supported:

Role Permissions
viewer Read-only access to CVEs, documents, weekly reports, knowledge base, Archer tickets
editor All viewer permissions plus: create/update CVEs, upload documents, upload weekly reports, manage knowledge base articles, manage Archer tickets
admin All editor permissions plus: delete documents, delete weekly reports, manage users, view audit logs

Sessions expire after 24 hours. Session tokens are stored in httpOnly cookies.

CVE Management

  • Add CVEs with full metadata: CVE ID, vendor, severity (Critical/High/Medium/Low), description, published date, and status (Open/In Progress/Addressed/Resolved)
  • The same CVE ID can be tracked across multiple vendors independently
  • Filter the CVE list by search term, vendor, severity, and status
  • Edit any field on an existing CVE entry; file paths are updated automatically when CVE ID or vendor changes
  • Delete a single vendor entry or all vendor entries for a CVE ID
  • Paginated list view to prevent performance issues with large datasets
  • Quick Check: look up a CVE ID and see all vendors tracking it with their current status

NVD Integration

  • Auto-fill CVE description, severity, and published date from the NIST NVD API 2.0 when adding a new CVE
  • Bulk NVD Sync: fetch updated metadata for all CVEs in the database in one operation (editor/admin)
  • CVSS severity mapping cascades: v3.1 preferred, then v3.0, then v2.0
  • NVD API key support via NVD_API_KEY environment variable for higher rate limits

Document Management

Documents are attached to a CVE/vendor pair and stored on disk under backend/uploads/<CVE-ID>/<vendor>/.

Supported document types: advisory, email, screenshot, patch, other

Allowed file extensions: PDF, images (PNG, JPG, GIF, BMP, TIFF), Office documents (DOC, DOCX, XLS, XLSX, PPT, PPTX), text files (TXT, MD, CSV, LOG), email files (MSG, EML), and others (RTF, HTML, XML, JSON, YAML, ODF variants).

File size limit: 10 MB per upload.

Weekly Reports

Editors and admins can upload weekly vulnerability reports as .xlsx files. The report is processed by a Python script (backend/scripts/split_cve_report.py) that:

  1. Reads the Vulnerabilities sheet
  2. Splits rows where multiple CVE IDs are comma-separated in the CVE ID column into individual rows
  3. Saves the processed file alongside the original

Both the original and processed files can be downloaded from the weekly reports list. Only the most recently uploaded report is marked as current. Admins can delete old report records and their associated files.

Archer Risk Acceptance Tickets

Track Archer exception tickets (EXC numbers) linked to specific CVE/vendor pairs.

  • EXC number format: EXC-NNNNN
  • Statuses: Draft, Open, Under Review, Accepted
  • Optional Archer URL field for deep-linking to the Archer record
  • Filter tickets by CVE ID, vendor, or status
  • EXC numbers are unique across the system

Knowledge Base

A document library for internal reference material such as policies, runbooks, and vendor advisories.

  • Upload documents with a title, optional description, and category
  • View documents inline in the browser (PDFs render in an iframe; markdown files are rendered as HTML)
  • Download any document
  • Filter and browse by category
  • Editors and admins can upload and delete; all authenticated users can view

Allowed file types: PDF, Markdown, TXT, Office documents, HTML, JSON, YAML, and images.

User Management (Admin)

Admins can create, update, and delete user accounts from the UI. Supported operations:

  • Create users with a role assignment
  • Change username, email, password, role, or active status
  • Deactivating a user immediately invalidates all their active sessions
  • Admins cannot demote themselves or deactivate their own account

Audit Log (Admin)

Every state-changing action is recorded with the user identity, IP address, action type, target entity, and a before/after details payload. Admins can view the audit log with filtering by user, action type, entity type, and date range. Results are paginated.


API Reference

All endpoints are prefixed with /api. All endpoints except /api/auth/login and /api/auth/logout require a valid session cookie.

Auth

Method Path Auth Description
POST /api/auth/login Public Log in, receive session cookie
POST /api/auth/logout Public Invalidate session
GET /api/auth/me Session Get current user info
POST /api/auth/cleanup-sessions Session Delete expired sessions

CVEs

Method Path Role Description
GET /api/cves viewer+ List CVEs with optional filters: search, vendor, severity, status
POST /api/cves editor+ Create a new CVE entry
PUT /api/cves/:id editor+ Update a CVE entry by row ID
PATCH /api/cves/:cveId/status editor+ Update status for all vendor rows matching a CVE ID
DELETE /api/cves/:id editor+ Delete a single CVE vendor entry
DELETE /api/cves/by-cve-id/:cveId editor+ Delete all vendor entries for a CVE ID
GET /api/cves/check/:cveId viewer+ Quick check: does this CVE exist and what is its status?
GET /api/cves/distinct-ids viewer+ List all distinct CVE IDs (used by NVD sync)
GET /api/cves/:cveId/vendors viewer+ List all vendor entries for a specific CVE ID

Documents

Method Path Role Description
GET /api/cves/:cveId/documents viewer+ List documents for a CVE, optionally filtered by ?vendor=
POST /api/cves/:cveId/documents editor+ Upload a document for a CVE/vendor pair
DELETE /api/documents/:id admin Delete a document and its file from disk

NVD

Method Path Role Description
GET /api/nvd/lookup/:cveId viewer+ Look up a single CVE in the NVD API
POST /api/cves/nvd-sync editor+ Bulk update CVE metadata from NVD

Weekly Reports

Method Path Role Description
POST /api/weekly-reports/upload editor+ Upload and process a .xlsx vulnerability report
GET /api/weekly-reports viewer+ List all uploaded reports
GET /api/weekly-reports/:id/download/:type viewer+ Download original or processed file
DELETE /api/weekly-reports/:id admin Delete a report record and its files

Knowledge Base

Method Path Role Description
POST /api/knowledge-base/upload editor+ Upload a new knowledge base document
GET /api/knowledge-base viewer+ List all articles
GET /api/knowledge-base/:id viewer+ Get article metadata
GET /api/knowledge-base/:id/content viewer+ Get file content for inline display
GET /api/knowledge-base/:id/download viewer+ Download the file
DELETE /api/knowledge-base/:id editor+ Delete article and file

Archer Tickets

Method Path Role Description
GET /api/archer-tickets viewer+ List tickets, optional filters: cve_id, vendor, status
POST /api/archer-tickets editor+ Create a new Archer ticket
PUT /api/archer-tickets/:id editor+ Update an Archer ticket
DELETE /api/archer-tickets/:id editor+ Delete an Archer ticket

Users (Admin only)

Method Path Role Description
GET /api/users admin List all users
GET /api/users/:id admin Get a single user
POST /api/users admin Create a user
PATCH /api/users/:id admin Update a user
DELETE /api/users/:id admin Delete a user

Audit Logs (Admin only)

Method Path Role Description
GET /api/audit-logs admin Paginated audit log with filters
GET /api/audit-logs/actions admin List distinct action types

Utility

Method Path Role Description
GET /api/vendors viewer+ List all distinct vendor names
GET /api/stats viewer+ Dashboard statistics (total CVEs, critical count, addressed count, document count)

Architecture

cve-dashboard/
├── start-servers.sh          # Start backend + frontend in background
├── stop-servers.sh           # Stop all servers
│
├── backend/
│   ├── server.js             # Express app, CVE/document endpoints, middleware
│   ├── setup.js              # One-time DB initialization and default admin creation
│   ├── cve_database.db       # SQLite database (gitignored)
│   ├── uploads/              # File storage (gitignored)
│   │   ├── <CVE-ID>/
│   │   │   └── <vendor>/     # CVE documents stored here
│   │   ├── weekly_reports/   # Uploaded vulnerability reports
│   │   ├── knowledge_base/   # Knowledge base documents
│   │   └── temp/             # Temporary upload staging directory
│   ├── routes/
│   │   ├── auth.js           # Login, logout, session check
│   │   ├── users.js          # User CRUD (admin)
│   │   ├── auditLog.js       # Audit log viewer (admin)
│   │   ├── nvdLookup.js      # NVD API proxy
│   │   ├── weeklyReports.js  # Weekly report upload and management
│   │   ├── knowledgeBase.js  # Knowledge base document management
│   │   └── archerTickets.js  # Archer EXC ticket CRUD
│   ├── middleware/
│   │   └── auth.js           # requireAuth and requireRole middleware
│   ├── helpers/
│   │   ├── auditLog.js       # logAudit helper
│   │   └── excelProcessor.js # Calls Python script for report processing
│   ├── migrations/
│   │   ├── add_weekly_reports_table.js
│   │   ├── add_knowledge_base_table.js
│   │   └── add_archer_tickets_table.js
│   └── scripts/
│       ├── split_cve_report.py   # Python: splits multi-CVE rows in Excel reports
│       └── requirements.txt      # pandas, openpyxl
│
└── frontend/
    └── src/
        ├── App.js                # Main application, CVE list, filters, modals
        ├── App.css               # Global styles
        ├── contexts/
        │   └── AuthContext.js    # Auth state provider
        └── components/
            ├── LoginForm.js         # Login page
            ├── UserMenu.js          # User dropdown in header
            ├── UserManagement.js    # Admin user management panel
            ├── AuditLog.js          # Admin audit log viewer
            ├── NvdSyncModal.js      # Bulk NVD sync dialog
            ├── WeeklyReportModal.js # Weekly report upload dialog
            ├── KnowledgeBaseModal.js   # Knowledge base upload/list
            └── KnowledgeBaseViewer.js  # Inline document viewer

Database Schema

Core tables

cves - One row per CVE/vendor pair. UNIQUE(cve_id, vendor).

documents - Files attached to a CVE/vendor pair. Foreign key to cves(cve_id).

required_documents - Vendor-specific document requirements (advisory, screenshot, etc.).

users - Accounts with roles: admin, editor, viewer.

sessions - Active sessions. Expire after 24 hours.

audit_logs - Append-only log of all state-changing actions.

Feature tables (added by migrations)

weekly_reports - Metadata for uploaded vulnerability reports. Tracks original and processed file paths, row counts, uploader, and a is_current flag.

knowledge_base - Document library entries with title, slug, category, description, and file metadata.

archer_tickets - Archer EXC exception tickets linked to CVE/vendor pairs. UNIQUE(exc_number).

View

cve_document_status - Aggregates document counts per CVE/vendor and derives a compliance_status (Complete when an advisory is present, otherwise Missing Required Docs).


Security Model

File upload security

  • Extension allowlist enforced by Multer; executables (.exe, .js, .sh, .py, .bat, etc.) are blocked
  • MIME type prefix validation in addition to extension checking
  • 10 MB per-file size limit
  • Filenames are sanitized: path separators, .. sequences, null bytes, and non-alphanumeric characters are removed

Path traversal prevention

  • sanitizePathSegment() strips /, \, .., and null bytes from any value used in path.join()
  • isPathWithinUploads() verifies resolved paths stay within the uploads root before any file operation

Input validation

  • CVE ID must match /^CVE-\d{4}-\d{4,}$/
  • Severity must be one of: Critical, High, Medium, Low
  • Status must be one of: Open, Addressed, In Progress, Resolved
  • Archer EXC numbers must match /^EXC-\d+$/
  • All database operations use prepared statements

Error handling

  • 500 responses never leak internal error messages to the client
  • Full errors are logged server-side only
  • Descriptive 400/409 responses are safe because they contain only validation messages written by the application

Security headers

Applied to all responses:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
  • Permissions-Policy: camera=(), microphone=(), geolocation=()

Session cookies

httpOnly: true, sameSite: lax, secure: true in production.


Migrations

Migrations are standalone Node.js scripts that alter the database directly. Run them in the order listed. They use CREATE TABLE IF NOT EXISTS, so they are safe to run again if needed.

cd backend
node migrations/add_weekly_reports_table.js
node migrations/add_knowledge_base_table.js
node migrations/add_archer_tickets_table.js

For an existing deployment upgrading from an earlier schema, also check the legacy migration scripts in backend/:

  • migrate_multivendor.js - Adds multi-vendor support to an older single-vendor schema
  • migrate-audit-log.js - Adds the audit_logs table to pre-auth deployments
  • migrate-to-1.1.js - General 1.0 to 1.1 schema update
Description
No description provided
Readme 20 MiB
Languages
JavaScript 98.5%
CSS 0.6%
Python 0.5%
Shell 0.3%
HTML 0.1%