Files
vulncheck/DATABASE_SCHEMA.md
T
vulncheck 6969d0c62e Initial release v1.0.0
VulnCheck - Open Source Vulnerability Management for Wazuh

Features:
- Vulnerability management with Wazuh integration
- AI-powered CVE analysis (OpenAI, Anthropic, Google, DeepSeek, Ollama, Infomaniak)
- SLA policy enforcement with automated email alerts
- Automated patch verification via Wazuh Syscollector
- Role-based access control (Admin, Editor, Readonly)
- PDF/CSV reporting for compliance workflows
- Full audit trail

https://gitea.isuit.ch/vulncheck/vulncheck
2026-02-08 10:15:20 +01:00

16 KiB
Raw Blame History

VulnManager - Database Schema

Entity Relationship Diagram (ERD)

┌─────────────────┐
│     users       │
├─────────────────┤
│ id (PK)         │
│ username        │◄────────┐
│ email           │         │
│ password_hash   │         │
│ role            │         │
│ is_active       │         │
│ is_verified     │         │
│ failed_login    │         │
│ created_at      │         │
│ updated_at      │         │
└─────────────────┘         │
                            │ (1:N)
                            │
                    ┌───────┴──────────┐
                    │   audit_logs     │
                    ├──────────────────┤
                    │ id (PK)          │
                    │ user_id (FK)     │
                    │ event_type       │
                    │ event_description│
                    │ ip_address       │
                    │ user_agent       │
                    │ resource_type    │
                    │ resource_id      │
                    │ old_value        │
                    │ new_value        │
                    │ timestamp        │
                    └──────────────────┘

┌─────────────────────┐
│       assets        │
├─────────────────────┤
│ id (PK)             │◄──────────┐
│ hostname            │           │
│ ip_address          │           │ (1:N)
│ wazuh_agent_id      │           │
│ operating_system    │           │
│ os_version          │     ┌─────┴──────────────┐
│ kernel_version      │     │  vulnerabilities   │
│ source              │     ├────────────────────┤
│ status              │     │ id (PK)            │
│ last_scan           │     │ cve_id             │
│ last_seen           │     │ asset_id (FK)      │◄────┐
│ description         │     │ cvss_score         │     │
│ location            │     │ cvss_vector        │     │
│ owner               │     │ severity           │     │ (1:1)
│ created_at          │     │ status             │     │
│ updated_at          │     │ title              │     │
└─────────────────────┘     │ description        │     │
          │                 │ package_name       │     │
          │ (1:N)           │ package_version    │     │
          │                 │ fixed_version      │     │
          └─────────┐       │ exploitable        │     │
                    │       │ exploit_available  │     │
              ┌─────┴──────┤ exploit_maturity   │     │
              │   scans    ││ published_date     │     │
              ├────────────┤│ detected_at        │     │
              │ id (PK)    ││ patched_at         │     │
              │ asset_id   ││ references         │     │
              │ scan_type  ││ cwe_id             │     │
              │ status     ││ created_at         │     │
              │ started_at ││ updated_at         │     │
              │ completed  │└────────────────────┘     │
              │ vuln_found │                           │
              │ vuln_new   │                           │
              │ vuln_resolv│                           │
              │ error_msg  │       ┌───────────────────┘
              │ created_at │       │
              │ updated_at │       │
              └────────────┘       │
                            ┌──────┴───────────────┐
                            │   ai_analyses        │
                            ├──────────────────────┤
                            │ id (PK)              │
                            │ vulnerability_id (FK)│
                            │ analysis_text        │
                            │ threat_level         │
                            │ exploits_found       │
                            │ workarounds          │
                            │ remediation_steps    │
                            │ threat_intel_sources │
                            │ model_version        │
                            │ confidence_score     │
                            │ analysis_timestamp   │
                            │ cache_expires_at     │
                            │ created_at           │
                            │ updated_at           │
                            └──────────────────────┘

Table Details

1. users

Stores user accounts with Role-Based Access Control (RBAC).

