MCPInstall

forensic-data-engineer

Expert in data forensics, anomaly detection, audit trail analysis, fraud detection, and breach investigation

Installs
178
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/daffy0208/ai-dev-standards --skill forensic-data-engineer
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads forensic-data-engineer automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Forensic Data Engineer Skill

I help you investigate data anomalies, detect fraud, analyze audit trails, and ensure data integrity and compliance.

What I Do

Forensic Analysis:

  • Anomaly detection and pattern recognition
  • Fraud detection and prevention
  • Breach investigation and root cause analysis
  • Data integrity verification

Audit & Compliance:

  • Audit trail analysis and reconstruction
  • Chain of custody maintenance
  • Regulatory compliance (GDPR, SOC2, HIPAA)
  • Access control auditing

Data Recovery:

  • Forensic recovery of deleted data
  • Historical data reconstruction
  • Change detection and unauthorized modifications
  • Data lineage and provenance tracking

Forensic Patterns

Pattern 1: Audit Trail Implementation

Use case: Track all data changes for compliance and investigation

// lib/forensics/audit-trail.ts

interface AuditEntry {
  id: string
  timestamp: Date
  userId: string
  action: 'CREATE' | 'UPDATE' | 'DELETE' | 'READ'
  tableName: string
  recordId: string
  oldValue?: any
  newValue?: any
  ipAddress: string
  userAgent: string
  sessionId: string
}

export async function createAuditLog(entry: Omit<AuditEntry, 'id' | 'timestamp'>) {
  return await db.auditLog.create({
    data: {
      ...entry,
      timestamp: new Date()
    }
  })
}

// Middleware for automatic audit logging
export function withAudit<T extends (...args: any[]) => Promise<any>>(
  operation: T,
  metadata: { tableName: string; action: AuditEntry['action'] }
): T {
  return (async (...args: any[]) => {
    const startTime = Date.now()
    const { tableName, action } = metadata

    try {
      // Capture before state for UPDATE/DELETE
      let oldValue
      if (action === 'UPDATE' || action === 'DELETE') {
        oldValue = await captureCurrentState(tableName, args[0])
      }

      // Execute operation
      const result = await operation(...args)

      // Capture after state
      const newValue = action !== 'DELETE' ? result : null

      // Log audit entry
      await createAuditLog({
        userId: getCurrentUser().id,
        action,
        tableName,
        recordId: args[0],
        oldValue,
        newValue,
        ipAddress: getClientIp(),
        userAgent: getClientUserAgent(),
        sessionId: getSessionId()
      })

      return result
    } catch (error) {
      // Log failed attempt
      await createAuditLog({
        userId: getCurrentUser().id,
        action,
        tableName,
        recordId: args[0],
        ipAddress: getClientIp(),
        userAgent: getClientUserAgent(),
        sessionId: getSessionId()
      })
      throw error
    }
  }) as T
}

// Usage
const updateUser = withAudit(
  async (userId: string, data: any) => {
    return await db.user.update({
      where: { id: userId },
      data
    })
  },
  { tableName: 'users', action: 'UPDATE' }
)

Pattern 2: Anomaly Detection

Use case: Identify suspicious patterns in transaction data

// lib/forensics/anomaly-detection.ts

interface Transaction {
  id: string
  userId: string
  amount: number
  timestamp: Date
  location: string
  deviceId: string
}

