UNPKG

ssvc

Version:

TypeScript implementation of SSVC (Stakeholder-Specific Vulnerability Categorization). A prioritization framework to triage CVE vulnerabilities as an alternative or compliment to CVSS

793 lines (665 loc) 19.8 kB
# Evidence Mapping & Audit Trail System This document describes the evidence mapping and audit trail system for SSVC (Stakeholder-Specific Vulnerability Categorization). This system enables forensic-grade tracking of vulnerability decisions with full chain of custody. ## Table of Contents - [Overview](#overview) - [Core Concepts](#core-concepts) - [Quick Start](#quick-start) - [Evidence Collection](#evidence-collection) - [Data Source Mapping](#data-source-mapping) - [Transform Rules](#transform-rules) - [Audit Trails](#audit-trails) - [Forensic Reports](#forensic-reports) - [Browser Compatibility](#browser-compatibility) - [API Reference](#api-reference) ## Overview The evidence mapping and audit trail system provides: - **Evidence Collection**: Cryptographic integrity with 15+ hash algorithms - **Data Source Abstraction**: Priority-based resolution from SQL, API, file, and manual sources - **Transform Rules**: Map raw data to methodology-specific values - **Audit Trails**: Complete timeline with chain of custody - **Forensic Reports**: Export for compliance and investigation - **Browser Compatibility**: Uses `crypto.randomUUID()` for universal support ## Core Concepts ### Evidence Structure Evidence includes verification methods, sources, checksums, and metadata: ```typescript interface DecisionPointEvidence { decisionPoint: string; value: string; verifications: VerificationMethod[]; } interface VerificationMethod { method: 'automated' | 'manual' | 'hybrid'; timestamp: number; source: string; result: string; evidence: EvidenceRecord; } ``` ### Data Sources Five types of data sources with priority-based resolution: 1. **SQL**: Database queries with table/column mapping 2. **Document**: NoSQL/MongoDB with JSONPath extraction 3. **API**: HTTP endpoints with custom headers 4. **File**: Local files with MIME type handling 5. **Manual**: Human-provided input ### Transform Rules Convert raw data to methodology values with source restrictions: ```typescript interface TransformRule { sourceValue: string | RegExp; targetValue: string; applicableToSources: string[]; applicableToMappings: string[]; } ``` ## Quick Start ### Basic Usage ```typescript import { createDecision, AuditableDecisionFactory } from 'ssvc'; // Create a basic decision const decision = createDecision('cisa', { exploitation: 'active', automatable: 'yes', technical_impact: 'total', mission_wellbeing: 'high' }); // Wrap for audit trail const auditableDecision = AuditableDecisionFactory.wrapDecision( decision, 'cisa', '1.0' ); // Evaluate with audit tracking const outcome = auditableDecision.evaluate(); console.log(`Decision: ${outcome.action} (${outcome.priority})`); console.log(`Evaluation ID: ${auditableDecision.evaluationId}`); ``` ### With Evidence Collection ```typescript // Attach evidence to decision points const evidence = { decisionPoint: 'exploitation', value: 'ACTIVE', verifications: [{ method: 'automated', timestamp: Date.now(), source: 'nvd-api', result: 'Active exploitation detected', evidence: { verified: true, evidenceId: crypto.randomUUID(), collectedAt: Date.now(), collectedBy: 'nvd-scanner', urls: ['https://nvd.nist.gov/vuln/detail/CVE-2024-1234'], notes: 'Multiple exploitation reports confirmed', checksums: [{ algorithm: 'sha256', signature: 'abc123def456789...', timestamp: Date.now(), contentId: crypto.randomUUID() }] } }] }; auditableDecision.attachEvidence('exploitation', evidence); ``` ## Evidence Collection ### Hash Algorithm Support The system supports 15+ cryptographic hash algorithms for evidence integrity: ```typescript type HashAlgorithm = | 'sha256' | 'sha512' | 'sha3-256' | 'sha3-512' | 'blake2b' | 'blake2s' | 'md5' | 'sha1' | 'ripemd160' | 'whirlpool' | 'tiger' | 'crc32' | 'adler32' | 'xxhash' | 'murmur3'; ``` ### Evidence Records Each piece of evidence includes comprehensive metadata: ```typescript interface EvidenceRecord { verified: boolean; evidenceId: string; collectedAt: number; collectedBy: string; urls?: string[]; notes?: string; contents?: any; checksums: ChecksumRecord[]; } interface ChecksumRecord { algorithm: HashAlgorithm; signature: string; timestamp: number; contentId: string; } ``` ### Multiple Verifications Decision points support multiple verification methods: ```typescript const multipleVerifications = { decisionPoint: 'technical_impact', value: 'TOTAL', verifications: [ { method: 'automated', source: 'cvss-calculator', result: 'CVSS Base Score: 9.8 (Critical)', evidence: { verified: true, evidenceId: crypto.randomUUID(), collectedAt: Date.now(), collectedBy: 'cvss-analyzer', contents: { baseScore: 9.8, vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H' }, checksums: [{ algorithm: 'sha256', signature: 'def789abc123...', timestamp: Date.now(), contentId: crypto.randomUUID() }] } }, { method: 'manual', source: 'security-analyst', result: 'Confirmed total system compromise possible', evidence: { verified: true, evidenceId: crypto.randomUUID(), collectedAt: Date.now(), collectedBy: 'john.analyst', notes: 'Manual verification by senior security analyst', checksums: [{ algorithm: 'sha512', signature: 'ghi456def789...', timestamp: Date.now(), contentId: crypto.randomUUID() }] } } ] }; ``` ## Data Source Mapping ### Configuration Configure data sources with priority-based resolution: ```typescript import { DataSourceFactory, MethodologyConfigBuilder } from 'ssvc'; const config = new MethodologyConfigBuilder('cisa', '1.0') .decisionPoint('exploitation') .required(true) .validValues(['none', 'poc', 'active']) .dataSource( DataSourceFactory.api( 'nvd-api', 'NVD Vulnerability Database', 1, // Highest priority { endpoint: 'https://services.nvd.nist.gov/rest/json/cves/2.0', method: 'GET', headers: { 'apiKey': process.env.NVD_API_KEY } }, 'Official NVD vulnerability data', ['application/json'] ) ) .dataSource( DataSourceFactory.manual( 'analyst-input', 'Security Analyst Assessment', 2, // Lower priority 'Manual assessment by security analyst', ['text/plain'] ) ) .build(); ``` ### Data Source Types #### SQL Sources ```typescript DataSourceFactory.sql( 'vuln-db', 'Vulnerability Database', 1, { table: 'vulnerabilities', primaryKey: 'cve_id', column: 'exploitation_status', query: 'SELECT exploitation_status FROM vulns WHERE cve_id = ?' }, 'Primary vulnerability database', ['application/json'] ) ``` #### Document Sources ```typescript DataSourceFactory.document( 'mongo-threats', 'Threat Intelligence DB', 2, { collection: 'threat_intel', documentKey: 'cve_id', jsonPath: '$.exploitation.status' }, 'MongoDB threat intelligence collection', ['application/json', 'application/bson'] ) ``` #### API Sources ```typescript DataSourceFactory.api( 'threat-feed', 'Commercial Threat Feed', 3, { endpoint: 'https://api.threatfeed.com/v1/cve/{cveId}', method: 'GET', headers: { 'Authorization': 'Bearer ${API_TOKEN}' } }, 'Commercial threat intelligence feed', ['application/json'] ) ``` #### File Sources ```typescript DataSourceFactory.file( 'local-intel', 'Local Intelligence Files', 4, { filePath: './intel/{cveId}.json', mimeType: 'application/json' }, 'Local intelligence file system', ['application/json', 'text/plain'] ) ``` ## Transform Rules ### Basic Transformation Transform raw data to methodology-specific values: ```typescript import { TransformEngine, CommonTransforms } from 'ssvc'; const engine = new TransformEngine(); const rules = [ { sourceValue: /^(active|exploitation|exploited)$/i, targetValue: 'ACTIVE', applicableToSources: ['nvd-api', 'threat-feed'], applicableToMappings: ['exploitation'] }, { sourceValue: /^(poc|proof.of.concept)$/i, targetValue: 'POC', applicableToSources: ['analyst-input'], applicableToMappings: ['exploitation'] } ]; const result = engine.transform( 'exploitation detected', rules, 'nvd-api', 'exploitation' ); console.log(result.value); // 'ACTIVE' ``` ### Common Transform Patterns Pre-built transforms for common scenarios: ```typescript // Boolean to Yes/No const booleanRules = CommonTransforms.booleanToYesNo(); const result = engine.transform('true', booleanRules, 'manual', 'automatable'); console.log(result.value); // 'YES' // Severity level normalization const severityRules = CommonTransforms.severityLevels(); const severity = engine.transform('high', severityRules, 'cvss', 'impact'); console.log(severity.value); // 'HIGH' // CVSS score to impact mapping const cvssRules = CommonTransforms.cvssToImpact(); const impact = engine.transform('9.8', cvssRules, 'cvss-calc', 'technical_impact'); console.log(impact.value); // 'TOTAL' ``` ### Source and Mapping Restrictions Rules can be restricted to specific sources and mappings: ```typescript const restrictedRules = [ { sourceValue: 'confirmed', targetValue: 'ACTIVE', applicableToSources: ['nvd-api'], // Only for NVD API applicableToMappings: ['exploitation'] // Only for exploitation mapping }, { sourceValue: 'confirmed', targetValue: 'HIGH', applicableToSources: ['analyst-input'], // Only for analyst input applicableToMappings: ['mission_wellbeing'] // Only for mission impact } ]; ``` ## Audit Trails ### Timeline Tracking Every action is recorded in the audit timeline: ```typescript const timeline = auditableDecision.getTimeline(); console.log(`Timeline entries: ${timeline.length}`); timeline.forEach(entry => { console.log(`${new Date(entry.timestamp).toISOString()}: ${entry.action}`); console.log(` Details: ${entry.details}`); console.log(` Duration: ${entry.duration}ms`); }); ``` ### Audit Entries Complete audit records with checksums: ```typescript const auditEntry = auditableDecision.getAuditEntry(); console.log(`Audit ID: ${auditEntry.auditId}`); console.log(`Methodology: ${auditEntry.methodology} v${auditEntry.version}`); console.log(`Checksum: ${auditEntry.checksum}`); console.log(`Evidence Count: ${Object.keys(auditEntry.evidence).length}`); console.log(`Created: ${new Date(auditEntry.timestamp).toISOString()}`); ``` ## Forensic Reports ### Generating Reports Create comprehensive forensic reports: ```typescript const forensicReport = auditableDecision.generateForensicReport(); console.log(`Report ID: ${forensicReport.reportId}`); console.log(`Generated: ${new Date(forensicReport.timestamp)}`); console.log(`Duration: ${forensicReport.totalDuration}ms`); console.log(`Decision: ${forensicReport.outcome.action}`); console.log(`Priority: ${forensicReport.outcome.priority}`); ``` ### Report Structure Forensic reports include: - **Report Metadata**: ID, timestamp, duration - **Decision Outcome**: Final action and priority - **Decision Path**: Complete evaluation steps - **Evidence Summary**: All collected evidence - **Data Sources**: Sources used and their priorities - **Chain of Custody**: Complete timeline - **Checksums**: Integrity verification ### Export Formats Export reports in multiple formats: ```typescript // JSON export (default) const jsonReport = JSON.stringify(forensicReport, null, 2); // Custom processing for other formats const reportData = { reportId: forensicReport.reportId, timestamp: forensicReport.timestamp, outcome: forensicReport.outcome, evidence: forensicReport.evidence, decisionPath: forensicReport.decisionPath }; // Generate CSV summary const csvReport = generateCSVSummary(reportData); // Generate CSV summary const csvReport = generateCSVReport(reportData); ``` ## Browser Compatibility ### UUID Generation The system uses browser-compatible `crypto.randomUUID()`: ```typescript // Browser-compatible UUID generation const evaluationId = crypto.randomUUID(); const evidenceId = crypto.randomUUID(); const contentId = crypto.randomUUID(); // Example evidence with browser-compatible UUIDs const evidence = { evidenceId: crypto.randomUUID(), collectedAt: Date.now(), checksums: [{ algorithm: 'sha256', contentId: crypto.randomUUID(), signature: 'abc123def456...', timestamp: Date.now() }] }; ``` ### Web Crypto API Hash calculations use the Web Crypto API when available: ```typescript // Browser-compatible hash calculation async function calculateHash(data: string): Promise<string> { const encoder = new TextEncoder(); const dataBuffer = encoder.encode(data); const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); return Array.from(new Uint8Array(hashBuffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } // Usage in evidence collection const signature = await calculateHash(JSON.stringify(evidenceData)); ``` ### Node.js Fallbacks In Node.js environments, fallbacks are provided: ```typescript // Node.js crypto module fallback import { randomUUID, createHash } from 'crypto'; function generateUUID(): string { // Use Node.js crypto in server environments if (typeof window === 'undefined') { return randomUUID(); } // Use browser crypto in client environments return crypto.randomUUID(); } function calculateHashSync(data: string): string { if (typeof window === 'undefined') { return createHash('sha256').update(data).digest('hex'); } // Use async Web Crypto API in browsers throw new Error('Use calculateHash() async method in browser'); } ``` ## Complete Example Here's a comprehensive example showing the full evidence mapping and audit trail workflow: ```typescript import { createDecision, AuditableDecisionFactory, TransformEngine, CommonTransforms, DataSourceFactory } from 'ssvc'; async function completeEvidenceWorkflow() { // 1. Create base decision const decision = createDecision('cisa', { exploitation: 'active', automatable: 'yes', technical_impact: 'total', mission_wellbeing: 'high' }); // 2. Wrap for audit trail const auditableDecision = AuditableDecisionFactory.wrapDecision( decision, 'cisa', '1.0' ); console.log(`Evaluation ID: ${auditableDecision.evaluationId}`); // 3. Configure transform rules const engine = new TransformEngine(); const rules = [ { sourceValue: /^(active|exploited)$/i, targetValue: 'ACTIVE', applicableToSources: ['nvd-api'], applicableToMappings: ['exploitation'] } ]; // 4. Transform raw data const transformResult = engine.transform( 'exploited', rules, 'nvd-api', 'exploitation' ); console.log(`Transformed: ${transformResult.value}`); // 5. Attach evidence const evidence = { decisionPoint: 'exploitation', value: 'ACTIVE', verifications: [{ method: 'automated', timestamp: Date.now(), source: 'nvd-api', result: 'Active exploitation confirmed in NVD database', evidence: { verified: true, evidenceId: crypto.randomUUID(), collectedAt: Date.now(), collectedBy: 'nvd-scanner-v2.1', urls: ['https://nvd.nist.gov/vuln/detail/CVE-2024-1234'], notes: 'Confirmed through automated NVD scan', contents: { cveId: 'CVE-2024-1234', exploitabilitySubScore: 3.9, impactSubScore: 5.9, lastModifiedDate: '2024-01-15T10:30:00.000Z' }, checksums: [{ algorithm: 'sha256', signature: 'a1b2c3d4e5f6789012345678901234567890123456789012345678901234567890', timestamp: Date.now(), contentId: crypto.randomUUID() }] } }] }; auditableDecision.attachEvidence('exploitation', evidence); // 6. Evaluate with full audit const outcome = auditableDecision.evaluate(); console.log(`Decision: ${outcome.action} (Priority: ${outcome.priority})`); // 7. Generate forensic report const forensicReport = auditableDecision.generateForensicReport(); console.log(`Forensic Report ID: ${forensicReport.reportId}`); console.log(`Total Duration: ${forensicReport.totalDuration}ms`); // 8. Export audit trail const timeline = auditableDecision.getTimeline(); console.log(`Timeline entries: ${timeline.length}`); const auditEntry = auditableDecision.getAuditEntry(); console.log(`Audit checksum: ${auditEntry.checksum}`); return { outcome, forensicReport, timeline, auditEntry }; } // Run the complete workflow completeEvidenceWorkflow() .then(result => { console.log('Evidence mapping and audit trail complete!'); console.log('Final decision:', result.outcome); }) .catch(error => { console.error('Workflow failed:', error); }); ``` ## API Reference ### Core Classes #### AuditableDecisionWrapper ```typescript class AuditableDecisionWrapper implements AuditableDecision { evaluationId: string; evaluate(): SSVCOutcome; attachEvidence(decisionPoint: string, evidence: DecisionPointEvidence): void; mapDataSource(decisionPoint: string, dataSource: DataSource): void; getAuditEntry(): AuditEntry; generateForensicReport(): ForensicReport; getEvidence(): Record<string, DecisionPointEvidence>; getDataSources(): Record<string, DataSource>; getTimeline(): TimelineEntry[]; getWrappedDecision(): SSVCDecision; } ``` #### AuditableDecisionFactory ```typescript class AuditableDecisionFactory { static wrapDecision( decision: SSVCDecision, methodology: string, version: string ): AuditableDecision; } ``` #### TransformEngine ```typescript class TransformEngine { transform( value: any, rules: TransformRule[], sourceId: string, mappingId: string ): { value: string; applied: TransformRule | null }; validate(value: string, validValues: string[]): boolean; getApplicableRules( rules: TransformRule[], sourceId: string, mappingId: string ): TransformRule[]; } ``` #### DataSourceFactory ```typescript class DataSourceFactory { static sql( sourceId: string, name: string, priority: number, config: SQLConfig, description: string, mimeTypes: string[] ): DataSource; static document( sourceId: string, name: string, priority: number, config: DocumentConfig, description: string, mimeTypes: string[] ): DataSource; static api( sourceId: string, name: string, priority: number, config: APIConfig, description: string, mimeTypes: string[] ): DataSource; static file( sourceId: string, name: string, priority: number, config: FileConfig, description: string, mimeTypes: string[] ): DataSource; static manual( sourceId: string, name: string, priority: number, description: string, mimeTypes: string[] ): DataSource; } ``` ### Helper Functions #### createDecision ```typescript function createDecision( methodology: string, options: Record<string, any> ): Decision; ``` #### CommonTransforms ```typescript class CommonTransforms { static booleanToYesNo(): TransformRule[]; static severityLevels(): TransformRule[]; static cvssToImpact(): TransformRule[]; static confidenceToReliability(): TransformRule[]; } ``` For complete type definitions, see the TypeScript files in the `src/` directory.