Columns:

  • id (INTEGER, PK): Unique User ID
  • username (VARCHAR(50), UNIQUE): Login name
  • email (VARCHAR(255), UNIQUE): Email address
  • password_hash (VARCHAR(255)): bcrypt hash of the password
  • role (ENUM): admin, editor, readonly
  • is_active (BOOLEAN): Account active/deactivated
  • is_verified (BOOLEAN): Email verified
  • failed_login_attempts (INTEGER): Counter for failed logins
  • created_at, updated_at (TIMESTAMP): Timestamps

Indexes:

  • ix_users_username (UNIQUE)
  • ix_users_email (UNIQUE)
  • ix_users_role

Permission Hierarchy:

ADMIN
  └─> All rights (User Management, Config, Delete)
EDITOR
  └─> Read + Write (Change vulnerability status, create assets)
READONLY
  └─> Read only (Dashboard, Reports)

2. assets

Inventory of all monitored systems (Wazuh Agents + manual entries).

Columns:

  • id (INTEGER, PK): Unique Asset ID
  • hostname (VARCHAR(255)): Hostname of the system
  • ip_address (VARCHAR(45)): IPv4/IPv6 address
  • wazuh_agent_id (VARCHAR(10), UNIQUE): Wazuh Agent ID (e.g., "001")
  • operating_system (VARCHAR(255)): OS Name (e.g., "Ubuntu 22.04")
  • os_version (VARCHAR(100)): Version
  • kernel_version (VARCHAR(100)): Kernel Version
  • source (ENUM): wazuh, manual
  • status (ENUM): active, inactive, decommissioned
  • last_scan (TIMESTAMP): Last vulnerability scan
  • last_seen (TIMESTAMP): Last contact (for Wazuh Agents)
  • description (TEXT): Free-text description
  • location (VARCHAR(255)): Physical location
  • owner (VARCHAR(255)): Responsible person/team
  • created_at, updated_at (TIMESTAMP): Timestamps

Indexes:

  • ix_assets_hostname
  • ix_assets_ip_address
  • ix_assets_wazuh_agent_id (UNIQUE)
  • ix_assets_source
  • ix_assets_status

Use Cases:

  • Wazuh Agents are automatically added upon the first scan
  • Manual assets for systems without an agent (e.g., network hardware)
  • last_seen for health monitoring (Alert if agent > 24h offline)

3. vulnerabilities

Central table for all detected security vulnerabilities.

Columns:

  • id (INTEGER, PK): Unique Vulnerability ID
  • cve_id (VARCHAR(20)): CVE identifier (e.g., "CVE-2024-1234")
  • asset_id (INTEGER, FK → assets.id): Affected system
  • cvss_score (FLOAT): CVSS Score (0.0-10.0)
  • cvss_vector (VARCHAR(100)): CVSS Vector String
  • severity (ENUM): critical, high, medium, low, none
  • status (ENUM): open, patched, pending_verification, patch_failed, accepted_risk, false_positive
  • title (VARCHAR(500)): Short description
  • description (TEXT): Detailed description
  • package_name (VARCHAR(255)): Affected software package
  • package_version (VARCHAR(100)): Installed version
  • fixed_version (VARCHAR(100)): Version with fix
  • exploitable (BOOLEAN): Potentially exploitable
  • exploit_available (BOOLEAN): Public exploit available
  • exploit_maturity (VARCHAR(50)): poc, functional, high
  • published_date (TIMESTAMP): CVE publication date
  • detected_at (TIMESTAMP): First detected
  • patched_at (TIMESTAMP): Marked as patched
  • references (TEXT): JSON array with URLs (NVD, Vendor Advisories)
  • cwe_id (VARCHAR(20)): CWE identifier (e.g., "CWE-79")
  • created_at, updated_at (TIMESTAMP): Timestamps

