Files
gh-hirefrank-hirefrank-mark…/skills/cors-configuration-validator/SKILL.md
2025-11-29 18:45:50 +08:00

12 KiB

name, description, triggers
name description triggers
cors-configuration-validator Automatically validates Cloudflare Workers CORS configuration, ensuring proper headers, OPTIONS handling, and origin validation for cross-origin requests
Response creation
API endpoints
cross-origin patterns
CORS headers

CORS Configuration Validator SKILL

Activation Patterns

This SKILL automatically activates when:

  • new Response() objects are created
  • CORS-related headers are set or modified
  • API endpoints that serve cross-origin requests
  • OPTIONS method handling is detected
  • Cross-origin request patterns are identified

Expertise Provided

Workers-Specific CORS Validation

  • Header Validation: Ensures all required CORS headers are present
  • OPTIONS Handling: Validates preflight request handling
  • Origin Validation: Checks for proper origin validation logic
  • Method Validation: Ensures correct allowed methods
  • Header Validation: Validates allowed headers configuration
  • Security: Prevents overly permissive CORS configurations

Specific Checks Performed

CORS Anti-Patterns

// These patterns trigger immediate alerts:
// Missing CORS headers
export default {
  async fetch(request: Request, env: Env) {
    return new Response(JSON.stringify(data));
    // Browsers will block cross-origin requests!
  }
}

// Overly permissive for authenticated APIs
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',  // ANY origin can call!
  'Access-Control-Allow-Credentials': 'true'  // With credentials!
};

CORS Best Practices

// These patterns are validated as correct:
// Proper CORS with origin validation
function getCorsHeaders(origin: string) {
  const allowedOrigins = ['https://app.example.com', 'https://example.com'];
  const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0];
  
  return {
    'Access-Control-Allow-Origin': allowOrigin,
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400',
  };
}

export default {
  async fetch(request: Request, env: Env) {
    const origin = request.headers.get('Origin') || '';
    
    if (request.method === 'OPTIONS') {
      return new Response(null, { headers: getCorsHeaders(origin) });
    }
    
    const response = new Response(JSON.stringify(data));
    Object.entries(getCorsHeaders(origin)).forEach(([k, v]) => {
      response.headers.set(k, v);
    });
    
    return response;
  }
}

Integration Points

Complementary to Existing Components

  • cloudflare-security-checker SKILL: Handles overall security, SKILL focuses specifically on CORS
  • workers-runtime-validator SKILL: Ensures runtime compatibility, SKILL validates CORS patterns
  • edge-performance-oracle SKILL: Handles performance, SKILL ensures CORS doesn't impact performance

Escalation Triggers

  • Complex CORS architecture questions → cloudflare-security-sentinel agent
  • Advanced authentication with CORS → cloudflare-security-sentinel agent
  • CORS troubleshooting → cloudflare-security-sentinel agent

Validation Rules

P1 - Critical (Will Break Cross-Origin Requests)

  • Missing CORS Headers: No CORS headers on API responses
  • Missing OPTIONS Handler: No preflight request handling
  • Invalid Header Combinations: Conflicting CORS header combinations

P2 - High (Security Risk)

  • Overly Permissive Origin: Access-Control-Allow-Origin: * with credentials
  • Wildcard Methods: Access-Control-Allow-Methods: * with sensitive operations
  • Missing Origin Validation: Accepting any origin without validation

P3 - Medium (Best Practices)

  • Missing Cache Headers: No Access-Control-Max-Age for preflight caching
  • Incomplete Headers: Missing some optional but recommended headers
  • Hardcoded Origins: Origins not easily configurable

Remediation Examples

Fixing Missing CORS Headers

// ❌ Critical: No CORS headers (browsers block requests)
export default {
  async fetch(request: Request, env: Env) {
    const data = { message: 'Hello from API' };
    
    return new Response(JSON.stringify(data), {
      headers: { 'Content-Type': 'application/json' }
      // Missing CORS headers!
    });
  }
}

// ✅ Correct: Complete CORS implementation
function getCorsHeaders(origin: string) {
  const allowedOrigins = ['https://app.example.com', 'https://example.com'];
  const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0];
  
  return {
    'Access-Control-Allow-Origin': allowOrigin,
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400',
  };
}

export default {
  async fetch(request: Request, env: Env) {
    const origin = request.headers.get('Origin') || '';
    
    // Handle preflight requests
    if (request.method === 'OPTIONS') {
      return new Response(null, { headers: getCorsHeaders(origin) });
    }
    
    const data = { message: 'Hello from API' };
    
    return new Response(JSON.stringify(data), {
      headers: {
        'Content-Type': 'application/json',
        ...getCorsHeaders(origin)
      }
    });
  }
}

Fixing Overly Permissive CORS

// ❌ High: Overly permissive for authenticated API
export default {
  async fetch(request: Request, env: Env) {
    const corsHeaders = {
      'Access-Control-Allow-Origin': '*',  // ANY origin!
      'Access-Control-Allow-Credentials': 'true',  // With credentials!
      'Access-Control-Allow-Methods': '*',  // ANY method!
    };
    
    // This allows any website to make authenticated requests!
    return new Response('Sensitive data', { headers: corsHeaders });
  }
}

// ✅ Correct: Secure CORS for authenticated API
function getSecureCorsHeaders(origin: string) {
  const allowedOrigins = [
    'https://app.example.com',
    'https://admin.example.com',
    'https://example.com'
  ];
  
  // Only allow known origins
  const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0];
  
  return {
    'Access-Control-Allow-Origin': allowOrigin,
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',  // Specific methods
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Max-Age': '86400',
  };
}

