ISO 27001 Compliance for ChatGPT Apps: Information Security Guide

Building ChatGPT apps for enterprise customers requires demonstrating robust information security management. ISO/IEC 27001 certification provides a globally recognized framework for protecting sensitive data, managing security risks, and ensuring business continuity. This comprehensive guide walks you through implementing ISO 27001 for your ChatGPT applications, from establishing your Information Security Management System (ISMS) to achieving and maintaining certification.

Whether you're targeting healthcare organizations subject to HIPAA, financial institutions under PCI DSS, or government agencies requiring FedRAMP compliance, ISO 27001 provides the foundational security framework that supports compliance with multiple regulatory standards. For ChatGPT apps processing customer data, implementing ISO 27001 controls protects against data breaches, builds customer trust, and opens doors to enterprise sales opportunities.

This guide provides production-ready code examples for risk assessment, control implementation, audit management, and continuous monitoring. You'll learn how to integrate ISO 27001 requirements into your ChatGPT app development workflow, implement technical safeguards that exceed baseline requirements, and maintain compliance as your application scales.

Understanding the ISMS Framework

The Information Security Management System (ISMS) forms the foundation of ISO 27001 compliance. Your ISMS encompasses policies, procedures, processes, and organizational structures designed to manage information security risks systematically. For ChatGPT apps, this means defining security boundaries, establishing governance structures, and implementing controls that protect data throughout its lifecycle.

Scope Definition and Context

Start by defining your ISMS scope—the boundaries of what you're protecting. For a ChatGPT app, this typically includes your MCP server infrastructure, widget code, authentication systems, data storage, and third-party integrations. Document internal and external factors affecting security, such as regulatory requirements, customer expectations, and threat landscape.

Your scope statement should explicitly identify what's included and excluded. If your ChatGPT app integrates with external APIs but you don't control those systems, clearly document the boundaries of responsibility. This clarity prevents scope creep during audits and focuses your security efforts where they matter most.

Information Security Policy Development

Your top-level information security policy establishes management commitment and sets the direction for your ISMS. This policy must align with business objectives while addressing ISO 27001 requirements. For ChatGPT apps, your policy should cover data protection principles, acceptable use of AI capabilities, incident response commitments, and continuous improvement objectives.

Develop supporting policies for specific areas: access control, cryptography, operations security, supplier relationships, and business continuity. Each policy should define objectives, responsibilities, and high-level requirements that cascade into detailed procedures and technical controls. Learn more about implementing comprehensive security policies for ChatGPT apps.

Here's a policy management system that tracks policy lifecycle, approval workflows, and compliance monitoring:

// policy-management-system.ts
import { EventEmitter } from 'events';

interface Policy {
  id: string;
  title: string;
  version: string;
  category: 'access' | 'data' | 'operations' | 'supplier' | 'continuity';
  content: string;
  owner: string;
  approvers: string[];
  status: 'draft' | 'review' | 'approved' | 'archived';
  effectiveDate?: Date;
  reviewDate: Date;
  relatedControls: string[];
  metadata: {
    createdAt: Date;
    updatedAt: Date;
    approvalHistory: ApprovalRecord[];
  };
}

interface ApprovalRecord {
  approver: string;
  decision: 'approved' | 'rejected' | 'pending';
  timestamp: Date;
  comments?: string;
}

interface PolicyViolation {
  policyId: string;
  description: string;
  severity: 'critical' | 'high' | 'medium' | 'low';
  detectedAt: Date;
  remediationActions: string[];
}

class PolicyManagementSystem extends EventEmitter {
  private policies: Map<string, Policy> = new Map();
  private violations: PolicyViolation[] = [];
  private reviewSchedule: Map<string, NodeJS.Timeout> = new Map();

  /**
   * Create a new policy in draft status
   */
  createPolicy(policyData: Omit<Policy, 'id' | 'status' | 'metadata'>): Policy {
    const policy: Policy = {
      ...policyData,
      id: this.generatePolicyId(policyData.category),
      status: 'draft',
      metadata: {
        createdAt: new Date(),
        updatedAt: new Date(),
        approvalHistory: []
      }
    };

    this.policies.set(policy.id, policy);
    this.scheduleReview(policy);
    this.emit('policy:created', policy);

    return policy;
  }

  /**
   * Submit policy for approval workflow
   */
  submitForApproval(policyId: string): void {
    const policy = this.policies.get(policyId);
    if (!policy) throw new Error('Policy not found');
    if (policy.status !== 'draft') throw new Error('Only draft policies can be submitted');

    policy.status = 'review';
    policy.metadata.updatedAt = new Date();

    // Initialize approval records
    policy.metadata.approvalHistory = policy.approvers.map(approver => ({
      approver,
      decision: 'pending',
      timestamp: new Date()
    }));

    this.policies.set(policyId, policy);
    this.emit('policy:submitted', policy);

    // Notify approvers
    this.notifyApprovers(policy);
  }

  /**
   * Record approval decision
   */
  recordApproval(
    policyId: string,
    approver: string,
    decision: 'approved' | 'rejected',
    comments?: string
  ): void {
    const policy = this.policies.get(policyId);
    if (!policy) throw new Error('Policy not found');

    const approvalRecord = policy.metadata.approvalHistory.find(
      record => record.approver === approver
    );

    if (!approvalRecord) throw new Error('Approver not authorized');

    approvalRecord.decision = decision;
    approvalRecord.timestamp = new Date();
    approvalRecord.comments = comments;

    policy.metadata.updatedAt = new Date();

    // Check if all approvals received
    const allApproved = policy.metadata.approvalHistory.every(
      record => record.decision === 'approved'
    );

    const anyRejected = policy.metadata.approvalHistory.some(
      record => record.decision === 'rejected'
    );

    if (allApproved) {
      policy.status = 'approved';
      policy.effectiveDate = new Date();
      this.emit('policy:approved', policy);
    } else if (anyRejected) {
      policy.status = 'draft';
      this.emit('policy:rejected', policy);
    }

    this.policies.set(policyId, policy);
  }

  /**
   * Track policy violations
   */
  recordViolation(violation: PolicyViolation): void {
    this.violations.push(violation);
    this.emit('policy:violation', violation);

    const policy = this.policies.get(violation.policyId);
    if (policy) {
      this.notifyPolicyOwner(policy, violation);
    }
  }

  /**
   * Generate compliance report
   */
  generateComplianceReport(): {
    totalPolicies: number;
    policyStatus: Record<Policy['status'], number>;
    upcomingReviews: Array<{ policyId: string; reviewDate: Date }>;
    violations: {
      total: number;
      bySeverity: Record<PolicyViolation['severity'], number>;
      recent: PolicyViolation[];
    };
    controlCoverage: Record<string, string[]>;
  } {
    const policyStatus: Record<Policy['status'], number> = {
      draft: 0,
      review: 0,
      approved: 0,
      archived: 0
    };

    const upcomingReviews: Array<{ policyId: string; reviewDate: Date }> = [];
    const controlCoverage: Record<string, string[]> = {};

    for (const policy of this.policies.values()) {
      policyStatus[policy.status]++;

      // Track upcoming reviews (next 30 days)
      const daysUntilReview = Math.ceil(
        (policy.reviewDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24)
      );

      if (daysUntilReview <= 30 && daysUntilReview > 0) {
        upcomingReviews.push({
          policyId: policy.id,
          reviewDate: policy.reviewDate
        });
      }

      // Map controls to policies
      for (const control of policy.relatedControls) {
        if (!controlCoverage[control]) {
          controlCoverage[control] = [];
        }
        controlCoverage[control].push(policy.id);
      }
    }

    const violationsBySeverity: Record<PolicyViolation['severity'], number> = {
      critical: 0,
      high: 0,
      medium: 0,
      low: 0
    };

    for (const violation of this.violations) {
      violationsBySeverity[violation.severity]++;
    }

    return {
      totalPolicies: this.policies.size,
      policyStatus,
      upcomingReviews: upcomingReviews.sort(
        (a, b) => a.reviewDate.getTime() - b.reviewDate.getTime()
      ),
      violations: {
        total: this.violations.length,
        bySeverity: violationsBySeverity,
        recent: this.violations.slice(-10)
      },
      controlCoverage
    };
  }

  private generatePolicyId(category: Policy['category']): string {
    const prefix = category.substring(0, 3).toUpperCase();
    const timestamp = Date.now().toString(36);
    return `${prefix}-${timestamp}`;
  }

  private scheduleReview(policy: Policy): void {
    const msUntilReview = policy.reviewDate.getTime() - Date.now();

    if (msUntilReview > 0) {
      const timeout = setTimeout(() => {
        this.emit('policy:review-due', policy);
        this.notifyPolicyOwner(policy, 'review-due');
      }, msUntilReview);

      this.reviewSchedule.set(policy.id, timeout);
    }
  }

  private notifyApprovers(policy: Policy): void {
    // Implementation would integrate with notification system
    console.log(`Notifying approvers for policy ${policy.id}:`, policy.approvers);
  }

  private notifyPolicyOwner(policy: Policy, event: string | PolicyViolation): void {
    // Implementation would integrate with notification system
    console.log(`Notifying policy owner ${policy.owner}:`, event);
  }
}

// Usage example
const pms = new PolicyManagementSystem();

// Create data protection policy
const dataPolicy = pms.createPolicy({
  title: 'ChatGPT App Data Protection Policy',
  version: '1.0',
  category: 'data',
  content: `
    # Data Protection Policy

    ## Purpose
    This policy establishes requirements for protecting customer data processed by our ChatGPT applications.

    ## Scope
    Applies to all data collected, processed, stored, or transmitted by MCP servers and widgets.

    ## Requirements
    1. Data minimization: Collect only necessary data
    2. Encryption: Encrypt data in transit and at rest
    3. Access control: Implement least privilege access
    4. Retention: Delete data according to retention schedules
    5. Breach notification: Report breaches within 72 hours
  `,
  owner: 'security-team@company.com',
  approvers: ['ciso@company.com', 'legal@company.com', 'cto@company.com'],
  reviewDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1 year
  relatedControls: ['A.8.2.1', 'A.8.2.2', 'A.8.2.3', 'A.9.4.1']
});

// Submit for approval
pms.submitForApproval(dataPolicy.id);

// Record approvals
pms.recordApproval(dataPolicy.id, 'ciso@company.com', 'approved', 'Meets security requirements');
pms.recordApproval(dataPolicy.id, 'legal@company.com', 'approved', 'Legally compliant');
pms.recordApproval(dataPolicy.id, 'cto@company.com', 'approved', 'Technically feasible');

// Monitor compliance
pms.on('policy:violation', (violation) => {
  console.log('Policy violation detected:', violation);
  // Trigger incident response workflow
});

// Generate compliance report
const report = pms.generateComplianceReport();
console.log('Compliance Report:', JSON.stringify(report, null, 2));

Risk Assessment and Treatment

ISO 27001 requires systematic identification and treatment of information security risks. For ChatGPT apps, this means analyzing threats to your MCP servers, authentication mechanisms, data storage, and third-party integrations. Your risk assessment should consider technical vulnerabilities, organizational weaknesses, and external threats.

Asset Identification and Valuation

Begin by creating a comprehensive asset inventory. For ChatGPT apps, assets include source code, cryptographic keys, customer data, MCP server infrastructure, authentication systems, and intellectual property. Classify assets by criticality and sensitivity to prioritize protection efforts.

Here's an asset inventory system that tracks information assets, their classification, and associated risks:

// asset-inventory.ts
interface Asset {
  id: string;
  name: string;
  type: 'data' | 'system' | 'service' | 'personnel' | 'facility' | 'ip';
  owner: string;
  custodian: string;
  classification: 'public' | 'internal' | 'confidential' | 'restricted';
  location: string;
  value: {
    confidentiality: 1 | 2 | 3 | 4 | 5;
    integrity: 1 | 2 | 3 | 4 | 5;
    availability: 1 | 2 | 3 | 4 | 5;
  };
  dependencies: string[];
  controls: string[];
  risks: string[];
  metadata: {
    createdAt: Date;
    lastReviewed: Date;
    reviewCycle: number; // days
  };
}

interface RiskAssociation {
  assetId: string;
  riskId: string;
  impact: 'critical' | 'high' | 'medium' | 'low';
  likelihood: 'very-high' | 'high' | 'medium' | 'low' | 'very-low';
  riskLevel: number;
}

class AssetInventory {
  private assets: Map<string, Asset> = new Map();
  private riskAssociations: RiskAssociation[] = [];

  /**
   * Register a new asset
   */
  registerAsset(assetData: Omit<Asset, 'id' | 'metadata'>): Asset {
    const asset: Asset = {
      ...assetData,
      id: this.generateAssetId(assetData.type),
      metadata: {
        createdAt: new Date(),
        lastReviewed: new Date(),
        reviewCycle: this.getDefaultReviewCycle(assetData.classification)
      }
    };

    this.assets.set(asset.id, asset);
    return asset;
  }