export async function detectTransactionAnomalies(transaction: Transaction) {
  const anomalies: string[] = []

  // Check 1: Unusual amount (statistical outlier)
  const userStats = await getUserTransactionStats(transaction.userId)
  const zScore = (transaction.amount - userStats.mean) / userStats.stdDev

  if (Math.abs(zScore) > 3) {
    anomalies.push(`Unusual amount: ${transaction.amount} (z-score: ${zScore.toFixed(2)})`)
  }

  // Check 2: Rapid succession (velocity check)
  const recentTransactions = await db.transactions.findMany({
    where: {
      userId: transaction.userId,
      timestamp: {
        gte: new Date(Date.now() - 5 * 60 * 1000) // Last 5 minutes
      }
    }
  })

  if (recentTransactions.length > 5) {
    anomalies.push(`High velocity: ${recentTransactions.length} transactions in 5 minutes`)
  }

  // Check 3: Impossible travel (location mismatch)
  const lastTransaction = await db.transactions.findFirst({
    where: { userId: transaction.userId },
    orderBy: { timestamp: 'desc' }
  })

  if (lastTransaction) {
    const timeDiff = transaction.timestamp.getTime() - lastTransaction.timestamp.getTime()
    const distance = calculateDistance(lastTransaction.location, transaction.location)
    const maxPossibleSpeed = 900 // km/h (commercial flight)
    const requiredSpeed = distance / (timeDiff / 3600000) // km/h

    if (requiredSpeed > maxPossibleSpeed) {
      anomalies.push(
        `Impossible travel: ${distance}km in ${timeDiff / 60000} minutes (${requiredSpeed.toFixed(0)} km/h required)`
      )
    }
  }

  // Check 4: New device from new location
  const deviceHistory = await db.deviceHistory.findFirst({
    where: {
      userId: transaction.userId,
      deviceId: transaction.deviceId
    }
  })

  if (!deviceHistory) {
    anomalies.push(`New device: ${transaction.deviceId}`)
  }

  // Check 5: Time-of-day anomaly
  const hour = transaction.timestamp.getHours()
  const userActivity = await getUserActivityPattern(transaction.userId)

  if (userActivity.typicalHours.indexOf(hour) === -1) {
    anomalies.push(`Unusual time: ${hour}:00 (typical: ${userActivity.typicalHours.join(', ')})`)
  }

  return {
    isAnomalous: anomalies.length > 0,
    anomalies,
    riskScore: calculateRiskScore(anomalies)
  }
}

async function getUserTransactionStats(userId: string) {
  const result = await db.$queryRaw<[{ mean: number; stddev: number }]>`
    SELECT
      AVG(amount)::float as mean,
      STDDEV(amount)::float as stddev
    FROM transactions
    WHERE user_id = ${userId}
    AND timestamp > NOW() - INTERVAL '90 days'
  `

  return {
    mean: result[0]?.mean || 0,
    stdDev: result[0]?.stddev || 1
  }
}

function calculateRiskScore(anomalies: string[]): number {
  // Weight different anomaly types
  const weights = {
    'Unusual amount': 2,
    'High velocity': 3,
    'Impossible travel': 5,
    'New device': 2,
    'Unusual time': 1
  }

  return anomalies.reduce((score, anomaly) => {
    const type = anomaly.split(':')[0]
    return score + (weights[type] || 1)
  }, 0)
}

Pattern 3: Data Lineage Tracking

Use case: Track data provenance and transformation history

// lib/forensics/lineage.ts

interface LineageNode {
  id: string
  datasetName: string
  recordId: string
  operation: string
  timestamp: Date
  sourceNodes: string[]
  metadata: Record<string, any>
}

export class DataLineageTracker {
  async trackTransformation(config: {
    output: { dataset: string; recordId: string }
    inputs: Array<{ dataset: string; recordId: string }>
    operation: string
    metadata?: Record<string, any>
  }) {
    const node: LineageNode = {
      id: generateId(),
      datasetName: config.output.dataset,
      recordId: config.output.recordId,
      operation: config.operation,
      timestamp: new Date(),
      sourceNodes: config.inputs.map(i => `${i.dataset}:${i.recordId}`),
      metadata: config.metadata || {}
    }

    await db.dataLineage.create({ data: node })
    return node
  }

  async getLineage(dataset: string, recordId: string): Promise<LineageNode[]> {
    const visited = new Set<string>()
    const lineage: LineageNode[] = []

    async function traverse(ds: string, rid: string) {
      const key = `${ds}:${rid}`
      if (visited.has(key)) return

      visited.add(key)

      const node = await db.dataLineage.findFirst({
        where: { datasetName: ds, recordId: rid }
      })

      if (!node) return

      lineage.push(node)

      // Recursively traverse source nodes
      for (const sourceKey of node.sourceNodes) {
        const [sourceDs, sourceRid] = sourceKey.split(':')
        await traverse(sourceDs, sourceRid)
      }
    }

    await traverse(dataset, recordId)
    return lineage
  }

