UnlockOS Developers
← Back to blog
🔐

Security Hardening and State Management in UnlockOS

Mar 2, 2026Mar 8, 2026
6 min
6 commits
Depth 8/10
securitystate-managementvalidationerror-handling

Security Hardening and State Management in UnlockOS

Introduction

Building trust in a security-critical system like UnlockOS requires meticulous attention to security vulnerabilities, robust state management, and defensive programming practices. Recent improvements to our iCal integration and checkout flow demonstrate key patterns for maintaining system integrity in property access management.

Critical Security Issue Resolution

When integrating external calendar systems like Airbnb's iCal feeds, security vulnerabilities can emerge that compromise the entire access control system. Our recent security audit identified critical and high-severity issues that required immediate remediation.

Input Validation and Sanitization

External calendar data represents an untrusted input source that must be rigorously validated:

interface ICalEventValidator {
  validateEventData(event: unknown): ValidationResult<CalendarEvent>;
  sanitizeDescription(description: string): string;
  validateDateRange(start: Date, end: Date): boolean;
}

class SecureICalParser implements ICalEventValidator {
  validateEventData(event: unknown): ValidationResult<CalendarEvent> {
    if (!event || typeof event !== 'object') {
      return { isValid: false, error: 'Invalid event structure' };
    }
    
    const eventObj = event as Record<string, unknown>;
    
    // Validate required fields with strict type checking
    if (!this.isValidDate(eventObj.dtstart) || !this.isValidDate(eventObj.dtend)) {
      return { isValid: false, error: 'Invalid date format' };
    }
    
    // Sanitize string fields to prevent injection attacks
    const sanitizedEvent: CalendarEvent = {
      dtstart: new Date(eventObj.dtstart as string),
      dtend: new Date(eventObj.dtend as string),
      summary: this.sanitizeDescription(eventObj.summary as string),
      uid: this.validateUID(eventObj.uid as string)
    };
    
    return { isValid: true, data: sanitizedEvent };
  }
  