  /**
   * Calculate asset value based on CIA triad
   */
  calculateAssetValue(assetId: string): number {
    const asset = this.assets.get(assetId);
    if (!asset) throw new Error('Asset not found');

    const { confidentiality, integrity, availability } = asset.value;

    // Weighted calculation (confidentiality weighs more for data assets)
    const weights = asset.type === 'data'
      ? { c: 0.4, i: 0.3, a: 0.3 }
      : { c: 0.3, i: 0.4, a: 0.3 };

    return (
      confidentiality * weights.c +
      integrity * weights.i +
      availability * weights.a
    );
  }

  /**
   * Associate risk with asset
   */
  associateRisk(
    assetId: string,
    riskId: string,
    impact: RiskAssociation['impact'],
    likelihood: RiskAssociation['likelihood']
  ): void {
    const asset = this.assets.get(assetId);
    if (!asset) throw new Error('Asset not found');

    const riskLevel = this.calculateRiskLevel(impact, likelihood);

    this.riskAssociations.push({
      assetId,
      riskId,
      impact,
      likelihood,
      riskLevel
    });

    // Add risk to asset tracking
    if (!asset.risks.includes(riskId)) {
      asset.risks.push(riskId);
    }
  }

  /**
   * Generate asset register report
   */
  generateAssetRegister(): {
    totalAssets: number;
    byType: Record<Asset['type'], number>;
    byClassification: Record<Asset['classification'], number>;
    criticalAssets: Asset[];
    assetsRequiringReview: Asset[];
    riskExposure: {
      totalRisks: number;
      highRiskAssets: string[];
      averageRiskLevel: number;
    };
  } {
    const byType: Record<Asset['type'], number> = {
      data: 0,
      system: 0,
      service: 0,
      personnel: 0,
      facility: 0,
      ip: 0
    };

    const byClassification: Record<Asset['classification'], number> = {
      public: 0,
      internal: 0,
      confidential: 0,
      restricted: 0
    };

    const criticalAssets: Asset[] = [];
    const assetsRequiringReview: Asset[] = [];

    for (const asset of this.assets.values()) {
      byType[asset.type]++;
      byClassification[asset.classification]++;

      // Identify critical assets (value >= 4)
      if (this.calculateAssetValue(asset.id) >= 4) {
        criticalAssets.push(asset);
      }

      // Check review status
      const daysSinceReview = Math.floor(
        (Date.now() - asset.metadata.lastReviewed.getTime()) / (1000 * 60 * 60 * 24)
      );

      if (daysSinceReview >= asset.metadata.reviewCycle) {
        assetsRequiringReview.push(asset);
      }
    }

    // Calculate risk exposure
    const assetRiskLevels = new Map<string, number>();

    for (const association of this.riskAssociations) {
      const currentLevel = assetRiskLevels.get(association.assetId) || 0;
      assetRiskLevels.set(
        association.assetId,
        Math.max(currentLevel, association.riskLevel)
      );
    }

    const highRiskAssets = Array.from(assetRiskLevels.entries())
      .filter(([_, level]) => level >= 15)
      .map(([assetId, _]) => assetId);

    const averageRiskLevel = assetRiskLevels.size > 0
      ? Array.from(assetRiskLevels.values()).reduce((a, b) => a + b, 0) / assetRiskLevels.size
      : 0;

    return {
      totalAssets: this.assets.size,
      byType,
      byClassification,
      criticalAssets,
      assetsRequiringReview,
      riskExposure: {
        totalRisks: this.riskAssociations.length,
        highRiskAssets,
        averageRiskLevel
      }
    };
  }

  private generateAssetId(type: Asset['type']): string {
    const prefix = type.substring(0, 3).toUpperCase();
    return `${prefix}-${Date.now().toString(36).toUpperCase()}`;
  }

  private getDefaultReviewCycle(classification: Asset['classification']): number {
    const cycles = {
      public: 365,
      internal: 180,
      confidential: 90,
      restricted: 30
    };
    return cycles[classification];
  }

  private calculateRiskLevel(
    impact: RiskAssociation['impact'],
    likelihood: RiskAssociation['likelihood']
  ): number {
    const impactValues = { critical: 5, high: 4, medium: 3, low: 2 };
    const likelihoodValues = { 'very-high': 5, high: 4, medium: 3, low: 2, 'very-low': 1 };

    return impactValues[impact] * likelihoodValues[likelihood];
  }
}

// Usage example
const inventory = new AssetInventory();

// Register ChatGPT app assets
const customerData = inventory.registerAsset({
  name: 'Customer Conversation Data',
  type: 'data',
  owner: 'data-team@company.com',
  custodian: 'engineering@company.com',
  classification: 'confidential',
  location: 'Firebase Firestore (us-central1)',
  value: {
    confidentiality: 5,
    integrity: 4,
    availability: 3
  },
  dependencies: ['SYS-001', 'SYS-002'],
  controls: ['A.9.4.1', 'A.10.1.1', 'A.10.1.2'],
  risks: []
});

const mcpServer = inventory.registerAsset({
  name: 'MCP Server Infrastructure',
  type: 'system',
  owner: 'engineering@company.com',
  custodian: 'devops@company.com',
  classification: 'internal',
  location: 'Google Cloud Platform (us-central1)',
  value: {
    confidentiality: 3,
    integrity: 5,
    availability: 5
  },
  dependencies: [],
  controls: ['A.12.1.2', 'A.12.6.1', 'A.17.2.1'],
  risks: []
});

// Associate risks
inventory.associateRisk(customerData.id, 'RISK-001', 'critical', 'medium');
inventory.associateRisk(mcpServer.id, 'RISK-002', 'high', 'low');

const register = inventory.generateAssetRegister();
console.log('Asset Register:', JSON.stringify(register, null, 2));

Threat Modeling and Vulnerability Assessment

Identify potential threats to each asset category. For ChatGPT apps, common threats include unauthorized access to conversation data, MCP server compromise, injection attacks through prompts, and third-party API breaches. Use structured threat modeling frameworks like STRIDE or PASTA to ensure comprehensive coverage.

This threat model generator implements STRIDE methodology for ChatGPT applications:

// threat-model-generator.ts
interface ThreatCategory {
  name: 'Spoofing' | 'Tampering' | 'Repudiation' | 'Information Disclosure' | 'Denial of Service' | 'Elevation of Privilege';
  description: string;
}

interface Threat {
  id: string;
  category: ThreatCategory['name'];
  title: string;
  description: string;
  affectedAssets: string[];
  attackVector: string;
  prerequisites: string[];
  impact: {
    confidentiality: 'none' | 'low' | 'medium' | 'high' | 'critical';
    integrity: 'none' | 'low' | 'medium' | 'high' | 'critical';
    availability: 'none' | 'low' | 'medium' | 'high' | 'critical';
  };
  likelihood: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
  existingControls: string[];
  residualRisk: number;
  mitigations: string[];
}

interface DataFlowDiagram {
  processes: Array<{ id: string; name: string; trustBoundary: boolean }>;
  dataStores: Array<{ id: string; name: string; type: string }>;
  externalEntities: Array<{ id: string; name: string }>;
  dataFlows: Array<{ from: string; to: string; data: string; protocol: string }>;
}

class ThreatModelGenerator {
  private threats: Map<string, Threat> = new Map();
  private dfd: DataFlowDiagram | null = null;

  /**
   * Generate threat model from data flow diagram
   */
  generateFromDFD(dfd: DataFlowDiagram): Threat[] {
    this.dfd = dfd;
    const generatedThreats: Threat[] = [];

    // Analyze each component type
    for (const process of dfd.processes) {
      generatedThreats.push(...this.analyzeProcess(process));
    }

    for (const dataStore of dfd.dataStores) {
      generatedThreats.push(...this.analyzeDataStore(dataStore));
    }

    for (const dataFlow of dfd.dataFlows) {
      generatedThreats.push(...this.analyzeDataFlow(dataFlow));
    }

    // Store generated threats
    for (const threat of generatedThreats) {
      this.threats.set(threat.id, threat);
    }

    return generatedThreats;
  }

  /**
   * Analyze process for STRIDE threats
   */
  private analyzeProcess(process: { id: string; name: string; trustBoundary: boolean }): Threat[] {
    const threats: Threat[] = [];

    // Spoofing
    threats.push({
      id: this.generateThreatId(),
      category: 'Spoofing',
      title: `Authentication Bypass in ${process.name}`,
      description: 'Attacker impersonates legitimate user or service to access process functionality',
      affectedAssets: [process.id],
      attackVector: 'Network',
      prerequisites: ['Network access to process', 'Knowledge of authentication mechanism'],
      impact: {
        confidentiality: 'high',
        integrity: 'high',
        availability: 'low'
      },
      likelihood: 'medium',
      existingControls: [],
      residualRisk: 0,
      mitigations: [
        'Implement multi-factor authentication',
        'Use OAuth 2.1 with PKCE',
        'Validate JWT signatures and claims',
        'Implement rate limiting on authentication endpoints'
      ]
    });

    // Tampering
    threats.push({
      id: this.generateThreatId(),
      category: 'Tampering',
      title: `Process Logic Manipulation in ${process.name}`,
      description: 'Attacker modifies process execution logic or data in transit',
      affectedAssets: [process.id],
      attackVector: 'Network',
      prerequisites: ['Man-in-the-middle position', 'Lack of integrity protection'],
      impact: {
        confidentiality: 'low',
        integrity: 'critical',
        availability: 'low'
      },
      likelihood: 'low',
      existingControls: [],
      residualRisk: 0,
      mitigations: [
        'Use TLS 1.3 for all communications',
        'Implement message signing for API requests',
        'Validate input at all trust boundaries',
        'Deploy integrity monitoring on process binaries'
      ]
    });

    if (process.trustBoundary) {
      // Elevation of Privilege (for processes crossing trust boundaries)
      threats.push({
        id: this.generateThreatId(),
        category: 'Elevation of Privilege',
        title: `Privilege Escalation in ${process.name}`,
        description: 'Attacker gains elevated privileges by exploiting process vulnerabilities',
        affectedAssets: [process.id],
        attackVector: 'Local',
        prerequisites: ['Access to process', 'Vulnerable privilege management'],
        impact: {
          confidentiality: 'critical',
          integrity: 'critical',
          availability: 'high'
        },
        likelihood: 'medium',
        existingControls: [],
        residualRisk: 0,
        mitigations: [
          'Implement principle of least privilege',
          'Use role-based access control (RBAC)',
          'Regular security code reviews',
          'Deploy runtime application self-protection (RASP)'
        ]
      });
    }

    return threats;
  }

  /**
   * Analyze data store for STRIDE threats
   */
  private analyzeDataStore(dataStore: { id: string; name: string; type: string }): Threat[] {
    const threats: Threat[] = [];

    // Information Disclosure
    threats.push({
      id: this.generateThreatId(),
      category: 'Information Disclosure',
      title: `Unauthorized Data Access in ${dataStore.name}`,
      description: 'Attacker gains unauthorized access to sensitive data in storage',
      affectedAssets: [dataStore.id],
      attackVector: 'Network',
      prerequisites: ['Access to storage system', 'Weak access controls'],
      impact: {
        confidentiality: 'critical',
        integrity: 'none',
        availability: 'none'
      },
      likelihood: 'high',
      existingControls: [],
      residualRisk: 0,
      mitigations: [
        'Encrypt data at rest using AES-256',
        'Implement field-level encryption for PII',
        'Use Firestore security rules for access control',
        'Enable audit logging for all data access',
        'Deploy DLP (Data Loss Prevention) tools'
      ]
    });

    // Tampering
    threats.push({
      id: this.generateThreatId(),
      category: 'Tampering',
      title: `Data Integrity Compromise in ${dataStore.name}`,
      description: 'Attacker modifies stored data without authorization',
      affectedAssets: [dataStore.id],
      attackVector: 'Network',
      prerequisites: ['Write access to storage', 'Insufficient integrity controls'],
      impact: {
        confidentiality: 'none',
        integrity: 'critical',
        availability: 'low'
      },
      likelihood: 'medium',
      existingControls: [],
      residualRisk: 0,
      mitigations: [
        'Implement write access controls',
        'Use cryptographic hashing for integrity verification',
        'Enable versioning and backup',
        'Deploy database activity monitoring',
        'Implement change data capture (CDC)'
      ]
    });

    // Denial of Service
    threats.push({
      id: this.generateThreatId(),
      category: 'Denial of Service',
      title: `Storage Exhaustion Attack on ${dataStore.name}`,
      description: 'Attacker floods storage system causing unavailability',
      affectedAssets: [dataStore.id],
      attackVector: 'Network',
      prerequisites: ['Write access', 'No quota limits'],
      impact: {
        confidentiality: 'none',
        integrity: 'low',
        availability: 'critical'
      },
      likelihood: 'medium',
      existingControls: [],
      residualRisk: 0,
      mitigations: [
        'Implement storage quotas per user/tenant',
        'Deploy rate limiting on write operations',
        'Monitor storage usage and alert on anomalies',
        'Implement auto-scaling for storage resources',
        'Regular cleanup of temporary/expired data'
      ]
    });

    return threats;
  }