Indexes:

  • ix_vulnerabilities_cve_id
  • ix_vulnerabilities_asset_id
  • ix_vulnerabilities_cvss_score
  • ix_vulnerabilities_severity
  • ix_vulnerabilities_status
  • ix_vulnerabilities_package_name
  • ix_vulnerabilities_exploitable
  • ix_vulnerabilities_detected_at
  • idx_vuln_status_severity (Composite)
  • idx_vuln_asset_status (Composite)

Severity Mapping (based on CVSS):

CRITICAL → 9.0-10.0
HIGH     → 7.0-8.9
MEDIUM   → 4.0-6.9
LOW      → 0.1-3.9
NONE     → 0.0

Priority Score Calculation:

Priority = (CVSS × 5) + (Exploitability × 30) + (Age × 20)
         = 0-50 points + 0-30 points        + 0-20 points
         = 0-100 points

Exploitability:
- Exploit available: 30 points
- Exploitable: 15 points
- No info: 0 points

Age:
- Linearly increasing: 0-20 points (0 days = 0, 30+ days = 20)

4. scans

History of all performed vulnerability scans.

Columns:

  • id (INTEGER, PK): Unique Scan ID
  • asset_id (INTEGER, FK → assets.id): Scanned asset
  • scan_type (ENUM): full, syscollector, manual
  • status (ENUM): pending, running, completed, failed
  • started_at (TIMESTAMP): Scan start
  • completed_at (TIMESTAMP): Scan end
  • vulnerabilities_found (INTEGER): Number of vulnerabilities found
  • vulnerabilities_new (INTEGER): New vulnerabilities since last scan
  • vulnerabilities_resolved (INTEGER): Resolved vulnerabilities
  • error_message (TEXT): Error message if status = failed
  • created_at, updated_at (TIMESTAMP): Timestamps

Indexes:

  • ix_scans_asset_id
  • ix_scans_status

Scan Types:

  • full: Complete Wazuh scan (all packages)
  • syscollector: Syscollector rescan after patch
  • manual: Manually triggered (e.g., after system update)

5. ai_analyses

Cached AI analyses of CVEs (Infomaniak AI API).

Columns:

  • id (INTEGER, PK): Unique Analysis ID
  • vulnerability_id (INTEGER, FK → vulnerabilities.id, UNIQUE): 1:1 Relationship
  • analysis_text (TEXT): Full LLM Output (Markdown)
  • threat_level (VARCHAR(20)): low, medium, high, critical
  • exploits_found (TEXT): JSON array with exploit links
  • workarounds (TEXT): JSON array with temporary fixes
  • remediation_steps (TEXT): JSON array with step-by-step instructions
  • threat_intel_sources (TEXT): JSON array with Threat Intel URLs
  • model_version (VARCHAR(50)): LLM Model (e.g., "gpt-4o")
  • confidence_score (VARCHAR(20)): low, medium, high
  • analysis_timestamp (TIMESTAMP): Time of analysis
  • cache_expires_at (TIMESTAMP): Cache expiration (24h TTL)
  • created_at, updated_at (TIMESTAMP): Timestamps

Indexes:

  • ix_ai_analyses_vulnerability_id (UNIQUE)

Cache Strategy:

TTL: 24 hours
- After expiration: New API call on next request
- On CVE update (e.g., new exploit): Invalidate cache

6. audit_logs

Audit trail for security and compliance requirements.

Columns:

  • id (INTEGER, PK): Unique Log ID
  • user_id (INTEGER, FK → users.id, NULLABLE): User (NULL for system events)
  • event_type (ENUM): See Event Types below
  • event_description (VARCHAR(500)): Human-readable description
  • ip_address (VARCHAR(45)): Client IP
  • user_agent (VARCHAR(500)): Browser/Client Info
  • resource_type (VARCHAR(50)): e.g., "vulnerability", "asset"
  • resource_id (VARCHAR(50)): ID of the affected resource
  • old_value (TEXT): JSON with old values (for diffs)
  • new_value (TEXT): JSON with new values
  • timestamp (TIMESTAMP): Event time

