Skip to main content

Overview

VulnTrack provides a complete vulnerability lifecycle management system that allows security teams to track vulnerabilities from discovery through remediation. The platform supports multi-tenant team workspaces with role-based access control and approval workflows.

Vulnerability Statuses

Each vulnerability progresses through defined states during its lifecycle:
Newly identified vulnerabilities start in the OPEN state. These require immediate attention and triaging by security analysts.

Severity Levels

VulnTrack uses industry-standard severity classifications:

CRITICAL

Requires immediate action. Critical vulnerabilities pose imminent risk to systems and data.

HIGH

High-priority issues that should be addressed within days. Significant security impact.

MEDIUM

Moderate risk vulnerabilities that should be remediated during regular maintenance cycles.

LOW

Low-impact issues that can be addressed as time permits.

Approval Workflow

VulnTrack includes a built-in approval system to maintain data quality in team environments:
Non-admin users who create vulnerabilities have their submissions marked as PENDING approval. Only admins can approve or reject these submissions.
// From schema.prisma
model Vulnerability {
  approvalStatus String @default("APPROVED") // PENDING, APPROVED, REJECTED
  // ...
}

Visibility Rules

  • Admins: See all vulnerabilities within their team workspace
  • Analysts/Viewers: See only APPROVED vulnerabilities + their own pending submissions
This prevents unapproved data from affecting team-wide reports and dashboards.

Creating Vulnerabilities

Vulnerabilities can be created manually or imported from CVE databases:
// From src/app/actions/vulnerabilities.ts:120
export async function createVulnerability(data: any) {
  // Automatic approval for admins
  const approvalStatus = user.role === 'ADMIN' ? 'APPROVED' : 'PENDING'
  
  // Prevent duplicates within team
  const existingVuln = await prisma.vulnerability.findFirst({
    where: { cveId: data.cveId, teamId: user.teamId }
  })
  
  if (existingVuln) {
    return { success: false, error: "This CVE has already been imported" }
  }
  
  // Auto-populate from NVD if CVE ID provided
  if (data.cveId) {
    const result = await importCve(data.cveId)
    // Merge CVE data with user input
  }
}

Assignment System

Only admins can assign vulnerabilities to team members. Assignments trigger automatic notifications via email and in-app alerts.
// From src/app/actions/vulnerabilities.ts:408
export async function assignVulnerability(
  vulnerabilityId: string, 
  assigneeId: string | null
) {
  // Verify assignee is in same team
  if (assignee.teamId !== vulnerability.teamId) {
    return { success: false, error: "Assignee must be in same team" }
  }
  
  // Create notification
  await prisma.notification.create({
    data: {
      userId: assigneeId,
      type: "ASSIGNMENT",
      title: "New Vulnerability Assigned",
      message: `You have been assigned to: ${vulnerability.title}`
    }
  })
  
  // Send email notification
  await sendEmail({
    to: assignee.email,
    subject: `New Assignment: ${vulnerability.title}`,
    html: getAssignmentEmail(vulnerability.title, vulnerabilityId)
  })
}

Vulnerability Schema

The complete data model for vulnerabilities:
model Vulnerability {
  id          String   @id @default(uuid())
  title       String
  description String
  status      String   // OPEN, IN_PROGRESS, RESOLVED, CLOSED
  severity    String   // CRITICAL, HIGH, MEDIUM, LOW
  
  userId      String
  user        User     @relation(fields: [userId], references: [id])
  
  teamId      String?
  team        Team?    @relation(fields: [teamId], references: [id])
  
  assignedToId String?
  assignedTo   User?    @relation("AssignedVulnerabilities")
  
  approvalStatus String @default("APPROVED")
  
  // Risk scoring
  dread       DreadScore?
  stride      StrideScore?
  cvssScore   Float?
  
  // CVE integration
  cveId             String?
  references        String? // JSON serialized
  affectedSystems   String? // JSON serialized
  
  // Asset tracking
  asset             String?
  mitigations       String? // JSON serialized
  impactAssessment  String? // JSON serialized
  
  // Audit fields
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  
  comments    Comment[]
}

Multi-Tenant Isolation

VulnTrack enforces strict team-level data isolation. Users can only access vulnerabilities within their assigned team workspace. Cross-tenant access is blocked at the database query level.
// From src/app/actions/vulnerabilities.ts:32
let whereClause: any = {
  teamId: teamId // Scope to team
}

if (user.role !== 'ADMIN') {
  // Non-admins see APPROVED items OR their own items
  whereClause = {
    teamId: teamId,
    OR: [
      { approvalStatus: "APPROVED" },
      { userId: session.user.id }
    ]
  }
}

User Roles

  • ADMIN: Full access to approve, assign, delete vulnerabilities
  • ANALYST: Can create vulnerabilities (requires approval), view approved items
  • VIEWER: Read-only access to approved vulnerabilities

Best Practices

  1. Triage Quickly: Set severity levels immediately upon discovery
  2. Use Assignments: Assign critical vulnerabilities to specific team members
  3. Track Progress: Update status as work progresses through remediation
  4. Document Evidence: Use comments to record findings and remediation steps
  5. Link CVEs: Always link to official CVE IDs when available for automatic enrichment

Build docs developers (and LLMs) love