  /**
   * Analyze data flow for STRIDE threats
   */
  private analyzeDataFlow(flow: { from: string; to: string; data: string; protocol: string }): Threat[] {
    const threats: Threat[] = [];

    // Information Disclosure
    if (!flow.protocol.includes('TLS') && !flow.protocol.includes('HTTPS')) {
      threats.push({
        id: this.generateThreatId(),
        category: 'Information Disclosure',
        title: `Unencrypted Data Flow: ${flow.from} → ${flow.to}`,
        description: 'Sensitive data transmitted without encryption, vulnerable to interception',
        affectedAssets: [flow.from, flow.to],
        attackVector: 'Network',
        prerequisites: ['Network access', 'Packet capture capability'],
        impact: {
          confidentiality: 'critical',
          integrity: 'none',
          availability: 'none'
        },
        likelihood: 'high',
        existingControls: [],
        residualRisk: 0,
        mitigations: [
          'Enforce TLS 1.3 for all data in transit',
          'Disable legacy protocols (TLS 1.0, 1.1)',
          'Implement certificate pinning in clients',
          'Use perfect forward secrecy (PFS) cipher suites'
        ]
      });
    }

    return threats;
  }

  /**
   * Calculate residual risk after controls
   */
  calculateResidualRisk(threatId: string, appliedControls: string[]): number {
    const threat = this.threats.get(threatId);
    if (!threat) throw new Error('Threat not found');

    // Update existing controls
    threat.existingControls = [...threat.existingControls, ...appliedControls];

    // Calculate risk reduction based on control coverage
    const totalMitigations = threat.mitigations.length;
    const implementedMitigations = appliedControls.length;
    const coverage = Math.min(implementedMitigations / totalMitigations, 1);

    const impactScore = this.impactToScore(threat.impact);
    const likelihoodScore = this.likelihoodToScore(threat.likelihood);
    const inherentRisk = impactScore * likelihoodScore;

    // Residual risk = Inherent risk * (1 - control effectiveness)
    const controlEffectiveness = coverage * 0.8; // Max 80% reduction
    threat.residualRisk = Math.round(inherentRisk * (1 - controlEffectiveness));

    return threat.residualRisk;
  }

  private impactToScore(impact: Threat['impact']): number {
    const levels = { none: 0, low: 1, medium: 2, high: 3, critical: 4 };
    const maxImpact = Math.max(
      levels[impact.confidentiality],
      levels[impact.integrity],
      levels[impact.availability]
    );
    return maxImpact;
  }

  private likelihoodToScore(likelihood: Threat['likelihood']): number {
    const scores = { 'very-low': 1, low: 2, medium: 3, high: 4, 'very-high': 5 };
    return scores[likelihood];
  }

  private generateThreatId(): string {
    return `THR-${Date.now().toString(36).toUpperCase()}`;
  }

  /**
   * Generate threat model report
   */
  generateReport(): {
    totalThreats: number;
    byCategory: Record<ThreatCategory['name'], number>;
    highRiskThreats: Threat[];
    controlGaps: Array<{ threatId: string; missingControls: string[] }>;
    riskHeatMap: Record<string, number>;
  } {
    const byCategory: Record<ThreatCategory['name'], number> = {
      'Spoofing': 0,
      'Tampering': 0,
      'Repudiation': 0,
      'Information Disclosure': 0,
      'Denial of Service': 0,
      'Elevation of Privilege': 0
    };

    const highRiskThreats: Threat[] = [];
    const controlGaps: Array<{ threatId: string; missingControls: string[] }> = [];
    const riskHeatMap: Record<string, number> = {};

    for (const threat of this.threats.values()) {
      byCategory[threat.category]++;

      if (threat.residualRisk >= 12) {
        highRiskThreats.push(threat);
      }

      if (threat.existingControls.length < threat.mitigations.length) {
        controlGaps.push({
          threatId: threat.id,
          missingControls: threat.mitigations.filter(
            m => !threat.existingControls.includes(m)
          )
        });
      }

      // Build risk heat map
      for (const asset of threat.affectedAssets) {
        riskHeatMap[asset] = (riskHeatMap[asset] || 0) + threat.residualRisk;
      }
    }

    return {
      totalThreats: this.threats.size,
      byCategory,
      highRiskThreats,
      controlGaps,
      riskHeatMap
    };
  }
}

// Usage example for ChatGPT app
const threatModel = new ThreatModelGenerator();

const chatGptAppDFD: DataFlowDiagram = {
  processes: [
    { id: 'PROC-001', name: 'MCP Server', trustBoundary: true },
    { id: 'PROC-002', name: 'Widget Renderer', trustBoundary: false },
    { id: 'PROC-003', name: 'Authentication Service', trustBoundary: true }
  ],
  dataStores: [
    { id: 'DS-001', name: 'Firestore Database', type: 'NoSQL' },
    { id: 'DS-002', name: 'Firebase Storage', type: 'Object Storage' }
  ],
  externalEntities: [
    { id: 'EXT-001', name: 'ChatGPT User' },
    { id: 'EXT-002', name: 'Third-Party API' }
  ],
  dataFlows: [
    { from: 'EXT-001', to: 'PROC-001', data: 'User Request', protocol: 'HTTPS' },
    { from: 'PROC-001', to: 'DS-001', data: 'Conversation Data', protocol: 'gRPC/TLS' },
    { from: 'PROC-001', to: 'EXT-002', data: 'API Request', protocol: 'HTTPS' }
  ]
};

const threats = threatModel.generateFromDFD(chatGptAppDFD);
console.log(`Generated ${threats.length} threats`);

// Apply controls and calculate residual risk
threatModel.calculateResidualRisk(threats[0].id, [
  'Implement multi-factor authentication',
  'Use OAuth 2.1 with PKCE',
  'Validate JWT signatures and claims'
]);

const report = threatModel.generateReport();
console.log('Threat Model Report:', JSON.stringify(report, null, 2));

Risk Treatment Planning

For each identified risk, ISO 27001 requires selecting a treatment option: avoid, reduce, share, or accept. Most ChatGPT app risks fall into the "reduce" category, requiring implementation of security controls from Annex A. Document your risk treatment plan with clear ownership, timelines, and success criteria. See our guide on risk management for ChatGPT applications for detailed strategies.

Here's a comprehensive risk assessment tool that integrates threat modeling with control selection:

// risk-assessment-tool.ts
interface Risk {
  id: string;
  title: string;
  description: string;
  category: 'strategic' | 'operational' | 'financial' | 'compliance' | 'reputational';
  affectedAssets: string[];
  threats: string[];
  vulnerabilities: string[];
  inherentRisk: {
    impact: 1 | 2 | 3 | 4 | 5;
    likelihood: 1 | 2 | 3 | 4 | 5;
    score: number;
  };
  treatment: 'avoid' | 'reduce' | 'share' | 'accept';
  controls: Array<{
    controlId: string;
    name: string;
    type: 'preventive' | 'detective' | 'corrective';
    effectiveness: number; // 0-1
    implementationStatus: 'planned' | 'in-progress' | 'implemented' | 'verified';
    implementationDate?: Date;
    owner: string;
  }>;
  residualRisk: {
    impact: 1 | 2 | 3 | 4 | 5;
    likelihood: 1 | 2 | 3 | 4 | 5;
    score: number;
  };
  acceptanceStatus: 'pending' | 'accepted' | 'rejected';
  owner: string;
  reviewDate: Date;
  metadata: {
    createdAt: Date;
    lastAssessed: Date;
    assessor: string;
  };
}

interface RiskTreatmentPlan {
  riskId: string;
  objectives: string[];
  actions: Array<{
    id: string;
    description: string;
    owner: string;
    deadline: Date;
    dependencies: string[];
    status: 'not-started' | 'in-progress' | 'completed' | 'blocked';
    completionPercentage: number;
  }>;
  budget: {
    estimated: number;
    actual: number;
    currency: string;
  };
  timeline: {
    startDate: Date;
    targetDate: Date;
    actualDate?: Date;
  };
  successCriteria: string[];
  kpis: Array<{
    name: string;
    target: number;
    actual: number;
    unit: string;
  }>;
}

class RiskAssessmentTool {
  private risks: Map<string, Risk> = new Map();
  private treatmentPlans: Map<string, RiskTreatmentPlan> = new Map();
  private riskMatrix: number[][] = this.initializeRiskMatrix();

  /**
   * Create risk assessment
   */
  assessRisk(riskData: Omit<Risk, 'id' | 'inherentRisk' | 'residualRisk' | 'metadata'>): Risk {
    const inherentScore = riskData.threats.length * riskData.vulnerabilities.length;
    const inherentImpact = Math.min(Math.ceil(inherentScore / 5), 5) as 1 | 2 | 3 | 4 | 5;
    const inherentLikelihood = Math.min(Math.ceil(inherentScore / 3), 5) as 1 | 2 | 3 | 4 | 5;

    const risk: Risk = {
      ...riskData,
      id: this.generateRiskId(),
      inherentRisk: {
        impact: inherentImpact,
        likelihood: inherentLikelihood,
        score: this.riskMatrix[inherentImpact - 1][inherentLikelihood - 1]
      },
      residualRisk: {
        impact: inherentImpact,
        likelihood: inherentLikelihood,
        score: this.riskMatrix[inherentImpact - 1][inherentLikelihood - 1]
      },
      metadata: {
        createdAt: new Date(),
        lastAssessed: new Date(),
        assessor: 'system'
      }
    };

    this.risks.set(risk.id, risk);
    return risk;
  }

  /**
   * Apply controls and recalculate residual risk
   */
  applyControls(riskId: string): void {
    const risk = this.risks.get(riskId);
    if (!risk) throw new Error('Risk not found');

    // Calculate control effectiveness
    const implementedControls = risk.controls.filter(
      c => c.implementationStatus === 'implemented' || c.implementationStatus === 'verified'
    );

    if (implementedControls.length === 0) {
      return; // No change to residual risk
    }

    // Preventive controls reduce likelihood
    // Detective/Corrective controls reduce impact
    const preventiveEffectiveness = implementedControls
      .filter(c => c.type === 'preventive')
      .reduce((sum, c) => sum + c.effectiveness, 0) / implementedControls.length || 0;

    const detectiveEffectiveness = implementedControls
      .filter(c => c.type !== 'preventive')
      .reduce((sum, c) => sum + c.effectiveness, 0) / implementedControls.length || 0;

    // Reduce likelihood by preventive control effectiveness
    const reducedLikelihood = Math.max(
      1,
      Math.round(risk.inherentRisk.likelihood * (1 - preventiveEffectiveness))
    ) as 1 | 2 | 3 | 4 | 5;

    // Reduce impact by detective/corrective control effectiveness
    const reducedImpact = Math.max(
      1,
      Math.round(risk.inherentRisk.impact * (1 - detectiveEffectiveness))
    ) as 1 | 2 | 3 | 4 | 5;

    risk.residualRisk = {
      impact: reducedImpact,
      likelihood: reducedLikelihood,
      score: this.riskMatrix[reducedImpact - 1][reducedLikelihood - 1]
    };

    risk.metadata.lastAssessed = new Date();
    this.risks.set(riskId, risk);
  }

  /**
   * Create risk treatment plan
   */
  createTreatmentPlan(
    riskId: string,
    planData: Omit<RiskTreatmentPlan, 'riskId'>
  ): RiskTreatmentPlan {
    const risk = this.risks.get(riskId);
    if (!risk) throw new Error('Risk not found');

    const plan: RiskTreatmentPlan = {
      riskId,
      ...planData
    };

    this.treatmentPlans.set(riskId, plan);
    return plan;
  }

  /**
   * Update treatment action status
   */
  updateActionStatus(
    riskId: string,
    actionId: string,
    status: RiskTreatmentPlan['actions'][0]['status'],
    completionPercentage: number
  ): void {
    const plan = this.treatmentPlans.get(riskId);
    if (!plan) throw new Error('Treatment plan not found');

    const action = plan.actions.find(a => a.id === actionId);
    if (!action) throw new Error('Action not found');

    action.status = status;
    action.completionPercentage = completionPercentage;

    // If all actions completed, update plan completion
    const allCompleted = plan.actions.every(a => a.status === 'completed');
    if (allCompleted && !plan.timeline.actualDate) {
      plan.timeline.actualDate = new Date();
    }

    this.treatmentPlans.set(riskId, plan);
  }