Indexes:

  • ix_audit_logs_user_id
  • ix_audit_logs_event_type
  • ix_audit_logs_timestamp

Event Types:

Authentication:

  • login_success: Successful login
  • login_failed: Failed login (Rate-Limiting trigger)
  • logout: Logout
  • password_change: Password changed

Authorization:

  • access_denied: Access denied (403)
  • permission_escalation: Role changed (Admin action)

Data Operations:

  • vulnerability_status_change: Status changed (e.g., open → patched)
  • asset_created: New asset added
  • asset_updated: Asset data updated
  • asset_deleted: Asset deleted

Scans:

  • scan_triggered: Scan started
  • scan_completed: Scan completed

AI:

  • ai_analysis_requested: AI analysis requested

System:

  • config_change: Configuration changed
  • security_alert: Security alert (e.g., Critical CVE)

Retention Policy:

Standard: 90 days
Critical Events (security_alert, access_denied): 1 year
Compliance: Adjustable per GDPR/HIPAA/SOC2

Constraints and Foreign Keys

-- Foreign Key Constraints
ALTER TABLE vulnerabilities
  ADD CONSTRAINT fk_vulnerability_asset
  FOREIGN KEY (asset_id) REFERENCES assets(id)
  ON DELETE CASCADE;

ALTER TABLE scans
  ADD CONSTRAINT fk_scan_asset
  FOREIGN KEY (asset_id) REFERENCES assets(id)
  ON DELETE CASCADE;

ALTER TABLE ai_analyses
  ADD CONSTRAINT fk_ai_analysis_vulnerability
  FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id)
  ON DELETE CASCADE;

ALTER TABLE audit_logs
  ADD CONSTRAINT fk_audit_log_user
  FOREIGN KEY (user_id) REFERENCES users(id)
  ON DELETE SET NULL;  -- Logs remain when user is deleted

Migration Commands

run initial Migration

# Create migration (autogenerate)
alembic revision --autogenerate -m "Initial schema"

# Apply migration
alembic upgrade head

# Revert migration
alembic downgrade -1

# Show current state
alembic current

Seed Data (Create Admin User)

from app.models.user import User, UserRole
from app.database import SessionLocal
from passlib.hash import bcrypt

db = SessionLocal()
admin = User(
    username="admin",
    email="admin@vulnmanager.local",
    password_hash=bcrypt.hash("changeme"),
    role=UserRole.ADMIN,
    is_active=True,
    is_verified=True
)
db.add(admin)
db.commit()

Performance Optimizations

1. Partitioning (for large datasets)

-- Partition vulnerabilities by status
CREATE TABLE vulnerabilities_open PARTITION OF vulnerabilities
  FOR VALUES IN ('open', 'pending_verification');

CREATE TABLE vulnerabilities_closed PARTITION OF vulnerabilities
  FOR VALUES IN ('patched', 'patch_failed', 'accepted_risk', 'false_positive');

2. Materialized Views for Dashboard

CREATE MATERIALIZED VIEW dashboard_stats AS
SELECT
  COUNT(*) FILTER (WHERE status = 'open') AS open_vulnerabilities,
  COUNT(*) FILTER (WHERE severity = 'critical') AS critical_count,
  AVG(cvss_score) AS avg_cvss,
  COUNT(DISTINCT asset_id) AS affected_assets
FROM vulnerabilities
WHERE status = 'open';

-- Refresh every 5 minutes via Cronjob
REFRESH MATERIALIZED VIEW dashboard_stats;

3. Read-Replica for Reports

Primary DB (Write) → Streaming Replication → Replica DB (Read-only)
                                              └─> Dashboard Queries

Backup Strategy

# Daily Backup (every 03:00 AM)
pg_dump -Fc vulnmanager > /backups/vulnmanager_$(date +%Y%m%d).dump

# Activate Point-in-Time-Recovery
# postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'

Retention:

  • Daily backups: 7 days
  • Weekly backups: 4 weeks
  • Monthly backups: 12 months