  private sanitizeDescription(description: string): string {
    // Remove potentially dangerous characters and limit length
    return description
      .replace(/[<>"'&]/g, '')
      .substring(0, 255)
      .trim();
  }
}

Authentication State Verification

Every external integration must verify authentication state before processing sensitive operations:

class AuthenticatedICalProcessor {
  async processCalendarSync(
    userId: string, 
    calendarUrl: string
  ): Promise<ProcessingResult> {
    // Verify user authentication and authorization
    const authResult = await this.authService.verifyUserAccess(userId, 'calendar:sync');
    if (!authResult.isValid) {
      await this.auditLogger.logSecurityEvent({
        event: 'unauthorized_calendar_access',
        userId,
        timestamp: new Date(),
        severity: 'HIGH'
      });
      throw new UnauthorizedError('Invalid authentication for calendar sync');
    }
    
    // Rate limiting to prevent abuse
    const rateLimitResult = await this.rateLimiter.checkLimit(userId, 'calendar_sync');
    if (!rateLimitResult.allowed) {
      throw new RateLimitError('Calendar sync rate limit exceeded');
    }
    
    return this.processSyncWithValidation(calendarUrl);
  }
}

State Machine Reliability: Preventing Zombie States

The checkout flow revealed a critical state management issue where UI components could enter "zombie states" - remaining active after the underlying business logic had completed. This pattern threatens system reliability.

Finite State Machine Implementation

import { createMachine, interpret } from 'xstate';

type CheckoutEvent = 
  | { type: 'START_CHECKOUT' }
  | { type: 'AUTO_CHECKOUT_TRIGGERED' }
  | { type: 'MANUAL_CHECKOUT' }
  | { type: 'CLEANUP_REQUIRED' }
  | { type: 'FORCE_RESET' };

interface CheckoutContext {
  checkoutId: string;
  startTime: Date;
  modalVisible: boolean;
  cleanupCompleted: boolean;
}

const checkoutStateMachine = createMachine<CheckoutContext, CheckoutEvent>({
  id: 'checkout',
  initial: 'idle',
  context: {
    checkoutId: '',
    startTime: new Date(),
    modalVisible: false,
    cleanupCompleted: false
  },
  states: {
    idle: {
      on: {
        START_CHECKOUT: 'checking_out'
      }
    },
    checking_out: {
      entry: 'showModal',
      on: {
        AUTO_CHECKOUT_TRIGGERED: 'auto_completing',
        MANUAL_CHECKOUT: 'manual_completing'
      }
    },
    auto_completing: {
      invoke: {
        src: 'performAutoCheckout',
        onDone: 'cleaning_up',
        onError: 'error_recovery'
      }
    },
    cleaning_up: {
      entry: 'hideModal',
      invoke: {
        src: 'cleanupResources',
        onDone: 'completed',
        onError: 'force_cleanup'
      }
    },
    completed: {
      entry: 'markCleanupComplete',
      type: 'final'
    },
    force_cleanup: {
      entry: ['forceHideModal', 'forceCleanup'],
      always: 'completed'
    },
    error_recovery: {
      on: {
        FORCE_RESET: 'force_cleanup'
      }
    }
  }
});

Guaranteed Resource Cleanup

class CheckoutStateManager {
  private stateMachine = interpret(checkoutStateMachine.withConfig({
    actions: {
      showModal: (context) => {
        this.modalController.show(context.checkoutId);
        this.scheduleTimeoutCleanup(context.checkoutId);
      },
      hideModal: () => {
        this.modalController.hide();
        this.clearTimeouts();
      },
      forceHideModal: () => {
        // Guaranteed cleanup even if normal flow fails
        this.modalController.forceDestroy();
        this.clearAllReferences();
      }
    },
    services: {
      performAutoCheckout: async (context) => {
        const result = await this.checkoutService.executeAutoCheckout(context.checkoutId);
        await this.auditLogger.logCheckoutEvent({
          type: 'auto_checkout_completed',
          checkoutId: context.checkoutId,
          duration: Date.now() - context.startTime.getTime()
        });
        return result;
      },
      cleanupResources: async () => {
        await Promise.all([
          this.cacheManager.clearCheckoutData(),
          this.eventListeners.removeAllCheckoutListeners(),
          this.timers.clearCheckoutTimers()
        ]);
      }
    }
  }));
  
  private scheduleTimeoutCleanup(checkoutId: string): void {
    // Failsafe: Force cleanup after maximum allowed time
    setTimeout(() => {
      if (this.stateMachine.getSnapshot().value !== 'completed') {
        this.stateMachine.send('FORCE_RESET');
      }
    }, 30000); // 30 second maximum
  }
}

Comprehensive Audit Logging

Every security-relevant operation requires detailed audit logging for compliance and incident response:

interface SecurityAuditEvent {
  eventType: 'checkout_completion' | 'calendar_sync' | 'access_granted' | 'security_violation';
  userId: string;
  propertyId: string;
  timestamp: Date;
  severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
  metadata: Record<string, unknown>;
  ipAddress?: string;
  userAgent?: string;
}

class SecurityAuditLogger {
  async logCheckoutCompletion(event: CheckoutCompletionEvent): Promise<void> {
    const auditEvent: SecurityAuditEvent = {
      eventType: 'checkout_completion',
      userId: event.userId,
      propertyId: event.propertyId,
      timestamp: new Date(),
      severity: 'MEDIUM',
      metadata: {
        checkoutMethod: event.method,
        duration: event.duration,
        receiptGenerated: event.receiptId ? true : false,
        emailSent: event.emailDelivered
      }
    };
    
    // Encrypt sensitive data before storage
    const encryptedEvent = await this.encryptSensitiveFields(auditEvent);
    await this.auditStore.persistEvent(encryptedEvent);
    
    // Real-time monitoring for anomalies
    await this.anomalyDetector.analyzeEvent(auditEvent);
  }
}

Email Security and Template Validation

Checkout completion emails contain sensitive property and access information requiring secure template handling:

interface SecureEmailTemplate {
  templateId: string;
  allowedVariables: string[];
  sanitizationRules: Record<string, (value: unknown) => string>;
}

class SecureEmailRenderer {
  async renderCheckoutReceipt(
    template: SecureEmailTemplate,
    checkoutData: CheckoutData
  ): Promise<string> {
    // Validate all template variables are allowlisted
    const templateVars = this.extractTemplateVariables(template);
    const unauthorizedVars = templateVars.filter(
      v => !template.allowedVariables.includes(v)
    );
    
    if (unauthorizedVars.length > 0) {
      throw new TemplateSecurityError(
        `Unauthorized template variables: ${unauthorizedVars.join(', ')}`
      );
    }
    
    // Sanitize all data before template rendering
    const sanitizedData = this.sanitizeTemplateData(
      checkoutData,
      template.sanitizationRules
    );
    
    return this.templateEngine.render(template.templateId, sanitizedData);
  }
  
  private sanitizeTemplateData(
    data: CheckoutData,
    rules: Record<string, (value: unknown) => string>
  ): Record<string, string> {
    const result: Record<string, string> = {};
    
    for (const [key, value] of Object.entries(data)) {
      const sanitizer = rules[key] || this.defaultSanitizer;
      result[key] = sanitizer(value);
    }
    
    return result;
  }
}

Summary

Security-critical systems require defense-in-depth approaches combining multiple protective layers:

  • Input Validation: Rigorous validation and sanitization of all external data sources
  • State Machine Reliability: Finite state machines with guaranteed cleanup prevent zombie states
  • Comprehensive Auditing: Every security event logged with encryption and anomaly detection
  • Template Security: Allowlisted variables and sanitization prevent injection attacks
  • Authentication Verification: Every operation validates current authentication state

These patterns ensure UnlockOS maintains the highest security standards while providing reliable property access management.

Key Insights

1
Security

External Data Validation

All external calendar data undergoes strict validation and sanitization to prevent injection attacks and system compromise

2
State Management

Zombie State Prevention

Finite state machines with guaranteed cleanup paths prevent UI components from remaining in invalid states after business logic completion

3
Audit Logging

Comprehensive Security Logging

Every security-relevant operation generates encrypted audit logs with real-time anomaly detection for compliance and incident response

4
Template Security

Secure Email Rendering

Email templates use allowlisted variables and sanitization rules to prevent injection attacks while handling sensitive checkout data