  /**
   * Generate risk register
   */
  generateRiskRegister(): {
    totalRisks: number;
    byCategory: Record<Risk['category'], number>;
    byTreatment: Record<Risk['treatment'], number>;
    riskDistribution: {
      critical: Risk[];
      high: Risk[];
      medium: Risk[];
      low: Risk[];
    };
    topRisks: Risk[];
    controlEffectiveness: {
      averageReduction: number;
      byControlType: Record<'preventive' | 'detective' | 'corrective', number>;
    };
    treatmentProgress: {
      totalPlans: number;
      onTrack: number;
      delayed: number;
      completed: number;
    };
  } {
    const byCategory: Record<Risk['category'], number> = {
      strategic: 0,
      operational: 0,
      financial: 0,
      compliance: 0,
      reputational: 0
    };

    const byTreatment: Record<Risk['treatment'], number> = {
      avoid: 0,
      reduce: 0,
      share: 0,
      accept: 0
    };

    const riskDistribution = {
      critical: [] as Risk[],
      high: [] as Risk[],
      medium: [] as Risk[],
      low: [] as Risk[]
    };

    let totalReduction = 0;
    const controlTypeReductions = { preventive: 0, detective: 0, corrective: 0 };
    const controlTypeCounts = { preventive: 0, detective: 0, corrective: 0 };

    for (const risk of this.risks.values()) {
      byCategory[risk.category]++;
      byTreatment[risk.treatment]++;

      // Classify by residual risk level
      if (risk.residualRisk.score >= 20) {
        riskDistribution.critical.push(risk);
      } else if (risk.residualRisk.score >= 12) {
        riskDistribution.high.push(risk);
      } else if (risk.residualRisk.score >= 6) {
        riskDistribution.medium.push(risk);
      } else {
        riskDistribution.low.push(risk);
      }

      // Calculate risk reduction
      const reduction = ((risk.inherentRisk.score - risk.residualRisk.score) / risk.inherentRisk.score) * 100;
      totalReduction += reduction;

      // Track control effectiveness by type
      for (const control of risk.controls) {
        if (control.implementationStatus === 'implemented' || control.implementationStatus === 'verified') {
          controlTypeReductions[control.type] += reduction;
          controlTypeCounts[control.type]++;
        }
      }
    }

    const averageReduction = this.risks.size > 0 ? totalReduction / this.risks.size : 0;

    // Treatment progress
    let onTrack = 0;
    let delayed = 0;
    let completed = 0;

    for (const plan of this.treatmentPlans.values()) {
      if (plan.timeline.actualDate) {
        completed++;
      } else {
        const now = new Date();
        if (now > plan.timeline.targetDate) {
          delayed++;
        } else {
          onTrack++;
        }
      }
    }

    // Top 10 risks by residual risk score
    const topRisks = Array.from(this.risks.values())
      .sort((a, b) => b.residualRisk.score - a.residualRisk.score)
      .slice(0, 10);

    return {
      totalRisks: this.risks.size,
      byCategory,
      byTreatment,
      riskDistribution,
      topRisks,
      controlEffectiveness: {
        averageReduction,
        byControlType: {
          preventive: controlTypeCounts.preventive > 0
            ? controlTypeReductions.preventive / controlTypeCounts.preventive
            : 0,
          detective: controlTypeCounts.detective > 0
            ? controlTypeReductions.detective / controlTypeCounts.detective
            : 0,
          corrective: controlTypeCounts.corrective > 0
            ? controlTypeReductions.corrective / controlTypeCounts.corrective
            : 0
        }
      },
      treatmentProgress: {
        totalPlans: this.treatmentPlans.size,
        onTrack,
        delayed,
        completed
      }
    };
  }

  private initializeRiskMatrix(): number[][] {
    // Risk matrix: [impact][likelihood] = score
    return [
      [1, 2, 3, 4, 5],      // Impact 1
      [2, 4, 6, 8, 10],     // Impact 2
      [3, 6, 9, 12, 15],    // Impact 3
      [4, 8, 12, 16, 20],   // Impact 4
      [5, 10, 15, 20, 25]   // Impact 5
    ];
  }

  private generateRiskId(): string {
    return `RISK-${Date.now().toString(36).toUpperCase()}`;
  }
}

// Usage example
const rat = new RiskAssessmentTool();

// Assess data breach risk
const dataBreachRisk = rat.assessRisk({
  title: 'Customer Data Breach',
  description: 'Unauthorized access to customer conversation data in Firestore',
  category: 'compliance',
  affectedAssets: ['DS-001'],
  threats: ['THR-001', 'THR-002', 'THR-003'],
  vulnerabilities: ['Weak access controls', 'Unencrypted fields'],
  treatment: 'reduce',
  controls: [
    {
      controlId: 'A.9.4.1',
      name: 'Information Access Restriction',
      type: 'preventive',
      effectiveness: 0.7,
      implementationStatus: 'implemented',
      implementationDate: new Date('2026-01-15'),
      owner: 'security-team@company.com'
    },
    {
      controlId: 'A.10.1.1',
      name: 'Cryptographic Controls Policy',
      type: 'preventive',
      effectiveness: 0.8,
      implementationStatus: 'implemented',
      implementationDate: new Date('2026-01-10'),
      owner: 'security-team@company.com'
    },
    {
      controlId: 'A.12.4.1',
      name: 'Event Logging',
      type: 'detective',
      effectiveness: 0.6,
      implementationStatus: 'verified',
      implementationDate: new Date('2026-01-05'),
      owner: 'operations@company.com'
    }
  ],
  acceptanceStatus: 'pending',
  owner: 'ciso@company.com',
  reviewDate: new Date('2026-07-01')
});

// Apply controls and recalculate residual risk
rat.applyControls(dataBreachRisk.id);

// Create treatment plan
const treatmentPlan = rat.createTreatmentPlan(dataBreachRisk.id, {
  objectives: [
    'Reduce likelihood of unauthorized access',
    'Implement field-level encryption',
    'Deploy real-time monitoring'
  ],
  actions: [
    {
      id: 'ACT-001',
      description: 'Implement field-level encryption for PII fields',
      owner: 'engineering@company.com',
      deadline: new Date('2026-02-28'),
      dependencies: [],
      status: 'in-progress',
      completionPercentage: 60
    },
    {
      id: 'ACT-002',
      description: 'Deploy SIEM for real-time access monitoring',
      owner: 'security-team@company.com',
      deadline: new Date('2026-03-15'),
      dependencies: ['ACT-001'],
      status: 'not-started',
      completionPercentage: 0
    }
  ],
  budget: {
    estimated: 50000,
    actual: 32000,
    currency: 'USD'
  },
  timeline: {
    startDate: new Date('2026-01-15'),
    targetDate: new Date('2026-03-31')
  },
  successCriteria: [
    'All PII fields encrypted at rest',
    'Zero unauthorized access events',
    'Mean time to detect (MTTD) < 5 minutes'
  ],
  kpis: [
    { name: 'Encryption Coverage', target: 100, actual: 60, unit: '%' },
    { name: 'MTTD', target: 5, actual: 15, unit: 'minutes' },
    { name: 'Unauthorized Access Attempts', target: 0, actual: 2, unit: 'count' }
  ]
});

const register = rat.generateRiskRegister();
console.log('Risk Register:', JSON.stringify(register, null, 2));

Implementing ISO 27001 Controls

Annex A of ISO 27001 contains 93 controls organized into 14 categories. Not all controls apply to every organization—your Statement of Applicability (SoA) documents which controls are relevant and how you're addressing them. For ChatGPT apps, focus on controls related to access control (A.9), cryptography (A.10), operations security (A.12), communications security (A.13), and supplier relationships (A.15).

Technical Controls Implementation

Technical controls protect your ChatGPT app infrastructure through encryption, access management, logging, and monitoring. Implement encryption for data at rest and in transit, use strong authentication mechanisms, deploy intrusion detection systems, and maintain comprehensive audit logs. For detailed guidance, see our article on implementing technical security controls.

This control matrix manager tracks implementation status across all Annex A controls:

// control-matrix-manager.ts
interface AnnexAControl {
  id: string; // e.g., "A.9.4.1"
  category: string; // e.g., "Access Control"
  name: string;
  objective: string;
  applicability: 'applicable' | 'not-applicable' | 'partially-applicable';
  justification: string;
  implementationStatus: 'not-started' | 'planned' | 'in-progress' | 'implemented' | 'verified';
  implementationApproach: string;
  evidence: Array<{
    type: 'document' | 'screenshot' | 'log' | 'configuration' | 'test-result';
    description: string;
    location: string;
    collectedDate: Date;
  }>;
  responsibleParty: string;
  reviewDate: Date;
  effectivenessRating: 1 | 2 | 3 | 4 | 5 | null;
  gaps: string[];
  remediationActions: string[];
  relatedControls: string[];
  relatedRisks: string[];
}

interface ControlCategory {
  id: string;
  name: string;
  controlCount: number;
  implementedCount: number;
  completionPercentage: number;
}

class ControlMatrixManager {
  private controls: Map<string, AnnexAControl> = new Map();

  constructor() {
    this.initializeAnnexAControls();
  }

  /**
   * Initialize all 93 Annex A controls
   */
  private initializeAnnexAControls(): void {
    // Sample of key controls for ChatGPT apps
    const controls: Partial<AnnexAControl>[] = [
      {
        id: 'A.9.4.1',
        category: 'Access Control',
        name: 'Information Access Restriction',
        objective: 'Access to information and application system functions shall be restricted in accordance with the access control policy',
        applicability: 'applicable',
        justification: 'Critical for protecting customer conversation data in Firestore'
      },
      {
        id: 'A.10.1.1',
        category: 'Cryptography',
        name: 'Policy on the Use of Cryptographic Controls',
        objective: 'A policy on the use of cryptographic controls for protection of information shall be developed and implemented',
        applicability: 'applicable',
        justification: 'Required for encrypting PII and authentication tokens'
      },
      {
        id: 'A.12.4.1',
        category: 'Operations Security',
        name: 'Event Logging',
        objective: 'Event logs recording user activities, exceptions, faults and information security events shall be produced, kept and regularly reviewed',
        applicability: 'applicable',
        justification: 'Essential for audit trail and incident investigation'
      },
      {
        id: 'A.13.1.1',
        category: 'Communications Security',
        name: 'Network Controls',
        objective: 'Networks shall be managed and controlled to protect information in systems and applications',
        applicability: 'applicable',
        justification: 'MCP server communicates over HTTPS; firewall rules required'
      },
      {
        id: 'A.15.1.2',
        category: 'Supplier Relationships',
        name: 'Addressing Security Within Supplier Agreements',
        objective: 'All relevant information security requirements shall be established and agreed with each supplier',
        applicability: 'applicable',
        justification: 'Third-party APIs (OpenAI, Firebase, payment processors) require security requirements'
      }
      // ... additional controls
    ];

    for (const controlData of controls) {
      const control: AnnexAControl = {
        id: controlData.id!,
        category: controlData.category!,
        name: controlData.name!,
        objective: controlData.objective!,
        applicability: controlData.applicability!,
        justification: controlData.justification!,
        implementationStatus: 'not-started',
        implementationApproach: '',
        evidence: [],
        responsibleParty: '',
        reviewDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
        effectivenessRating: null,
        gaps: [],
        remediationActions: [],
        relatedControls: [],
        relatedRisks: []
      };

      this.controls.set(control.id, control);
    }
  }

  /**
   * Update control implementation
   */
  updateControl(
    controlId: string,
    updates: Partial<Pick<
      AnnexAControl,
      'implementationStatus' | 'implementationApproach' | 'responsibleParty' | 'effectivenessRating'
    >>
  ): void {
    const control = this.controls.get(controlId);
    if (!control) throw new Error('Control not found');

    Object.assign(control, updates);
    this.controls.set(controlId, control);
  }

  /**
   * Add evidence for control
   */
  addEvidence(
    controlId: string,
    evidence: AnnexAControl['evidence'][0]
  ): void {
    const control = this.controls.get(controlId);
    if (!control) throw new Error('Control not found');

    control.evidence.push(evidence);
    this.controls.set(controlId, control);
  }

  /**
   * Identify control gaps
   */
  identifyGaps(controlId: string, gaps: string[]): void {
    const control = this.controls.get(controlId);
    if (!control) throw new Error('Control not found');

    control.gaps = gaps;
    this.controls.set(controlId, control);
  }

  /**
   * Generate Statement of Applicability (SoA)
   */
  generateSoA(): {
    applicable: AnnexAControl[];
    notApplicable: AnnexAControl[];
    partiallyApplicable: AnnexAControl[];
    completionSummary: {
      total: number;
      implemented: number;
      inProgress: number;
      notStarted: number;
      percentage: number;
    };
  } {
    const applicable: AnnexAControl[] = [];
    const notApplicable: AnnexAControl[] = [];
    const partiallyApplicable: AnnexAControl[] = [];

    let implemented = 0;
    let inProgress = 0;
    let notStarted = 0;

    for (const control of this.controls.values()) {
      if (control.applicability === 'applicable') {
        applicable.push(control);
      } else if (control.applicability === 'not-applicable') {
        notApplicable.push(control);
      } else {
        partiallyApplicable.push(control);
      }

      if (control.implementationStatus === 'implemented' || control.implementationStatus === 'verified') {
        implemented++;
      } else if (control.implementationStatus === 'in-progress' || control.implementationStatus === 'planned') {
        inProgress++;
      } else {
        notStarted++;
      }
    }

    const total = applicable.length + partiallyApplicable.length;
    const percentage = total > 0 ? (implemented / total) * 100 : 0;

    return {
      applicable,
      notApplicable,
      partiallyApplicable,
      completionSummary: {
        total,
        implemented,
        inProgress,
        notStarted,
        percentage
      }
    };
  }

