A comprehensive React + TypeScript dashboard for visualizing and analyzing security vulnerabilities in software ecosystems. This application provides powerful filtering, visualization, and analysis capabilities for large-scale vulnerability datasets.
Live deployment: Vercel | GitHub Pages
- Features
- Tech Stack
- Project Structure
- Installation
- Data Format
- Usage
- Performance Optimizations
- Development
- Deployment
- Planning Docs
- Beyond the Requirements
- Release Notes
- Git LFS Note
- Contributing
- License
- Future Enhancements
- Large Dataset Handling: Efficiently processes and displays vulnerability data files (300MB+)
- Advanced Filtering: Filter vulnerabilities by severity, status, package name, and more
- Analysis Modes:
- Analysis Mode: Filters out CVEs with
kaiStatus"invalid - norisk" - AI Analysis Mode: Filters out CVEs with
kaiStatus"ai-invalid-norisk"
- Analysis Mode: Filters out CVEs with
- Intelligent Search: Debounced search with live suggestions, hints, and contextual matches
- Interactive Visualizations: Severity distribution, risk factor frequency, trend analysis, and an AI vs manual relationship bar chart that surfaces absolute triage counts for each decision bucket
- Vulnerability Comparison: Select up to 4 vulnerabilities from the dashboard list and compare them side-by-side with a persistent selection bar
- Theme Controls: One-click dark/light mode toggle plus palette options for charts
- Data Export: Export filtered data as JSON or CSV
- Virtualization: Efficient rendering of large vulnerability lists (density adapts to user preference)
- State Management: React Context API + React Query for optimal data handling
- Persisted Preferences: User-configurable defaults, chart palettes, animation controls, and compare selections saved to localStorage
- Type Safety: Full TypeScript implementation with comprehensive type definitions
- Performance Optimized: Code splitting, memoization, and lazy loading across routes and heavy components
- Modern UI: Built with Chakra UI and Framer Motion for smooth animations
- Resilient Data Loading: Fetches the upstream
ui_demo.jsondataset with automatic fallbacks to the bundled copy and synthetic mock data - Status Normalization: Harmonizes upstream
statusstrings (e.g., numerous "fixed in …" values) to the Kai Cyber classifications for accurate pie and bar charts while keeping raw values available for drill-downs
- React 18 with TypeScript
- Vite - Fast build tool and dev server
- React Router - Client-side routing
- React Query (@tanstack/react-query) - Server state management and caching
- Chakra UI - Component library
- Recharts - Data visualization
- Framer Motion - Animations
- React Window - Virtualization for large lists
vulnerability-visualizer/
├── public/
│ └── ui_demo.json # Vulnerability data file (Git LFS)
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── AnalysisButtons.tsx # Analysis mode filter buttons
│ │ ├── Charts.tsx # Data visualization suite
│ │ ├── CompareSelectionBar.tsx # Floating compare selection bar with summary metrics
│ │ ├── CriticalHighlights.tsx # Spotlight on high-impact vulnerabilities
│ │ ├── FilterBar.tsx # Search, suggestions, and filter interface
│ │ ├── Layout.tsx # Main layout wrapper + preferences entry point
│ │ ├── PreferencesDrawer.tsx # User customization controls
│ │ ├── StatsCards.tsx # Statistics summary cards
│ │ └── VulnerabilityList.tsx # Virtualized vulnerability table with compare toggles
│ ├── context/
│ │ ├── __tests__/ # Context tests
│ │ │ └── CompareSelection.test.tsx # Compare workflow tests
│ │ ├── UserPreferencesContext.tsx # Persisted user settings
│ │ └── VulnerabilityContext.tsx # Global vulnerability state management + compare selection
│ ├── hooks/
│ │ ├── useDebounce.ts # Debounce hook for search
│ │ ├── useLocalStorage.ts # LocalStorage-backed state helper
│ │ └── useVulnerabilityData.ts # React Query hook for data loading
│ ├── pages/
│ │ ├── Dashboard.tsx # Main dashboard page
│ │ ├── VulnerabilityDetail.tsx # Individual vulnerability view
│ │ └── Comparison.tsx # Vulnerability comparison page
│ ├── types/
│ │ └── vulnerability.ts # TypeScript type definitions
│ ├── utils/
│ │ ├── dataLoader.ts # Data loading utilities
│ │ ├── dataProcessor.ts # Filtering and processing logic
│ │ └── export.ts # Export functionality
│ ├── App.tsx # Main app component
│ ├── main.tsx # Application entry point
│ └── theme.ts # Chakra UI theme configuration
├── package.json
├── tsconfig.json
└── vite.config.ts
- Node.js 18+ and npm/yarn/pnpm
- Git LFS (if working with the actual ui_demo.json file)
-
Clone the repository
git clone <repository-url> cd vulnerability-visualizer
-
Install Git LFS (if needed for ui_demo.json)
git lfs install git lfs pull
-
Install dependencies
npm install # or yarn install # or pnpm install
-
(Optional) Pull the full dataset locally before starting dev:
npm run prebuild
Skip this step if you are happy using the bundled sample data.
-
Start the development server
npm run dev # or yarn dev # or pnpm dev
-
Open your browser Navigate to
http://localhost:3000
The application expects vulnerability data in JSON format. The data loader supports multiple formats:
- Array of vulnerabilities:
[{...}, {...}] - Object with
vulnerabilitieskey:{ vulnerabilities: [...] } - Object with
datakey:{ data: [...] } - Hierarchical object with
groups -> repos -> images -> vulnerabilities(as provided by the upstream dataset)
{
id: string; // Unique identifier
cveId?: string; // CVE identifier
packageName?: string; // Affected package name
packageVersion?: string; // Package version
severity?: 'critical' | 'high' | 'medium' | 'low' | 'info' | 'unknown';
kaiStatus?: 'invalid - norisk' | 'ai-invalid-norisk' | 'valid' | 'ai-valid' | 'pending' | 'unknown';
score?: number; // Vulnerability score
cvss?: { // CVSS details
version?: string;
baseScore?: number;
vector?: string;
};
description?: string; // Vulnerability description
publishedDate?: string; // ISO date string
modifiedDate?: string; // ISO date string
riskFactors?: Array<{ // Risk factor data
name: string;
value: string | number;
category?: string;
}>;
references?: string[]; // Reference URLs
}The main dashboard displays:
- Statistics Cards: Overview of vulnerabilities by severity
- Filter Bar: Intelligent search, live suggestions, and filters
- Analysis Mode Buttons: Quick filters for analysis workflows
- Charts: Severity, risk factors, trend analysis, and AI vs manual relationship
- Critical Spotlight: Highlights the most urgent items after filtering
- Vulnerability List: Virtualized, density-aware table of all vulnerabilities
- Search: Type in the search box to filter by CVE ID, package name, or description. The suggestion drawer offers context-aware recommendations, quick severity/status filters, and description matches.
- Severity Filter: Select a severity level from the dropdown
- Status Filter: Filter by kaiStatus value
- Analysis Modes:
- All Vulnerabilities: Shows all data
- Analysis: Excludes "invalid - norisk" CVEs
- AI Analysis: Excludes "ai-invalid-norisk" CVEs
Click on any CVE ID in the vulnerability list to view detailed information including:
- Basic information (CVE ID, package, severity, status)
- Description
- CVSS scores
- Risk factors
- Dates
- References
- Add to Compare: Use the "Add to Compare" button on the detail page to add the vulnerability to your comparison set
- Select vulnerabilities: Click the "Compare" button on any vulnerability row in the dashboard list (or use the "Add to Compare" button on detail pages)
- Review selection: A floating selection bar appears at the bottom showing your selected items (up to 4), summary metrics, and quick actions
- Compare: Click "Compare" in the selection bar to navigate to the comparison page, or visit the "Compare" tab directly
- Persistent selection: Your compare selections are saved to localStorage and persist across page reloads
Use the "Export JSON" or "Export CSV" buttons on the dashboard to export the currently filtered dataset.
- Open the settings icon in the header to choose default analysis mode, table density, animation preference, and chart palette.
- Preferences are stored locally, so your preferred layout persists between sessions.
- Virtualization: Large lists use react-window with overscan tuning and density preferences
- Debounced Search: Search input is debounced to reduce filtering operations
- Memoization: Components and computations are memoized where appropriate
- Code Splitting: Routes are lazy-loaded for faster initial load
- React Query: Intelligent caching and data fetching
- Palette-aware Rendering: Visualization components adapt to colorblind-friendly or night modes
- Resilient fetching: Remote dataset is retrieved from GitHub with graceful fallback to the local copy or generated mock data
- Full-dataset visualization: The dashboard renders all 236k+ upstream exposure records, while export utilities still deduplicate by CVE when generating CSV/JSON handoffs
- Primary dataset:
ui_demo.json - The runtime loader first prefers the remote URL, then the build-time copy at
/ui_demo.json, and finally the curated sample (/ui_demo.sample.json) before generating mock data. - When targeting GitHub Pages set
DEPLOY_TARGET=github-pages(the workflow already does this) so Vite outputs todist-github-pagesand uses the repository sub-path. For Vercel/Netlify or local builds leaveDEPLOY_TARGETunset to build intodistwith a site root base. - When the prebuild fetch succeeds the build script sets
VITE_DATA_SOURCE=prebuiltso the UI surfaces the badge asremote (prebuilt)(indicating the upstream dataset was bundled during the build). Leave this unset when you want to rely on runtime fetching. - As a last resort, realistic mock data is generated so the dashboard always renders. The source badge communicates:
remote– fetched live from GitHub at runtimeremote (prebuilt)– upstream dataset downloaded during the build and served from the static host/CDNlocal sample– bundled curated sample for offline demosmock– generated fallback when neither upstream nor bundled data is reachable
npm run prebuildpulls the canonical dataset intopublic/ui_demo.jsonusingscripts/fetch-data.mjs. This step runs automatically duringnpm run build(for Vercel or local production builds). The script understands Git LFS pointers and will dereference them to download the real payload frommedia.githubusercontent.com.npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run ESLintnpm run type-check- Validate TypeScript types withtsc --noEmitnpm run test- Execute the Vitest + Testing Library suite
- GitHub Pages: Automated via
.github/workflows/deploy.yml. Builds withDEPLOY_TARGET=github-pages, skips the runtime fetch (SKIP_DATA_FETCH=true), and publishes the prebuilt artifact fromdist-github-pages/. - Vercel: Imports directly from GitHub. Leave
DEPLOY_TARGETunset so build output lands indist/.npm run buildstill runsprebuild, ensuring the canonical dataset is bundled even when GitHub Pages is not the target.
The active and future backlog files are the canonical work queues. Release notes, architecture docs, and QA reports can provide context, but new work should be promoted into one of the backlog files.
- Persisted user preferences (analysis defaults, density, chart palette, animation toggle)
- Intelligent search suggestions with quick severity/status pivots
- Virtualized list with adaptive density and optional animations
- Filter impact meter quantifying how many CVEs are hidden by the current filters
- Manual vs AI analysis comparison using a grouped bar chart with absolute counts
- Improved compare workflow: Select vulnerabilities directly from the dashboard list with a persistent selection bar showing summary metrics (highest severity, average score, status breakdown)
- Compare selections persist across sessions via localStorage
- Toast notifications for compare actions (add/remove/limit reached)
- v1.3.0 – Full-dataset visuals, Kai status normalization, and manual vs AI bar chart
- v1.2.0 – Dark mode toggle, lint/type/test gates, and data ingestion overhaul
- The upstream
ui_demo.jsonis a 300MB+ Git LFS object. Rungit lfs install && git lfs pullor executenpm run prebuildto download the full payload locally. The repository ships with a curatedui_demo.sample.jsonfor quick demos when bandwidth or storage is constrained.
Contributions are welcome! Fork the repository, create a branch, and open a pull request. Please run npm run lint, npm run type-check, and npm run test before submitting.
MIT License. See LICENSE for details.
Future work now lives in Future Backlog so the README does not become a second planning queue.