  async visualizeLineage(dataset: string, recordId: string): Promise<string> {
    const lineage = await this.getLineage(dataset, recordId)

    // Generate Mermaid diagram
    let diagram = 'graph TD\n'

    for (const node of lineage) {
      const nodeId = `${node.datasetName}_${node.recordId}`
      diagram += `  ${nodeId}["${node.datasetName}:${node.recordId}<br/>${node.operation}"]\\n`

      for (const source of node.sourceNodes) {
        const [ds, rid] = source.split(':')
        const sourceId = `${ds}_${rid}`
        diagram += `  ${sourceId} --> ${nodeId}\n`
      }
    }

    return diagram
  }
}

// Usage example
const tracker = new DataLineageTracker()

// Track ETL transformation
await tracker.trackTransformation({
  output: { dataset: 'customers_enriched', recordId: 'c123' },
  inputs: [
    { dataset: 'customers_raw', recordId: 'c123' },
    { dataset: 'geolocation', recordId: 'geo456' }
  ],
  operation: 'enrichWithGeodata',
  metadata: {
    pipelineName: 'customer-enrichment',
    version: '1.0.0'
  }
})

Pattern 4: Fraud Detection Patterns

Use case: Identify fraudulent activities using pattern matching

// lib/forensics/fraud-detection.ts

interface FraudIndicator {
  type: string
  severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
  description: string
  evidence: any
}

export async function detectFraud(userId: string): Promise<FraudIndicator[]> {
  const indicators: FraudIndicator[] = []

  // Pattern 1: Account takeover indicators
  const recentPasswordChanges = await db.auditLog.count({
    where: {
      userId,
      action: 'UPDATE',
      tableName: 'users',
      timestamp: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000) }
    }
  })

  if (recentPasswordChanges > 3) {
    indicators.push({
      type: 'ACCOUNT_TAKEOVER',
      severity: 'HIGH',
      description: 'Multiple password changes in 24 hours',
      evidence: { count: recentPasswordChanges }
    })
  }

  // Pattern 2: Structuring (smurfing)
  const recentSmallTransactions = await db.transactions.findMany({
    where: {
      userId,
      amount: { lt: 9999 }, // Just under reporting threshold
      timestamp: { gte: new Date(Date.now() - 24 * 60 * 60 * 1000) }
    }
  })

  if (recentSmallTransactions.length > 5) {
    const total = recentSmallTransactions.reduce((sum, t) => sum + t.amount, 0)
    indicators.push({
      type: 'STRUCTURING',
      severity: 'CRITICAL',
      description: 'Multiple transactions just under reporting threshold',
      evidence: {
        count: recentSmallTransactions.length,
        total,
        averageAmount: total / recentSmallTransactions.length
      }
    })
  }

  // Pattern 3: Unusual beneficiary patterns
  const beneficiaries = await db.transactions.groupBy({
    by: ['beneficiaryId'],
    where: {
      userId,
      timestamp: { gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
    },
    _count: true
  })

  const newBeneficiaries = beneficiaries.filter(async b => {
    const history = await db.transactions.count({
      where: {
        userId,
        beneficiaryId: b.beneficiaryId,
        timestamp: { lt: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }
      }
    })
    return history === 0
  })

  if (newBeneficiaries.length > 3) {
    indicators.push({
      type: 'UNUSUAL_BENEFICIARIES',
      severity: 'MEDIUM',
      description: 'Multiple new beneficiaries in short period',
      evidence: { count: newBeneficiaries.length }
    })
  }

  // Pattern 4: Round-tripping
  const circularTransfers = await detectCircularTransfers(userId)
  if (circularTransfers.length > 0) {
    indicators.push({
      type: 'ROUND_TRIPPING',
      severity: 'CRITICAL',
      description: 'Circular money flow detected',
      evidence: { chains: circularTransfers }
    })
  }

  return indicators
}

async function detectCircularTransfers(userId: string): Promise<string[][]> {
  // Find chains where money flows back to original sender
  const result = await db.$queryRaw<Array<{path: string[]}}>`
    WITH RECURSIVE transfer_chain AS (
      SELECT
        sender_id,
        recipient_id,
        ARRAY[sender_id, recipient_id] as path,
        1 as depth
      FROM transfers
      WHERE sender_id = ${userId}
        AND timestamp > NOW() - INTERVAL '30 days'

      UNION ALL

      SELECT
        tc.sender_id,
        t.recipient_id,
        tc.path || t.recipient_id,
        tc.depth + 1
      FROM transfer_chain tc
      JOIN transfers t ON tc.recipient_id = t.sender_id
      WHERE tc.depth < 5
        AND NOT t.recipient_id = ANY(tc.path)
    )
    SELECT path
    FROM transfer_chain
    WHERE recipient_id = sender_id
  `

  return result.map(r => r.path)
}