  /**
   * Generate control effectiveness report
   */
  generateEffectivenessReport(): {
    byCategory: ControlCategory[];
    weakControls: AnnexAControl[];
    controlsWithGaps: AnnexAControl[];
    evidenceStatus: {
      controlsWithEvidence: number;
      controlsWithoutEvidence: number;
      averageEvidencePerControl: number;
    };
  } {
    const categoryMap = new Map<string, ControlCategory>();
    const weakControls: AnnexAControl[] = [];
    const controlsWithGaps: AnnexAControl[] = [];

    let totalEvidence = 0;
    let controlsWithEvidence = 0;

    for (const control of this.controls.values()) {
      if (control.applicability === 'not-applicable') continue;

      // Track by category
      if (!categoryMap.has(control.category)) {
        categoryMap.set(control.category, {
          id: control.category,
          name: control.category,
          controlCount: 0,
          implementedCount: 0,
          completionPercentage: 0
        });
      }

      const category = categoryMap.get(control.category)!;
      category.controlCount++;

      if (control.implementationStatus === 'implemented' || control.implementationStatus === 'verified') {
        category.implementedCount++;
      }

      // Identify weak controls
      if (control.effectivenessRating && control.effectivenessRating <= 2) {
        weakControls.push(control);
      }

      // Track gaps
      if (control.gaps.length > 0) {
        controlsWithGaps.push(control);
      }

      // Evidence tracking
      if (control.evidence.length > 0) {
        controlsWithEvidence++;
        totalEvidence += control.evidence.length;
      }
    }

    // Calculate completion percentages
    for (const category of categoryMap.values()) {
      category.completionPercentage = category.controlCount > 0
        ? (category.implementedCount / category.controlCount) * 100
        : 0;
    }

    const byCategory = Array.from(categoryMap.values()).sort(
      (a, b) => b.completionPercentage - a.completionPercentage
    );

    const applicableControls = Array.from(this.controls.values()).filter(
      c => c.applicability !== 'not-applicable'
    ).length;

    return {
      byCategory,
      weakControls,
      controlsWithGaps,
      evidenceStatus: {
        controlsWithEvidence,
        controlsWithoutEvidence: applicableControls - controlsWithEvidence,
        averageEvidencePerControl: applicableControls > 0
          ? totalEvidence / applicableControls
          : 0
      }
    };
  }
}

// Usage example
const cmm = new ControlMatrixManager();

// Update access control implementation
cmm.updateControl('A.9.4.1', {
  implementationStatus: 'implemented',
  implementationApproach: 'Firestore security rules enforce user-level access control. Each document has userId field checked against request.auth.uid.',
  responsibleParty: 'engineering@company.com',
  effectivenessRating: 4
});

// Add evidence
cmm.addEvidence('A.9.4.1', {
  type: 'configuration',
  description: 'Firestore security rules configuration',
  location: '/firestore.rules',
  collectedDate: new Date()
});

cmm.addEvidence('A.9.4.1', {
  type: 'test-result',
  description: 'Security rules unit test results',
  location: '/test-results/firestore-security-tests.xml',
  collectedDate: new Date()
});

// Identify gaps
cmm.identifyGaps('A.15.1.2', [
  'No formal security requirements in Firebase supplier agreement',
  'Third-party API security assessment not documented'
]);

// Generate reports
const soa = cmm.generateSoA();
console.log('Statement of Applicability:', JSON.stringify(soa, null, 2));

const effectiveness = cmm.generateEffectivenessReport();
console.log('Control Effectiveness:', JSON.stringify(effectiveness, null, 2));

Organizational Controls and Documentation

ISO 27001 requires extensive documentation: information security policy, risk assessment methodology, risk treatment plan, Statement of Applicability, documented procedures, and evidence of control operation. Maintain version control for all ISMS documents and ensure they're accessible to relevant personnel. Regular reviews keep documentation current as your ChatGPT app evolves.

Establish clear roles and responsibilities for information security. Designate an information security manager, define management review schedules, and create incident response procedures. For enterprise ChatGPT apps, consider establishing a security governance committee that meets quarterly to review risk status and approve significant changes.

Here's an audit logging system that provides evidence of control operation:

// audit-logger.ts
interface AuditEvent {
  id: string;
  timestamp: Date;
  eventType: 'access' | 'modification' | 'deletion' | 'configuration' | 'authentication' | 'authorization';
  severity: 'info' | 'warning' | 'error' | 'critical';
  userId: string;
  userEmail: string;
  ipAddress: string;
  userAgent: string;
  resource: {
    type: string;
    id: string;
    name: string;
  };
  action: string;
  result: 'success' | 'failure';
  details: Record<string, any>;
  controlReference?: string;
  complianceFlags: string[];
}

interface AuditQuery {
  startDate?: Date;
  endDate?: Date;
  eventTypes?: AuditEvent['eventType'][];
  severities?: AuditEvent['severity'][];
  userIds?: string[];
  resources?: string[];
  results?: AuditEvent['result'][];
  controlReferences?: string[];
  limit?: number;
}

class AuditLogger {
  private events: AuditEvent[] = [];
  private readonly retentionDays = 2555; // 7 years for ISO 27001

  /**
   * Log audit event
   */
  log(eventData: Omit<AuditEvent, 'id' | 'timestamp'>): AuditEvent {
    const event: AuditEvent = {
      id: this.generateEventId(),
      timestamp: new Date(),
      ...eventData
    };

    this.events.push(event);
    this.enforceRetentionPolicy();

    // Real-time alerting for critical events
    if (event.severity === 'critical') {
      this.alertSecurityTeam(event);
    }

    return event;
  }

  /**
   * Query audit logs
   */
  query(criteria: AuditQuery): AuditEvent[] {
    let results = [...this.events];

    if (criteria.startDate) {
      results = results.filter(e => e.timestamp >= criteria.startDate!);
    }

    if (criteria.endDate) {
      results = results.filter(e => e.timestamp <= criteria.endDate!);
    }

    if (criteria.eventTypes && criteria.eventTypes.length > 0) {
      results = results.filter(e => criteria.eventTypes!.includes(e.eventType));
    }

    if (criteria.severities && criteria.severities.length > 0) {
      results = results.filter(e => criteria.severities!.includes(e.severity));
    }

    if (criteria.userIds && criteria.userIds.length > 0) {
      results = results.filter(e => criteria.userIds!.includes(e.userId));
    }

    if (criteria.resources && criteria.resources.length > 0) {
      results = results.filter(e => criteria.resources!.includes(e.resource.id));
    }

    if (criteria.results && criteria.results.length > 0) {
      results = results.filter(e => criteria.results!.includes(e.result));
    }

    if (criteria.controlReferences && criteria.controlReferences.length > 0) {
      results = results.filter(e =>
        e.controlReference && criteria.controlReferences!.includes(e.controlReference)
      );
    }

    // Sort by timestamp descending
    results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());

    if (criteria.limit) {
      results = results.slice(0, criteria.limit);
    }

    return results;
  }

  /**
   * Generate compliance report for specific control
   */
  generateControlEvidence(
    controlId: string,
    startDate: Date,
    endDate: Date
  ): {
    totalEvents: number;
    successCount: number;
    failureCount: number;
    byEventType: Record<AuditEvent['eventType'], number>;
    suspiciousActivities: AuditEvent[];
    complianceSummary: string;
  } {
    const events = this.query({
      startDate,
      endDate,
      controlReferences: [controlId]
    });

    const byEventType: Record<AuditEvent['eventType'], number> = {
      access: 0,
      modification: 0,
      deletion: 0,
      configuration: 0,
      authentication: 0,
      authorization: 0
    };

    let successCount = 0;
    let failureCount = 0;
    const suspiciousActivities: AuditEvent[] = [];

    for (const event of events) {
      byEventType[event.eventType]++;

      if (event.result === 'success') {
        successCount++;
      } else {
        failureCount++;
      }

      // Flag suspicious patterns
      if (event.severity === 'critical' || event.severity === 'error') {
        suspiciousActivities.push(event);
      }
    }

    const complianceSummary = this.generateComplianceSummary(
      controlId,
      events,
      successCount,
      failureCount
    );

    return {
      totalEvents: events.length,
      successCount,
      failureCount,
      byEventType,
      suspiciousActivities,
      complianceSummary
    };
  }

  /**
   * Detect anomalous behavior
   */
  detectAnomalies(): {
    unusualAccessPatterns: Array<{
      userId: string;
      anomalyType: string;
      events: AuditEvent[];
    }>;
    failedAuthenticationSpikes: Array<{
      userId: string;
      failureCount: number;
      timeWindow: { start: Date; end: Date };
    }>;
    afterHoursActivity: AuditEvent[];
  } {
    const unusualAccessPatterns: Array<{
      userId: string;
      anomalyType: string;
      events: AuditEvent[];
    }> = [];

    const failedAuthenticationSpikes: Array<{
      userId: string;
      failureCount: number;
      timeWindow: { start: Date; end: Date };
    }> = [];

    const afterHoursActivity: AuditEvent[] = [];

    // Group events by user
    const eventsByUser = new Map<string, AuditEvent[]>();

    for (const event of this.events) {
      if (!eventsByUser.has(event.userId)) {
        eventsByUser.set(event.userId, []);
      }
      eventsByUser.get(event.userId)!.push(event);
    }

    // Analyze each user's activity
    for (const [userId, userEvents] of eventsByUser) {
      // Check for rapid successive actions
      const rapidActions = this.detectRapidActions(userEvents);
      if (rapidActions.length > 0) {
        unusualAccessPatterns.push({
          userId,
          anomalyType: 'rapid-successive-actions',
          events: rapidActions
        });
      }

      // Check for failed authentication spikes
      const authFailures = userEvents.filter(
        e => e.eventType === 'authentication' && e.result === 'failure'
      );

      if (authFailures.length >= 5) {
        const start = authFailures[0].timestamp;
        const end = authFailures[authFailures.length - 1].timestamp;
        const timeWindowHours = (end.getTime() - start.getTime()) / (1000 * 60 * 60);

        if (timeWindowHours <= 1) {
          failedAuthenticationSpikes.push({
            userId,
            failureCount: authFailures.length,
            timeWindow: { start, end }
          });
        }
      }

      // Check for after-hours activity (outside 9 AM - 6 PM)
      for (const event of userEvents) {
        const hour = event.timestamp.getHours();
        if (hour < 9 || hour >= 18) {
          afterHoursActivity.push(event);
        }
      }
    }

    return {
      unusualAccessPatterns,
      failedAuthenticationSpikes,
      afterHoursActivity
    };
  }

  private detectRapidActions(events: AuditEvent[]): AuditEvent[] {
    const rapidActions: AuditEvent[] = [];
    const sortedEvents = [...events].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());

    for (let i = 0; i < sortedEvents.length - 1; i++) {
      const timeDiff = sortedEvents[i + 1].timestamp.getTime() - sortedEvents[i].timestamp.getTime();

      // Flag if actions within 500ms
      if (timeDiff < 500) {
        rapidActions.push(sortedEvents[i], sortedEvents[i + 1]);
      }
    }

    return rapidActions;
  }

  private enforceRetentionPolicy(): void {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - this.retentionDays);

    this.events = this.events.filter(e => e.timestamp >= cutoffDate);
  }

  private alertSecurityTeam(event: AuditEvent): void {
    // Implementation would integrate with alerting system
    console.log('CRITICAL SECURITY EVENT:', event);
  }

  private generateComplianceSummary(
    controlId: string,
    events: AuditEvent[],
    successCount: number,
    failureCount: number
  ): string {
    const successRate = events.length > 0
      ? (successCount / events.length) * 100
      : 0;

    return `
      Control ${controlId} Evidence Summary
      Period: ${events.length > 0 ? events[events.length - 1].timestamp.toISOString() : 'N/A'} to ${events.length > 0 ? events[0].timestamp.toISOString() : 'N/A'}
      Total Events: ${events.length}
      Success Rate: ${successRate.toFixed(2)}%
      Failures: ${failureCount}

      Assessment: ${successRate >= 95 ? 'Control operating effectively' : 'Control requires attention'}
    `.trim();
  }

  private generateEventId(): string {
    return `AUD-${Date.now().toString(36).toUpperCase()}-${Math.random().toString(36).substring(2, 6).toUpperCase()}`;
  }
}

// Usage example
const auditLogger = new AuditLogger();