export default {
  async fetch(request: Request, env: Env) {
    const origin = request.headers.get('Origin') || '';
    
    // Verify authentication
    const authHeader = request.headers.get('Authorization');
    if (!authHeader || !isValidAuth(authHeader)) {
      return new Response('Unauthorized', { status: 401 });
    }
    
    return new Response('Sensitive data', {
      headers: getSecureCorsHeaders(origin)
    });
  }
}

Fixing Missing OPTIONS Handler

// ❌ Critical: No OPTIONS handling (preflight fails)
export default {
  async fetch(request: Request, env: Env) {
    if (request.method === 'POST') {
      // Handle POST request
      return new Response('POST handled');
    }
    
    return new Response('Method not allowed', { status: 405 });
  }
}

// ✅ Correct: Proper OPTIONS handling
export default {
  async fetch(request: Request, env: Env) {
    const origin = request.headers.get('Origin') || '';
    
    // Handle preflight requests
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: {
          'Access-Control-Allow-Origin': origin,
          'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
          'Access-Control-Allow-Headers': 'Content-Type, Authorization',
          'Access-Control-Max-Age': '86400',
        }
      });
    }
    
    if (request.method === 'POST') {
      return new Response('POST handled', {
        headers: {
          'Access-Control-Allow-Origin': origin,
        }
      });
    }
    
    return new Response('Method not allowed', { status: 405 });
  }
}

Fixing Dynamic CORS for Different Environments

// ❌ Medium: Hardcoded origins (not flexible)
function getCorsHeaders() {
  return {
    'Access-Control-Allow-Origin': 'https://app.example.com',  // Hardcoded
    'Access-Control-Allow-Methods': 'GET, POST',
  };
}

// ✅ Correct: Configurable and secure CORS
function getCorsHeaders(origin: string, env: Env) {
  // Get allowed origins from environment
  const allowedOrigins = (env.ALLOWED_ORIGINS || 'https://app.example.com')
    .split(',')
    .map(o => o.trim());
  
  const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0];
  
  return {
    'Access-Control-Allow-Origin': allowOrigin,
    'Access-Control-Allow-Methods': env.ALLOWED_METHODS || 'GET, POST, PUT, DELETE',
    'Access-Control-Allow-Headers': env.ALLOWED_HEADERS || 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400',
  };
}

export default {
  async fetch(request: Request, env: Env) {
    const origin = request.headers.get('Origin') || '';
    
    if (request.method === 'OPTIONS') {
      return new Response(null, { headers: getCorsHeaders(origin, env) });
    }
    
    return new Response('Response', {
      headers: getCorsHeaders(origin, env)
    });
  }
}

CORS Header Reference

Essential Headers

{
  'Access-Control-Allow-Origin': 'https://example.com',  // Required
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',  // Required for preflight
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',  // Required for preflight
}
{
  'Access-Control-Max-Age': '86400',  // Cache preflight for 24 hours
  'Access-Control-Allow-Credentials': 'true',  // For cookies/auth
  'Vary': 'Origin',  // Important for caching with multiple origins
}

Security Considerations

// ❌ Don't do this for authenticated APIs:
{
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Credentials': 'true'
}

// ✅ Do this instead:
{
  'Access-Control-Allow-Origin': 'https://app.example.com',  // Specific origin
  'Access-Control-Allow-Credentials': 'true'
}

MCP Server Integration

When Cloudflare MCP server is available:

  • Query latest CORS best practices and security recommendations
  • Get current browser CORS specification updates
  • Check for common CORS vulnerabilities and mitigations

Benefits

Immediate Impact

  • Prevents CORS Errors: Catches missing headers before deployment
  • Improves Security: Prevents overly permissive CORS configurations
  • Better User Experience: Ensures cross-origin requests work properly

Long-term Value

  • Consistent CORS Standards: Ensures all APIs follow proper CORS patterns
  • Reduced Debugging Time: Immediate feedback on CORS issues
  • Security Compliance: Prevents CORS-related security vulnerabilities

Usage Examples

During Response Creation

// Developer types: new Response(data)
// SKILL immediately activates: "⚠️ HIGH: Response missing CORS headers. Cross-origin requests will be blocked by browsers."

During API Development

// Developer types: 'Access-Control-Allow-Origin': '*'
// SKILL immediately activates: "⚠️ HIGH: Overly permissive CORS with wildcard origin. Consider specific origins for security."

During Method Handling

// Developer types: if (request.method === 'POST') { ... }
// SKILL immediately activates: "⚠️ HIGH: Missing OPTIONS handler for preflight requests. Add OPTIONS method handling."

CORS Checklist

Required for Cross-Origin Requests

  • Access-Control-Allow-Origin header set
  • OPTIONS method handled for preflight requests
  • Access-Control-Allow-Methods header for preflight
  • Access-Control-Allow-Headers header for preflight

Security Best Practices

  • Origin validation (not wildcard for authenticated APIs)
  • Specific allowed methods (not wildcard)
  • Proper credentials handling
  • Environment-based origin configuration

Performance Optimization

  • Access-Control-Max-Age header set
  • Vary: Origin header for caching
  • Efficient preflight handling

This SKILL ensures CORS is configured correctly by providing immediate, autonomous validation of CORS patterns, preventing common cross-origin issues and security vulnerabilities.