Pattern 5: Breach Investigation

Use case: Investigate and analyze data breaches

// lib/forensics/breach-investigation.ts

interface BreachReport {
  id: string
  detectedAt: Date
  affectedRecords: number
  compromisedFields: string[]
  attackVector: string
  timeline: BreachEvent[]
  impactAssessment: ImpactAssessment
}

interface BreachEvent {
  timestamp: Date
  event: string
  details: any
}

export class BreachInvestigator {
  async investigateBreach(suspiciousActivity: {
    startTime: Date
    endTime: Date
    affectedTable: string
  }): Promise<BreachReport> {
    const timeline: BreachEvent[] = []

    // 1. Identify initial access
    const suspiciousLogins = await db.auditLog.findMany({
      where: {
        action: 'READ',
        tableName: 'users',
        timestamp: {
          gte: suspiciousActivity.startTime,
          lte: suspiciousActivity.endTime
        }
      },
      orderBy: { timestamp: 'asc' }
    })

    timeline.push({
      timestamp: suspiciousLogins[0]?.timestamp || suspiciousActivity.startTime,
      event: 'INITIAL_ACCESS',
      details: suspiciousLogins[0]
    })

    // 2. Identify privilege escalation
    const privilegeChanges = await db.auditLog.findMany({
      where: {
        action: 'UPDATE',
        tableName: 'users',
        timestamp: {
          gte: suspiciousActivity.startTime,
          lte: suspiciousActivity.endTime
        }
      }
    })

    for (const change of privilegeChanges) {
      if (change.newValue?.role !== change.oldValue?.role) {
        timeline.push({
          timestamp: change.timestamp,
          event: 'PRIVILEGE_ESCALATION',
          details: change
        })
      }
    }

    // 3. Identify data exfiltration
    const dataAccess = await db.auditLog.findMany({
      where: {
        tableName: suspiciousActivity.affectedTable,
        action: 'READ',
        timestamp: {
          gte: suspiciousActivity.startTime,
          lte: suspiciousActivity.endTime
        }
      }
    })

    const massExfiltration = this.detectMassExfiltration(dataAccess)
    if (massExfiltration) {
      timeline.push({
        timestamp: massExfiltration.startTime,
        event: 'DATA_EXFILTRATION',
        details: massExfiltration
      })
    }

    // 4. Identify affected records
    const affectedRecordIds = new Set(dataAccess.map(a => a.recordId))
    const affectedRecords = affectedRecordIds.size

    // 5. Determine compromised fields
    const compromisedFields = this.identifyCompromisedFields(dataAccess)

    // 6. Determine attack vector
    const attackVector = await this.determineAttackVector(timeline)

    // 7. Impact assessment
    const impactAssessment = await this.assessImpact({
      affectedRecords,
      compromisedFields,
      affectedTable: suspiciousActivity.affectedTable
    })

    return {
      id: generateId(),
      detectedAt: new Date(),
      affectedRecords,
      compromisedFields,
      attackVector,
      timeline,
      impactAssessment
    }
  }

  private detectMassExfiltration(accesses: any[]) {
    // Group by user and time window
    const byUser = groupBy(accesses, 'userId')

    for (const [userId, userAccesses] of Object.entries(byUser)) {
      const sorted = userAccesses.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())

      // Check for rapid sequential access
      if (sorted.length > 100) {
        const duration =
          sorted[sorted.length - 1].timestamp.getTime() - sorted[0].timestamp.getTime()

        if (duration < 60000) {
          // Less than 1 minute
          return {
            userId,
            recordCount: sorted.length,
            startTime: sorted[0].timestamp,
            endTime: sorted[sorted.length - 1].timestamp,
            duration
          }
        }
      }
    }