// Log successful access
auditLogger.log({
  eventType: 'access',
  severity: 'info',
  userId: 'user-123',
  userEmail: 'user@example.com',
  ipAddress: '203.0.113.42',
  userAgent: 'Mozilla/5.0...',
  resource: {
    type: 'conversation',
    id: 'conv-456',
    name: 'Customer Support Chat'
  },
  action: 'view',
  result: 'success',
  details: {
    method: 'GET',
    endpoint: '/api/conversations/conv-456'
  },
  controlReference: 'A.9.4.1',
  complianceFlags: ['access-control', 'data-protection']
});

// Log failed authentication
auditLogger.log({
  eventType: 'authentication',
  severity: 'warning',
  userId: 'user-789',
  userEmail: 'suspicious@example.com',
  ipAddress: '198.51.100.99',
  userAgent: 'curl/7.68.0',
  resource: {
    type: 'auth-service',
    id: 'auth-001',
    name: 'Authentication Service'
  },
  action: 'login',
  result: 'failure',
  details: {
    reason: 'Invalid credentials',
    attemptCount: 3
  },
  controlReference: 'A.9.2.1',
  complianceFlags: ['access-control', 'authentication']
});

// Generate control evidence
const evidence = auditLogger.generateControlEvidence(
  'A.9.4.1',
  new Date('2026-01-01'),
  new Date('2026-12-31')
);

console.log('Control Evidence:', evidence);

// Detect anomalies
const anomalies = auditLogger.detectAnomalies();
console.log('Security Anomalies:', anomalies);

Certification Process

Achieving ISO 27001 certification requires passing a third-party audit. The process typically takes 6-12 months from initial gap analysis to certification. Understanding each phase helps you prepare effectively and avoid common pitfalls that delay certification.

Internal Audit and Management Review

Before engaging external auditors, conduct thorough internal audits of your ISMS. Internal audits verify control implementation, identify gaps, and provide evidence of ISMS operation. For ChatGPT apps, audit critical areas like authentication mechanisms, data encryption, access controls, and incident response procedures.

Schedule regular management reviews where senior leadership evaluates ISMS performance, reviews risk status, and approves resource allocation. Document these reviews meticulously—auditors will examine meeting minutes, decisions made, and follow-up actions.

This incident management system demonstrates control operation and continuous improvement:

// incident-manager.ts
interface SecurityIncident {
  id: string;
  title: string;
  description: string;
  severity: 'critical' | 'high' | 'medium' | 'low';
  category: 'breach' | 'malware' | 'dos' | 'unauthorized-access' | 'data-loss' | 'other';
  status: 'reported' | 'investigating' | 'contained' | 'resolved' | 'closed';
  reportedBy: string;
  reportedAt: Date;
  detectedAt: Date;
  affectedAssets: string[];
  affectedUsers: number;
  dataCompromised: boolean;
  regulatoryNotificationRequired: boolean;
  timeline: Array<{
    timestamp: Date;
    event: string;
    actor: string;
    notes: string;
  }>;
  rootCause?: string;
  correctiveActions: Array<{
    id: string;
    description: string;
    owner: string;
    deadline: Date;
    status: 'pending' | 'in-progress' | 'completed';
    verificationEvidence?: string;
  }>;
  lessonsLearned: string[];
  relatedControls: string[];
  estimatedImpact: {
    financial: number;
    reputational: 'none' | 'low' | 'medium' | 'high' | 'critical';
    operational: 'none' | 'low' | 'medium' | 'high' | 'critical';
  };
  metadata: {
    createdAt: Date;
    updatedAt: Date;
    closedAt?: Date;
  };
}

class IncidentManager {
  private incidents: Map<string, SecurityIncident> = new Map();
  private slaTargets = {
    critical: { detection: 15, containment: 60, resolution: 240 }, // minutes
    high: { detection: 30, containment: 240, resolution: 1440 },
    medium: { detection: 120, containment: 1440, resolution: 4320 },
    low: { detection: 1440, containment: 4320, resolution: 10080 }
  };

  /**
   * Report new security incident
   */
  reportIncident(incidentData: Omit<SecurityIncident, 'id' | 'status' | 'timeline' | 'metadata'>): SecurityIncident {
    const incident: SecurityIncident = {
      ...incidentData,
      id: this.generateIncidentId(),
      status: 'reported',
      timeline: [{
        timestamp: new Date(),
        event: 'Incident Reported',
        actor: incidentData.reportedBy,
        notes: `Severity: ${incidentData.severity}, Category: ${incidentData.category}`
      }],
      metadata: {
        createdAt: new Date(),
        updatedAt: new Date()
      }
    };

    this.incidents.set(incident.id, incident);

    // Auto-escalate critical incidents
    if (incident.severity === 'critical') {
      this.escalateIncident(incident.id);
    }

    // Check regulatory notification requirements
    if (incident.regulatoryNotificationRequired) {
      this.scheduleRegulatoryNotification(incident);
    }

    return incident;
  }

  /**
   * Update incident status
   */
  updateStatus(
    incidentId: string,
    newStatus: SecurityIncident['status'],
    notes: string,
    actor: string
  ): void {
    const incident = this.incidents.get(incidentId);
    if (!incident) throw new Error('Incident not found');

    incident.status = newStatus;
    incident.timeline.push({
      timestamp: new Date(),
      event: `Status changed to ${newStatus}`,
      actor,
      notes
    });

    incident.metadata.updatedAt = new Date();

    if (newStatus === 'closed') {
      incident.metadata.closedAt = new Date();
    }

    this.incidents.set(incidentId, incident);
  }

  /**
   * Add corrective action
   */
  addCorrectiveAction(
    incidentId: string,
    action: Omit<SecurityIncident['correctiveActions'][0], 'id' | 'status'>
  ): void {
    const incident = this.incidents.get(incidentId);
    if (!incident) throw new Error('Incident not found');

    incident.correctiveActions.push({
      ...action,
      id: this.generateActionId(),
      status: 'pending'
    });

    incident.metadata.updatedAt = new Date();
    this.incidents.set(incidentId, incident);
  }

  /**
   * Calculate incident metrics
   */
  calculateMetrics(incidentId: string): {
    timeToDetect: number;
    timeToContain: number;
    timeToResolve: number;
    slaCompliance: {
      detection: boolean;
      containment: boolean;
      resolution: boolean;
    };
  } {
    const incident = this.incidents.get(incidentId);
    if (!incident) throw new Error('Incident not found');

    const detectedAt = incident.detectedAt.getTime();
    const reportedAt = incident.reportedAt.getTime();

    const containedEvent = incident.timeline.find(e => e.event.includes('contained'));
    const containedAt = containedEvent ? containedEvent.timestamp.getTime() : Date.now();

    const resolvedEvent = incident.timeline.find(e => e.event.includes('resolved'));
    const resolvedAt = resolvedEvent ? resolvedEvent.timestamp.getTime() : Date.now();

    const timeToDetect = (reportedAt - detectedAt) / 60000; // minutes
    const timeToContain = (containedAt - reportedAt) / 60000;
    const timeToResolve = (resolvedAt - reportedAt) / 60000;

    const sla = this.slaTargets[incident.severity];

    return {
      timeToDetect,
      timeToContain,
      timeToResolve,
      slaCompliance: {
        detection: timeToDetect <= sla.detection,
        containment: timeToContain <= sla.containment,
        resolution: timeToResolve <= sla.resolution
      }
    };
  }

  /**
   * Generate incident report
   */
  generateReport(startDate: Date, endDate: Date): {
    totalIncidents: number;
    bySeverity: Record<SecurityIncident['severity'], number>;
    byCategory: Record<SecurityIncident['category'], number>;
    byStatus: Record<SecurityIncident['status'], number>;
    slaCompliance: {
      overall: number;
      byMetric: {
        detection: number;
        containment: number;
        resolution: number;
      };
    };
    topIncidents: SecurityIncident[];
    controlGaps: string[];
    recommendations: string[];
  } {
    const filteredIncidents = Array.from(this.incidents.values()).filter(
      i => i.reportedAt >= startDate && i.reportedAt <= endDate
    );

    const bySeverity: Record<SecurityIncident['severity'], number> = {
      critical: 0,
      high: 0,
      medium: 0,
      low: 0
    };

    const byCategory: Record<SecurityIncident['category'], number> = {
      breach: 0,
      malware: 0,
      dos: 0,
      'unauthorized-access': 0,
      'data-loss': 0,
      other: 0
    };

    const byStatus: Record<SecurityIncident['status'], number> = {
      reported: 0,
      investigating: 0,
      contained: 0,
      resolved: 0,
      closed: 0
    };

    let slaMetCount = 0;
    const metricCompliance = { detection: 0, containment: 0, resolution: 0 };

    const controlGapsMap = new Map<string, number>();

    for (const incident of filteredIncidents) {
      bySeverity[incident.severity]++;
      byCategory[incident.category]++;
      byStatus[incident.status]++;

      // Calculate SLA compliance
      const metrics = this.calculateMetrics(incident.id);
      if (metrics.slaCompliance.detection && metrics.slaCompliance.containment && metrics.slaCompliance.resolution) {
        slaMetCount++;
      }

      if (metrics.slaCompliance.detection) metricCompliance.detection++;
      if (metrics.slaCompliance.containment) metricCompliance.containment++;
      if (metrics.slaCompliance.resolution) metricCompliance.resolution++;

      // Track control gaps
      for (const control of incident.relatedControls) {
        controlGapsMap.set(control, (controlGapsMap.get(control) || 0) + 1);
      }
    }

    const totalIncidents = filteredIncidents.length;
    const overallSlaCompliance = totalIncidents > 0 ? (slaMetCount / totalIncidents) * 100 : 100;

    // Identify top control gaps
    const controlGaps = Array.from(controlGapsMap.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, 5)
      .map(([control, _]) => control);

    // Generate recommendations
    const recommendations: string[] = [];

    if (bySeverity.critical > 0) {
      recommendations.push('Review critical incident root causes and strengthen preventive controls');
    }

    if (overallSlaCompliance < 95) {
      recommendations.push('Improve incident response procedures to meet SLA targets');
    }

    if (controlGaps.length > 0) {
      recommendations.push(`Address control gaps in: ${controlGaps.join(', ')}`);
    }

    // Top 5 incidents by severity and impact
    const topIncidents = filteredIncidents
      .sort((a, b) => {
        const severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
        return severityOrder[b.severity] - severityOrder[a.severity] ||
               b.estimatedImpact.financial - a.estimatedImpact.financial;
      })
      .slice(0, 5);

    return {
      totalIncidents,
      bySeverity,
      byCategory,
      byStatus,
      slaCompliance: {
        overall: overallSlaCompliance,
        byMetric: {
          detection: totalIncidents > 0 ? (metricCompliance.detection / totalIncidents) * 100 : 100,
          containment: totalIncidents > 0 ? (metricCompliance.containment / totalIncidents) * 100 : 100,
          resolution: totalIncidents > 0 ? (metricCompliance.resolution / totalIncidents) * 100 : 100
        }
      },
      topIncidents,
      controlGaps,
      recommendations
    };
  }

  private generateIncidentId(): string {
    return `INC-${Date.now().toString(36).toUpperCase()}`;
  }

  private generateActionId(): string {
    return `ACT-${Date.now().toString(36).toUpperCase()}`;
  }

  private escalateIncident(incidentId: string): void {
    // Implementation would integrate with escalation system
    console.log(`CRITICAL INCIDENT ESCALATION: ${incidentId}`);
  }

  private scheduleRegulatoryNotification(incident: SecurityIncident): void {
    // Implementation would schedule notification within regulatory timeframe (e.g., 72 hours for GDPR)
    console.log(`Scheduling regulatory notification for incident ${incident.id}`);
  }
}

// Usage example
const incidentMgr = new IncidentManager();

// Report data breach incident
const dataBreachIncident = incidentMgr.reportIncident({
  title: 'Unauthorized Access to Customer Data',
  description: 'Firestore security rules misconfiguration allowed user to access other users\' conversation history',
  severity: 'critical',
  category: 'unauthorized-access',
  reportedBy: 'security@company.com',
  reportedAt: new Date(),
  detectedAt: new Date(Date.now() - 30 * 60 * 1000), // Detected 30 mins ago
  affectedAssets: ['DS-001'],
  affectedUsers: 127,
  dataCompromised: true,
  regulatoryNotificationRequired: true,
  correctiveActions: [],
  lessonsLearned: [],
  relatedControls: ['A.9.4.1', 'A.12.4.1'],
  estimatedImpact: {
    financial: 150000,
    reputational: 'high',
    operational: 'medium'
  }
});

// Update status as investigation progresses
incidentMgr.updateStatus(
  dataBreachIncident.id,
  'investigating',
  'Root cause analysis in progress. Security rules being reviewed.',
  'incident-response-team@company.com'
);

// Add corrective actions
incidentMgr.addCorrectiveAction(dataBreachIncident.id, {
  description: 'Deploy corrected Firestore security rules',
  owner: 'engineering@company.com',
  deadline: new Date(Date.now() + 2 * 60 * 60 * 1000) // 2 hours
});

incidentMgr.addCorrectiveAction(dataBreachIncident.id, {
  description: 'Notify affected customers',
  owner: 'legal@company.com',
  deadline: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
});

// Calculate metrics
const metrics = incidentMgr.calculateMetrics(dataBreachIncident.id);
console.log('Incident Metrics:', metrics);

// Generate monthly report
const report = incidentMgr.generateReport(
  new Date('2026-01-01'),
  new Date('2026-01-31')
);
console.log('Incident Report:', JSON.stringify(report, null, 2));

External Certification Audit

The external audit occurs in two stages. Stage 1 is a documentation review where auditors examine your ISMS documentation, policies, procedures, and Statement of Applicability. They'll identify gaps and provide guidance before Stage 2.

Stage 2 is the on-site audit where auditors verify control implementation through interviews, system inspections, and evidence review. For ChatGPT apps, expect auditors to test authentication mechanisms, review access logs, verify encryption implementation, and examine incident response records. Prepare by organizing evidence systematically and ensuring key personnel are available for interviews.

Address any non-conformities identified during the audit. Minor non-conformities can typically be resolved within 90 days; major non-conformities require correction before certification can be granted. Once all issues are resolved, the certification body issues your ISO 27001 certificate, valid for three years.

Surveillance Audits and Recertification

ISO 27001 certification requires annual surveillance audits to verify continued compliance. These lighter audits focus on changes since the previous audit, control operation evidence, and management review outcomes. Maintain your ISMS actively between audits—certification is not a one-time achievement but an ongoing commitment.

After three years, undergo a full recertification audit similar to your initial Stage 2 audit. This ensures your ISMS remains effective as your ChatGPT app grows and evolves. For guidance on maintaining compliance during rapid growth, see our article on scaling security for ChatGPT applications.

Here's a certification tracking system that manages audit schedules and evidence collection:

// certification-tracker.ts
interface AuditEvent {
  id: string;
  type: 'stage-1' | 'stage-2' | 'surveillance' | 'recertification' | 'internal';
  scheduledDate: Date;
  actualDate?: Date;
  auditor: string;
  certificationBody?: string;
  scope: string[];
  findings: Array<{
    id: string;
    type: 'major-nc' | 'minor-nc' | 'observation' | 'ofi'; // OFI = Opportunity for Improvement
    controlReference: string;
    description: string;
    evidence: string;
    correctiveAction?: string;
    deadline?: Date;
    status: 'open' | 'resolved' | 'verified';
  }>;
  auditReport?: string;
  status: 'scheduled' | 'in-progress' | 'completed' | 'cancelled';
}

interface CertificationStatus {
  certificateNumber: string;
  issueDate: Date;
  expiryDate: Date;
  certificationBody: string;
  scope: string;
  status: 'active' | 'suspended' | 'expired' | 'withdrawn';
  surveillanceSchedule: Date[];
  recertificationDate: Date;
}

class CertificationTracker {
  private audits: Map<string, AuditEvent> = new Map();
  private certification: CertificationStatus | null = null;

  /**
   * Schedule audit
   */
  scheduleAudit(auditData: Omit<AuditEvent, 'id' | 'status' | 'findings'>): AuditEvent {
    const audit: AuditEvent = {
      ...auditData,
      id: this.generateAuditId(),
      status: 'scheduled',
      findings: []
    };

    this.audits.set(audit.id, audit);
    return audit;
  }

  /**
   * Record audit findings
   */
  recordFindings(
    auditId: string,
    findings: AuditEvent['findings']
  ): void {
    const audit = this.audits.get(auditId);
    if (!audit) throw new Error('Audit not found');

    audit.findings = findings;
    audit.status = 'completed';

    if (!audit.actualDate) {
      audit.actualDate = new Date();
    }

    this.audits.set(auditId, audit);

    // Auto-escalate major non-conformities
    const majorNCs = findings.filter(f => f.type === 'major-nc');
    if (majorNCs.length > 0) {
      this.escalateMajorNonConformities(audit.id, majorNCs);
    }
  }

  /**
   * Update finding status
   */
  updateFinding(
    auditId: string,
    findingId: string,
    updates: Partial<Pick<AuditEvent['findings'][0], 'correctiveAction' | 'status' | 'deadline'>>
  ): void {
    const audit = this.audits.get(auditId);
    if (!audit) throw new Error('Audit not found');

    const finding = audit.findings.find(f => f.id === findingId);
    if (!finding) throw new Error('Finding not found');

    Object.assign(finding, updates);
    this.audits.set(auditId, audit);
  }

  /**
   * Record certification issuance
   */
  recordCertification(certData: CertificationStatus): void {
    this.certification = certData;

    // Auto-schedule surveillance audits
    this.scheduleSurveillanceAudits();
  }

  /**
   * Generate audit readiness report
   */
  generateReadinessReport(upcomingAuditId: string): {
    auditDetails: AuditEvent;
    openFindings: Array<{ fromAuditId: string; finding: AuditEvent['findings'][0] }>;
    evidenceCollected: number;
    evidenceRequired: number;
    readinessScore: number;
    actionItems: Array<{
      priority: 'critical' | 'high' | 'medium' | 'low';
      description: string;
      deadline: Date;
      owner: string;
    }>;
  } {
    const audit = this.audits.get(upcomingAuditId);
    if (!audit) throw new Error('Audit not found');

    // Collect open findings from previous audits
    const openFindings: Array<{ fromAuditId: string; finding: AuditEvent['findings'][0] }> = [];

    for (const [auditId, prevAudit] of this.audits) {
      if (auditId === upcomingAuditId) continue;

      for (const finding of prevAudit.findings) {
        if (finding.status !== 'verified') {
          openFindings.push({ fromAuditId: auditId, finding });
        }
      }
    }

    // Calculate readiness score
    const totalChecks = 10;
    let passedChecks = 0;

    // Check 1: No open major non-conformities
    const openMajorNCs = openFindings.filter(f => f.finding.type === 'major-nc');
    if (openMajorNCs.length === 0) passedChecks++;

    // Check 2: All minor NCs have corrective actions
    const openMinorNCs = openFindings.filter(f => f.finding.type === 'minor-nc');
    const minorNCsWithActions = openMinorNCs.filter(f => f.finding.correctiveAction);
    if (openMinorNCs.length === 0 || minorNCsWithActions.length === openMinorNCs.length) passedChecks++;

    // Check 3: Internal audit completed in last 12 months
    const recentInternalAudits = Array.from(this.audits.values()).filter(
      a => a.type === 'internal' &&
           a.actualDate &&
           (Date.now() - a.actualDate.getTime()) < 365 * 24 * 60 * 60 * 1000
    );
    if (recentInternalAudits.length > 0) passedChecks++;

    // Check 4: Management review completed in last 12 months
    // (Would check management review records in real implementation)
    passedChecks++;

    // Check 5-10: Additional checks
    passedChecks += 6; // Simplified for example

    const readinessScore = (passedChecks / totalChecks) * 100;

    // Generate action items
    const actionItems: Array<{
      priority: 'critical' | 'high' | 'medium' | 'low';
      description: string;
      deadline: Date;
      owner: string;
    }> = [];

    if (openMajorNCs.length > 0) {
      actionItems.push({
        priority: 'critical',
        description: `Resolve ${openMajorNCs.length} open major non-conformities`,
        deadline: new Date(audit.scheduledDate.getTime() - 7 * 24 * 60 * 60 * 1000),
        owner: 'security-team@company.com'
      });
    }

    if (openMinorNCs.length > minorNCsWithActions.length) {
      actionItems.push({
        priority: 'high',
        description: `Define corrective actions for ${openMinorNCs.length - minorNCsWithActions.length} minor NCs`,
        deadline: new Date(audit.scheduledDate.getTime() - 14 * 24 * 60 * 60 * 1000),
        owner: 'compliance@company.com'
      });
    }

    return {
      auditDetails: audit,
      openFindings,
      evidenceCollected: passedChecks,
      evidenceRequired: totalChecks,
      readinessScore,
      actionItems
    };
  }

  private scheduleSurveillanceAudits(): void {
    if (!this.certification) return;

    for (const surveillanceDate of this.certification.surveillanceSchedule) {
      this.scheduleAudit({
        type: 'surveillance',
        scheduledDate: surveillanceDate,
        auditor: 'TBD',
        certificationBody: this.certification.certificationBody,
        scope: [this.certification.scope]
      });
    }

    // Schedule recertification
    this.scheduleAudit({
      type: 'recertification',
      scheduledDate: this.certification.recertificationDate,
      auditor: 'TBD',
      certificationBody: this.certification.certificationBody,
      scope: [this.certification.scope]
    });
  }

  private escalateMajorNonConformities(
    auditId: string,
    majorNCs: AuditEvent['findings']
  ): void {
    console.log(`MAJOR NON-CONFORMITIES detected in audit ${auditId}:`, majorNCs);
    // Implementation would integrate with escalation system
  }

  private generateAuditId(): string {
    return `AUD-${Date.now().toString(36).toUpperCase()}`;
  }
}

// Usage example
const certTracker = new CertificationTracker();

// Schedule Stage 1 audit
const stage1 = certTracker.scheduleAudit({
  type: 'stage-1',
  scheduledDate: new Date('2026-03-15'),
  auditor: 'John Smith, Lead Auditor',
  certificationBody: 'BSI Group',
  scope: ['ChatGPT App Platform - MCP Servers, Widgets, Infrastructure']
});

// Record findings from Stage 1
certTracker.recordFindings(stage1.id, [
  {
    id: 'F001',
    type: 'minor-nc',
    controlReference: 'A.5.1.1',
    description: 'Information security policy does not explicitly address AI/ML model security',
    evidence: 'Policy document review',
    status: 'open'
  },
  {
    id: 'F002',
    type: 'observation',
    controlReference: 'A.12.4.1',
    description: 'Log retention period not documented',
    evidence: 'Interview with operations team',
    status: 'open'
  }
]);

// Update finding with corrective action
certTracker.updateFinding(stage1.id, 'F001', {
  correctiveAction: 'Updated information security policy to include Section 4.7: AI/ML Model Security Requirements',
  deadline: new Date('2026-04-01'),
  status: 'resolved'
});

// Schedule Stage 2 audit
const stage2 = certTracker.scheduleAudit({
  type: 'stage-2',
  scheduledDate: new Date('2026-05-10'),
  auditor: 'John Smith, Lead Auditor',
  certificationBody: 'BSI Group',
  scope: ['ChatGPT App Platform - MCP Servers, Widgets, Infrastructure']
});

// Record certification
certTracker.recordCertification({
  certificateNumber: 'ISO27001-2026-12345',
  issueDate: new Date('2026-06-01'),
  expiryDate: new Date('2028-06-01'),
  certificationBody: 'BSI Group',
  scope: 'Design, development, and operation of ChatGPT applications and supporting infrastructure',
  status: 'active',
  surveillanceSchedule: [
    new Date('2026-06-01'),
    new Date('2027-06-01')
  ],
  recertificationDate: new Date('2028-05-01')
});

// Generate readiness report for first surveillance audit
const readinessReport = certTracker.generateReadinessReport(
  Array.from(certTracker['audits'].values()).find(a => a.type === 'surveillance')!.id
);

console.log('Audit Readiness:', JSON.stringify(readinessReport, null, 2));

Continuous Improvement and Monitoring

ISO 27001 requires continuous improvement of your ISMS. Regular monitoring, measurement, and review ensure your security controls remain effective as threats evolve and your ChatGPT app scales. Establish key performance indicators (KPIs) and security metrics that provide early warning of control degradation.

Implement automated monitoring where possible. Track authentication failure rates, unauthorized access attempts, system uptime, patch deployment times, and incident response metrics. Visualize these metrics in dashboards that security teams review daily. For comprehensive monitoring strategies, explore our guide on security monitoring for ChatGPT applications.

Conduct regular risk reassessments when significant changes occur: new features, infrastructure changes, emerging threats, or regulatory updates. Update your risk treatment plan accordingly and ensure controls adapt to new risks. This dynamic approach maintains the effectiveness of your security program over time.

Here's a comprehensive compliance dashboard that visualizes ISO 27001 program health:

// compliance-dashboard.tsx
import React, { useState, useEffect } from 'react';
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  BarElement,
  ArcElement,
  Title,
  Tooltip,
  Legend
} from 'chart.js';
import { Line, Bar, Doughnut } from 'react-chartjs-2';

ChartJS.register(
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  BarElement,
  ArcElement,
  Title,
  Tooltip,
  Legend
);

interface ComplianceMetrics {
  controlImplementation: {
    total: number;
    implemented: number;
    inProgress: number;
    notStarted: number;
  };
  riskStatus: {
    critical: number;
    high: number;
    medium: number;
    low: number;
  };
  incidentTrend: Array<{
    month: string;
    count: number;
    severity: Record<string, number>;
  }>;
  auditReadiness: {
    score: number;
    openFindings: number;
    evidenceGaps: number;
  };
  certificationStatus: {
    valid: boolean;
    expiryDate: string;
    daysRemaining: number;
  };
}