    return null
  }

  private identifyCompromisedFields(accesses: any[]): string[] {
    const fields = new Set<string>()

    for (const access of accesses) {
      if (access.metadata?.fields) {
        access.metadata.fields.forEach(f => fields.add(f))
      }
    }

    return Array.from(fields)
  }

  private async determineAttackVector(timeline: BreachEvent[]): Promise<string> {
    // Analyze timeline to determine likely attack vector
    const events = timeline.map(e => e.event)

    if (events.includes('SQL_INJECTION')) {
      return 'SQL Injection'
    } else if (events.includes('PRIVILEGE_ESCALATION')) {
      return 'Privilege Escalation'
    } else if (events.includes('BRUTE_FORCE')) {
      return 'Brute Force Attack'
    } else {
      return 'Unknown - Requires Manual Investigation'
    }
  }

  private async assessImpact(config: {
    affectedRecords: number
    compromisedFields: string[]
    affectedTable: string
  }): Promise<ImpactAssessment> {
    const sensitiveFields = ['ssn', 'password', 'creditCard', 'email', 'phone']
    const hasSensitiveData = config.compromisedFields.some(f => sensitiveFields.includes(f))

    return {
      severity: hasSensitiveData ? 'CRITICAL' : 'HIGH',
      affectedUsers: config.affectedRecords,
      requiresNotification: true,
      regulatoryImplications: hasSensitiveData ? ['GDPR', 'CCPA', 'State Breach Laws'] : [],
      estimatedCost: this.estimateBreachCost(config.affectedRecords)
    }
  }

  private estimateBreachCost(recordCount: number): number {
    // Based on IBM Cost of Data Breach Report
    const costPerRecord = 150 // USD
    return recordCount * costPerRecord
  }
}

interface ImpactAssessment {
  severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
  affectedUsers: number
  requiresNotification: boolean
  regulatoryImplications: string[]
  estimatedCost: number
}

Pattern 6: Change Detection

Use case: Detect unauthorized database modifications

// lib/forensics/change-detection.ts

export class ChangeDetector {
  async detectUnauthorizedChanges(tableName: string, timeWindow: number = 24) {
    const changes = await db.auditLog.findMany({
      where: {
        tableName,
        action: { in: ['UPDATE', 'DELETE'] },
        timestamp: {
          gte: new Date(Date.now() - timeWindow * 60 * 60 * 1000)
        }
      },
      include: {
        user: true
      }
    })

    const suspicious: any[] = []

    for (const change of changes) {
      // Check 1: Change outside business hours
      const hour = change.timestamp.getHours()
      if (hour < 6 || hour > 22) {
        suspicious.push({
          ...change,
          reason: 'OUTSIDE_BUSINESS_HOURS',
          severity: 'MEDIUM'
        })
      }

      // Check 2: Bulk operations
      const recentChanges = changes.filter(
        c =>
          c.userId === change.userId &&
          Math.abs(c.timestamp.getTime() - change.timestamp.getTime()) < 60000
      )

      if (recentChanges.length > 50) {
        suspicious.push({
          ...change,
          reason: 'BULK_OPERATION',
          severity: 'HIGH',
          affectedRecords: recentChanges.length
        })
      }

      // Check 3: Privilege mismatch
      if (change.user.role !== 'ADMIN' && tableName === 'users') {
        suspicious.push({
          ...change,
          reason: 'INSUFFICIENT_PRIVILEGES',
          severity: 'CRITICAL'
        })
      }

      // Check 4: Unusual modifications
      if (change.action === 'DELETE' && !change.metadata?.deletionReason) {
        suspicious.push({
          ...change,
          reason: 'UNDOCUMENTED_DELETION',
          severity: 'HIGH'
        })
      }
    }

    return suspicious
  }

  async generateChangeReport(startDate: Date, endDate: Date) {
    const changes = await db.auditLog.findMany({
      where: {
        timestamp: { gte: startDate, lte: endDate }
      }
    })

    // Group by table and action
    const summary = changes.reduce(
      (acc, change) => {
        const key = `${change.tableName}:${change.action}`
        acc[key] = (acc[key] || 0) + 1
        return acc
      },
      {} as Record<string, number>
    )

    // Group by user
    const byUser = changes.reduce(
      (acc, change) => {
        acc[change.userId] = (acc[change.userId] || 0) + 1
        return acc
      },
      {} as Record<string, number>
    )

    return {
      totalChanges: changes.length,
      byTableAndAction: summary,
      byUser,
      timeRange: { start: startDate, end: endDate }
    }
  }
}

Pattern 7: Forensic Recovery

Use case: Recover deleted or modified data

// lib/forensics/recovery.ts

export class ForensicRecovery {
  async recoverDeletedRecord(tableName: string, recordId: string) {
    // Find deletion event
    const deletion = await db.auditLog.findFirst({
      where: {
        tableName,
        recordId,
        action: 'DELETE'
      },
      orderBy: { timestamp: 'desc' }
    })

    if (!deletion || !deletion.oldValue) {
      throw new Error('No recovery data available')
    }

    // Verify record is still deleted
    const exists = await db[tableName].findUnique({
      where: { id: recordId }
    })

    if (exists) {
      throw new Error('Record already exists')
    }

    // Restore from audit log
    const restored = await db[tableName].create({
      data: {
        ...deletion.oldValue,
        restoredAt: new Date(),
        restoredBy: getCurrentUser().id,
        restoredFrom: deletion.id
      }
    })

    // Log recovery
    await createAuditLog({
      userId: getCurrentUser().id,
      action: 'CREATE',
      tableName,
      recordId,
      newValue: restored,
      metadata: {
        recovery: true,
        originalDeletionId: deletion.id
      }
    })

    return restored
  }

  async reconstructHistory(tableName: string, recordId: string) {
    const history = await db.auditLog.findMany({
      where: { tableName, recordId },
      orderBy: { timestamp: 'asc' }
    })

    const timeline = []
    let currentState = null

    for (const event of history) {
      switch (event.action) {
        case 'CREATE':
          currentState = event.newValue
          break
        case 'UPDATE':
          currentState = { ...currentState, ...event.newValue }
          break
        case 'DELETE':
          currentState = null
          break
      }

      timeline.push({
        timestamp: event.timestamp,
        action: event.action,
        changes:
          event.action === 'UPDATE' ? this.diffObjects(event.oldValue, event.newValue) : null,
        state: structuredClone(currentState)
      })
    }

    return timeline
  }

  private diffObjects(old: any, new_: any): any {
    const changes = {}

    for (const key of Object.keys(new_)) {
      if (JSON.stringify(old[key]) !== JSON.stringify(new_[key])) {
        changes[key] = { old: old[key], new: new_[key] }
      }
    }

    return changes
  }

  async rollbackToTimestamp(tableName: string, recordId: string, timestamp: Date) {
    const timeline = await this.reconstructHistory(tableName, recordId)

    // Find state at target timestamp
    const targetState = timeline.filter(t => t.timestamp <= timestamp).pop()?.state

    if (!targetState) {
      throw new Error('No state found at target timestamp')
    }

    // Update to target state
    await db[tableName].update({
      where: { id: recordId },
      data: {
        ...targetState,
        rolledBackAt: new Date(),
        rolledBackBy: getCurrentUser().id,
        rolledBackTo: timestamp
      }
    })

    return targetState
  }
}

Compliance Patterns

Pattern 8: GDPR Compliance Tools

// lib/forensics/gdpr-compliance.ts

export class GDPRCompliance {
  async generateDataPortabilityReport(userId: string) {
    // Collect all user data across tables
    const userData = {
      personal: await db.users.findUnique({ where: { id: userId } }),
      orders: await db.orders.findMany({ where: { userId } }),
      preferences: await db.userPreferences.findFirst({ where: { userId } }),
      activityLog: await db.activityLog.findMany({
        where: { userId },
        orderBy: { timestamp: 'desc' },
        take: 1000
      })
    }

    return {
      exportDate: new Date(),
      userId,
      data: userData,
      format: 'JSON',
      rightExercised: 'DATA_PORTABILITY'
    }
  }

  async rightToBeForgotten(userId: string) {
    // Log request
    await db.gdprRequests.create({
      data: {
        userId,
        requestType: 'ERASURE',
        requestedAt: new Date(),
        status: 'PROCESSING'
      }
    })

    // Anonymize instead of delete for audit compliance
    await db.users.update({
      where: { id: userId },
      data: {
        email: `deleted-${userId}@example.com`,
        name: 'Deleted User',
        phone: null,
        address: null,
        deletedAt: new Date()
      }
    })

    // Remove from third-party services
    await this.removeFromThirdParties(userId)

    // Update request status
    await db.gdprRequests.update({
      where: { userId },
      data: {
        status: 'COMPLETED',
        completedAt: new Date()
      }
    })
  }

  async generateProcessingRegister() {
    // GDPR Article 30 - Record of Processing Activities
    return {
      controller: {
        name: 'Your Company Ltd',
        contact: 'dpo@company.com',
        representative: 'Data Protection Officer'
      },
      purposes: [
        'Service delivery',
        'Customer support',
        'Marketing (with consent)',
        'Legal compliance'
      ],
      dataCategories: ['Identity data', 'Contact data', 'Financial data', 'Usage data'],
      recipients: ['Payment processors', 'Email service providers', 'Analytics providers'],
      retentionPeriods: {
        activeUsers: '5 years after last activity',
        deletedUsers: '1 year (anonymized)',
        transactions: '7 years (legal requirement)'
      },
      securityMeasures: [
        'Encryption at rest and in transit',
        'Access control with MFA',
        'Regular security audits',
        'Audit logging'
      ]
    }
  }
}

Monitoring and Alerting

Pattern 9: Real-Time Threat Detection

// lib/forensics/threat-detection.ts

export class ThreatDetector {
  async monitorForThreats() {
    // Set up real-time monitoring
    const threats = []

    // Monitor 1: SQL Injection attempts
    const sqlInjectionPatterns = [
      /['";].*(--)|(;).*--/,
      /\bUNION\b.*\bSELECT\b/i,
      /\bOR\b.*['"].*=.*['"]/i
    ]

    const recentQueries = await this.getRecentQueries()
    for (const query of recentQueries) {
      if (sqlInjectionPatterns.some(p => p.test(query.sql))) {
        threats.push({
          type: 'SQL_INJECTION',
          severity: 'CRITICAL',
          query: query.sql,
          userId: query.userId,
          timestamp: query.timestamp
        })
      }
    }

    // Monitor 2: Brute force attempts
    const loginAttempts = await db.loginAttempts.groupBy({
      by: ['ipAddress'],
      where: {
        success: false,
        timestamp: { gte: new Date(Date.now() - 5 * 60 * 1000) }
      },
      _count: true
    })

    for (const attempt of loginAttempts) {
      if (attempt._count > 10) {
        threats.push({
          type: 'BRUTE_FORCE',
          severity: 'HIGH',
          ipAddress: attempt.ipAddress,
          attempts: attempt._count
        })
      }
    }

    // Monitor 3: Privilege escalation
    const privilegeChanges = await db.auditLog.findMany({
      where: {
        tableName: 'users',
        action: 'UPDATE',
        timestamp: { gte: new Date(Date.now() - 60 * 60 * 1000) }
      }
    })

    for (const change of privilegeChanges) {
      if (change.newValue?.role === 'ADMIN' && change.oldValue?.role !== 'ADMIN') {
        threats.push({
          type: 'PRIVILEGE_ESCALATION',
          severity: 'CRITICAL',
          userId: change.userId,
          targetUserId: change.recordId,
          timestamp: change.timestamp
        })
      }
    }

    // Alert on critical threats
    const criticalThreats = threats.filter(t => t.severity === 'CRITICAL')
    if (criticalThreats.length > 0) {
      await this.alertSecurityTeam(criticalThreats)
    }

    return threats
  }

  private async alertSecurityTeam(threats: any[]) {
    // Send alerts via multiple channels
    await Promise.all([
      this.sendSlackAlert(threats),
      this.sendEmailAlert(threats),
      this.createPagerDutyIncident(threats)
    ])
  }
}

When to Use Me

Perfect for:

  • Security incident investigation
  • Fraud detection and prevention
  • Compliance auditing (GDPR, SOC2, HIPAA)
  • Data breach response
  • Forensic analysis of suspicious activity
  • Data integrity verification

I'll help you:

  • Build audit trail systems
  • Detect anomalies and fraud
  • Track data lineage
  • Investigate breaches
  • Ensure regulatory compliance
  • Recover compromised data

What I'll Create

🔍 Audit Trail Systems
🚨 Anomaly Detection Engines
🔐 Fraud Detection Pipelines
📊 Data Lineage Tracking
🛡️ Breach Investigation Tools
⚖️ Compliance Reporting
🔄 Forensic Recovery Systems

Let's build secure, auditable, and compliant data systems!

FAQ

What does the forensic-data-engineer skill do?

Expert in data forensics, anomaly detection, audit trail analysis, fraud detection, and breach investigation

How do I install forensic-data-engineer?

Run npx skills add https://github.com/daffy0208/ai-dev-standards --skill forensic-data-engineer in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/forensic-data-engineer/ (personal) or .claude/skills/forensic-data-engineer/ (project).

Which AI agents can use forensic-data-engineer?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is forensic-data-engineer safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains forensic-data-engineer?

It is published by daffy0208 in daffy0208/ai-dev-standards. It has 178 recorded installs.

More from daffy0208/ai-dev-standards

View all →

animation-designer

daffy0208/ai-dev-standards

Expert in web animations, transitions, and motion design using Framer Motion and CSS

Frontend & Design1.9K installs

brand-designer

daffy0208/ai-dev-standards

Expert in brand identity, logo design, and visual brand systems

Marketing & SEO1.3K installs

3d-visualizer

daffy0208/ai-dev-standards

Expert in Three.js, 3D graphics, and interactive 3D visualizations

Media & Creative665 installs

data-visualizer

daffy0208/ai-dev-standards

Expert in creating charts, dashboards, and data visualizations using modern libraries

572 installs

video-producer

daffy0208/ai-dev-standards

Open the skill to read its SKILL.md instructions.

Media & Creative449 installs

knowledge base manager

daffy0208/ai-dev-standards

Open the skill to read its SKILL.md instructions.

438 installs

Popular security skills

View category →

azure-compliance

microsoft/azure-skills

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

OfficialSecurity567K installs

minimal-run-and-audit

lllllllama/rigorpilot-skills

Rigor Run skill for README-first deep learning repo reproduction. Use when the task is specifically to capture or normalize evidence from the selected smoke test or documented inference or evaluation command and write standardized reprooutputs/ files, including patch notes when repository files changed. Do not use for training execution, initial repo intake, generic environment setup, paper lookup, target selection, hidden scientific-meaning changes, or end-to-end orchestration by itself.

Security477.4K installs

seo-audit

coreyhaines31/marketingskills

When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not showing up in Google," "site isn't ranking," "Google update hit me," "page speed," "core web vitals," "crawl errors," "indexing issues," "stuck on page 2," "striking distance keywords," "title tag rewrite," "low CTR," "local SEO," "Google Business Profile," or "map pack." Use this even if the user just says something vague like "my SEO is bad" or "help with SEO" — start with an audit. For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema. For AI search optimization, see ai-seo.

Security238.7K installs

firebase-security-rules-auditor

firebase/agent-skills

Audits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource exhaustion, type safety, size limits, and hasOnly ownership checks. Use when auditing/reviewing rules, running red-team rule assessments, or scoring against auditor checklists. Don't use for Firebase CLI (login, deploy), Auth, Crashlytics, Remote Config, or database queries.

OfficialSecurity139.1K installs

audit

pbakaus/impeccable

Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan. Use when the user wants an accessibility check, performance audit, or technical quality review.

Security81.9K installs

competitors

coreyhaines31/marketingskills

When the user wants to create competitor comparison or alternative pages for SEO and buyer-facing use. Also use when the user mentions 'alternative page,' 'vs page,' 'competitor comparison,' 'comparison page,' '[Product] vs [Product],' '[Product] alternative,' 'competitive landing pages,' 'how do we compare to X,' 'competitor teardown,' 'audit our competitor pages,' 'are our comparison pages out of date,' or 'competitive asset audit.' Use this for any content that positions your product against competitors. Covers four formats: singular alternative, plural alternatives, you vs competitor, and competitor vs competitor. For auditing existing claims (not researching competitors from scratch, which is competitor-profiling; not technical SEO on these pages, which is seo-audit), use the asset audit here. For internal battle cards and sales-specific competitor docs, see sales-enablement.

Security79.3K installs