const ComplianceDashboard: React.FC = () => {
  const [metrics, setMetrics] = useState<ComplianceMetrics>({
    controlImplementation: {
      total: 93,
      implemented: 78,
      inProgress: 12,
      notStarted: 3
    },
    riskStatus: {
      critical: 2,
      high: 5,
      medium: 15,
      low: 8
    },
    incidentTrend: [
      { month: 'Jan', count: 3, severity: { critical: 0, high: 1, medium: 2, low: 0 } },
      { month: 'Feb', count: 2, severity: { critical: 0, high: 0, medium: 1, low: 1 } },
      { month: 'Mar', count: 5, severity: { critical: 1, high: 2, medium: 2, low: 0 } },
      { month: 'Apr', count: 1, severity: { critical: 0, high: 0, medium: 1, low: 0 } },
      { month: 'May', count: 4, severity: { critical: 0, high: 1, medium: 2, low: 1 } },
      { month: 'Jun', count: 2, severity: { critical: 0, high: 0, medium: 2, low: 0 } }
    ],
    auditReadiness: {
      score: 87,
      openFindings: 3,
      evidenceGaps: 2
    },
    certificationStatus: {
      valid: true,
      expiryDate: '2028-06-01',
      daysRemaining: 1247
    }
  });

  // Control implementation chart
  const controlImplementationData = {
    labels: ['Implemented', 'In Progress', 'Not Started'],
    datasets: [{
      data: [
        metrics.controlImplementation.implemented,
        metrics.controlImplementation.inProgress,
        metrics.controlImplementation.notStarted
      ],
      backgroundColor: ['#10B981', '#F59E0B', '#EF4444'],
      borderWidth: 0
    }]
  };

  // Risk distribution chart
  const riskDistributionData = {
    labels: ['Critical', 'High', 'Medium', 'Low'],
    datasets: [{
      label: 'Number of Risks',
      data: [
        metrics.riskStatus.critical,
        metrics.riskStatus.high,
        metrics.riskStatus.medium,
        metrics.riskStatus.low
      ],
      backgroundColor: ['#DC2626', '#F59E0B', '#FBBF24', '#10B981']
    }]
  };

  // Incident trend chart
  const incidentTrendData = {
    labels: metrics.incidentTrend.map(d => d.month),
    datasets: [
      {
        label: 'Critical',
        data: metrics.incidentTrend.map(d => d.severity.critical),
        borderColor: '#DC2626',
        backgroundColor: 'rgba(220, 38, 38, 0.1)',
        tension: 0.4
      },
      {
        label: 'High',
        data: metrics.incidentTrend.map(d => d.severity.high),
        borderColor: '#F59E0B',
        backgroundColor: 'rgba(245, 158, 11, 0.1)',
        tension: 0.4
      },
      {
        label: 'Medium',
        data: metrics.incidentTrend.map(d => d.severity.medium),
        borderColor: '#FBBF24',
        backgroundColor: 'rgba(251, 191, 36, 0.1)',
        tension: 0.4
      }
    ]
  };

  // Chart options
  const doughnutOptions = {
    responsive: true,
    plugins: {
      legend: {
        position: 'bottom' as const
      },
      title: {
        display: true,
        text: 'Control Implementation Status'
      }
    }
  };

  const barOptions = {
    responsive: true,
    plugins: {
      legend: {
        display: false
      },
      title: {
        display: true,
        text: 'Risk Distribution'
      }
    },
    scales: {
      y: {
        beginAtZero: true,
        ticks: {
          stepSize: 5
        }
      }
    }
  };

  const lineOptions = {
    responsive: true,
    plugins: {
      legend: {
        position: 'bottom' as const
      },
      title: {
        display: true,
        text: 'Security Incident Trend (Last 6 Months)'
      }
    },
    scales: {
      y: {
        beginAtZero: true,
        ticks: {
          stepSize: 1
        }
      }
    }
  };

  return (
    <div className="compliance-dashboard" style={{ padding: '24px', backgroundColor: '#f9fafb' }}>
      <div style={{ marginBottom: '32px' }}>
        <h1 style={{ fontSize: '28px', fontWeight: 'bold', marginBottom: '8px' }}>
          ISO 27001 Compliance Dashboard
        </h1>
        <p style={{ color: '#6b7280' }}>
          Real-time overview of information security management system health
        </p>
      </div>

      {/* Key Metrics */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
        gap: '16px',
        marginBottom: '32px'
      }}>
        {/* Certification Status */}
        <div style={{
          backgroundColor: 'white',
          padding: '20px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
            <div>
              <p style={{ fontSize: '14px', color: '#6b7280', marginBottom: '8px' }}>
                Certification Status
              </p>
              <p style={{ fontSize: '24px', fontWeight: 'bold' }}>
                {metrics.certificationStatus.valid ? 'Valid' : 'Expired'}
              </p>
              <p style={{ fontSize: '12px', color: '#6b7280', marginTop: '4px' }}>
                {metrics.certificationStatus.daysRemaining} days remaining
              </p>
            </div>
            <div style={{
              width: '12px',
              height: '12px',
              borderRadius: '50%',
              backgroundColor: metrics.certificationStatus.valid ? '#10B981' : '#EF4444'
            }} />
          </div>
        </div>

        {/* Control Implementation */}
        <div style={{
          backgroundColor: 'white',
          padding: '20px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <p style={{ fontSize: '14px', color: '#6b7280', marginBottom: '8px' }}>
            Control Implementation
          </p>
          <p style={{ fontSize: '24px', fontWeight: 'bold' }}>
            {Math.round((metrics.controlImplementation.implemented / metrics.controlImplementation.total) * 100)}%
          </p>
          <p style={{ fontSize: '12px', color: '#6b7280', marginTop: '4px' }}>
            {metrics.controlImplementation.implemented} of {metrics.controlImplementation.total} controls
          </p>
        </div>

        {/* Audit Readiness */}
        <div style={{
          backgroundColor: 'white',
          padding: '20px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <p style={{ fontSize: '14px', color: '#6b7280', marginBottom: '8px' }}>
            Audit Readiness Score
          </p>
          <p style={{ fontSize: '24px', fontWeight: 'bold' }}>
            {metrics.auditReadiness.score}/100
          </p>
          <p style={{ fontSize: '12px', color: '#6b7280', marginTop: '4px' }}>
            {metrics.auditReadiness.openFindings} open findings
          </p>
        </div>

        {/* Active Risks */}
        <div style={{
          backgroundColor: 'white',
          padding: '20px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <p style={{ fontSize: '14px', color: '#6b7280', marginBottom: '8px' }}>
            High/Critical Risks
          </p>
          <p style={{ fontSize: '24px', fontWeight: 'bold', color: '#DC2626' }}>
            {metrics.riskStatus.critical + metrics.riskStatus.high}
          </p>
          <p style={{ fontSize: '12px', color: '#6b7280', marginTop: '4px' }}>
            Requires immediate attention
          </p>
        </div>
      </div>

      {/* Charts */}
      <div style={{
        display: 'grid',
        gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))',
        gap: '24px',
        marginBottom: '32px'
      }}>
        {/* Control Implementation Doughnut */}
        <div style={{
          backgroundColor: 'white',
          padding: '24px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <Doughnut data={controlImplementationData} options={doughnutOptions} />
        </div>

        {/* Risk Distribution Bar */}
        <div style={{
          backgroundColor: 'white',
          padding: '24px',
          borderRadius: '8px',
          boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
        }}>
          <Bar data={riskDistributionData} options={barOptions} />
        </div>
      </div>

      {/* Incident Trend Line Chart */}
      <div style={{
        backgroundColor: 'white',
        padding: '24px',
        borderRadius: '8px',
        boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
        marginBottom: '32px'
      }}>
        <Line data={incidentTrendData} options={lineOptions} />
      </div>

      {/* Action Items */}
      <div style={{
        backgroundColor: 'white',
        padding: '24px',
        borderRadius: '8px',
        boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
      }}>
        <h2 style={{ fontSize: '18px', fontWeight: 'bold', marginBottom: '16px' }}>
          Priority Action Items
        </h2>

        <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
          <div style={{
            padding: '16px',
            borderLeft: '4px solid #DC2626',
            backgroundColor: '#FEF2F2',
            borderRadius: '4px'
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
              <span style={{ fontWeight: '600' }}>Resolve 2 critical risks</span>
              <span style={{ fontSize: '12px', color: '#DC2626' }}>CRITICAL</span>
            </div>
            <p style={{ fontSize: '14px', color: '#6b7280' }}>
              Data breach risk and authentication bypass require immediate mitigation
            </p>
          </div>

          <div style={{
            padding: '16px',
            borderLeft: '4px solid #F59E0B',
            backgroundColor: '#FFFBEB',
            borderRadius: '4px'
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
              <span style={{ fontWeight: '600' }}>Close 3 audit findings</span>
              <span style={{ fontSize: '12px', color: '#F59E0B' }}>HIGH</span>
            </div>
            <p style={{ fontSize: '14px', color: '#6b7280' }}>
              Complete corrective actions before next surveillance audit
            </p>
          </div>

          <div style={{
            padding: '16px',
            borderLeft: '4px solid #3B82F6',
            backgroundColor: '#EFF6FF',
            borderRadius: '4px'
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
              <span style={{ fontWeight: '600' }}>Update 12 controls in progress</span>
              <span style={{ fontSize: '12px', color: '#3B82F6' }}>MEDIUM</span>
            </div>
            <p style={{ fontSize: '14px', color: '#6b7280' }}>
              Complete implementation to achieve 100% control coverage
            </p>
          </div>
        </div>
      </div>
    </div>
  );
};

export default ComplianceDashboard;

Finally, here's an evidence repository system for organizing audit evidence:

// evidence-repository.ts
interface Evidence {
  id: string;
  title: string;
  type: 'document' | 'screenshot' | 'log' | 'configuration' | 'test-result' | 'video' | 'other';
  relatedControls: string[];
  relatedAudits: string[];
  collectedDate: Date;
  collectedBy: string;
  location: string;
  hash: string; // SHA-256 hash for integrity verification
  metadata: {
    format: string;
    size: number;
    lastModified: Date;
    retentionPeriod: number; // days
  };
  tags: string[];
  notes: string;
}

class EvidenceRepository {
  private evidence: Map<string, Evidence> = new Map();

  /**
   * Store evidence item
   */
  storeEvidence(evidenceData: Omit<Evidence, 'id'>): Evidence {
    const evidence: Evidence = {
      ...evidenceData,
      id: this.generateEvidenceId()
    };

    this.evidence.set(evidence.id, evidence);
    return evidence;
  }

  /**
   * Retrieve evidence by control
   */
  getEvidenceByControl(controlId: string): Evidence[] {
    return Array.from(this.evidence.values()).filter(
      e => e.relatedControls.includes(controlId)
    );
  }

  /**
   * Retrieve evidence by audit
   */
  getEvidenceByAudit(auditId: string): Evidence[] {
    return Array.from(this.evidence.values()).filter(
      e => e.relatedAudits.includes(auditId)
    );
  }

  /**
   * Verify evidence integrity
   */
  verifyIntegrity(evidenceId: string, currentHash: string): boolean {
    const evidence = this.evidence.get(evidenceId);
    if (!evidence) throw new Error('Evidence not found');

    return evidence.hash === currentHash;
  }

  private generateEvidenceId(): string {
    return `EVD-${Date.now().toString(36).toUpperCase()}`;
  }
}

Conclusion: Building Trust Through ISO 27001

ISO 27001 certification demonstrates your commitment to information security and builds trust with enterprise customers. For ChatGPT apps handling sensitive business data, certification opens doors to contracts with Fortune 500 companies, healthcare organizations, and government agencies that require verified security controls.

The journey to certification requires significant investment in documentation, control implementation, and organizational change. However, the benefits extend beyond the certificate itself. The discipline of systematic risk management, continuous monitoring, and regular audits strengthens your security posture and reduces breach likelihood.

Ready to build ISO 27001 compliant ChatGPT apps? MakeAIHQ provides the security foundation you need with built-in encryption, access controls, audit logging, and compliance documentation. Start your free trial today and leverage our pre-configured security controls that align with ISO 27001 requirements.

Whether you're pursuing certification for the first time or maintaining an existing ISMS, the code examples and frameworks in this guide provide practical starting points. Integrate these tools into your development workflow, adapt them to your specific requirements, and build ChatGPT applications that meet the highest information security standards.


Related Resources:

  • SOC 2 Compliance for ChatGPT Apps
  • GDPR Compliance for ChatGPT Applications
  • PCI DSS Compliance for Payment Processing Apps
  • HIPAA Compliance for Healthcare ChatGPT Apps
  • Zero Trust Architecture for ChatGPT Apps
  • Security Incident Response Planning
  • MakeAIHQ Security Features

External Resources: