Lucene search
+L

CORS Misconfiguration Scanner

🗓️ 01 Dec 2025 12:51:31Reported by KittySploitType 
kittysploit
 kittysploit
🔗 kittysploit.com👁 1 Views

CORS Misconfiguration Scanner scans for CORS flaws allowing unauthorized cross-origin requests.

Refs
Code
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from kittysploit import *
from lib.protocols.http.http_client import Http_client
from lib.scanner.http.module_result import finalize_http_scanner_run
import urllib.parse

class Module(Auxiliary, Http_client):

    __info__ = {
        'name': 'CORS Misconfiguration Scanner',
        'description': 'Scans for common CORS (Cross-Origin Resource Sharing) misconfigurations that could allow unauthorized cross-origin requests',
        'author': 'KittySploit Team',
        'tags': ['web', 'cors', 'scanner', 'security'],
    'agent': {
        'risk': 'active',
        'effects': ['network_probe'],
        'expected_requests': 2,
        'reversible': True,
        'approval_required': False,
        'produces': ['tech_hints', 'risk_signals', 'endpoints', 'params'],
        'cost': 1.0,
        'noise': 0.5,
        'value': 1.0,
        'requires':         {'min_endpoints': 0,
         'min_params': 0,
         'tech_hints_any': [],
         'tech_hints_all': [],
         'specializations_any': [],
         'risk_signals_any': [],
         'auth_session': False,
         'capabilities_any': [],
         'capabilities_all': [],
         'confidence_min': {},
         'confidence_min_any': {},
         'endpoint_pattern_any': [],
         'param_any': [],
         'api_surface_ready': False},
        'chain':         {'produces_capabilities': [{'capability': 'endpoints', 'from_detail': ''}],
         'consumes_capabilities': [],
         'option_bindings': {},
         'suggested_followups': []},
    },
    }

    def check(self):
        """
        Check if the target is accessible
        """
        try:
            response = self.http_request(method="GET", path="/")
            if response and response.status_code in [200, 301, 302, 403, 404]:
                return True
            return False
        except Exception as e:
            return False
    
    def test_cors_headers(self, origin_header):
        """
        Test CORS configuration with a specific Origin header
        
        Args:
            origin_header: The Origin header value to test
            
        Returns:
            dict: Test results including headers and vulnerability status
        """
        try:
            # Prepare custom headers with the test Origin
            custom_headers = {
                'Origin': origin_header,
                'Access-Control-Request-Method': 'GET',
                'Access-Control-Request-Headers': 'Content-Type'
            }
            
            # Send OPTIONS request (preflight)
            preflight_response = self.http_request(
                method="OPTIONS",
                path="/",
                headers=custom_headers
            )
            
            # Send GET request with Origin header
            get_response = self.http_request(
                method="GET",
                path="/",
                headers={'Origin': origin_header}
            )
            
            # Check both responses for CORS headers
            cors_headers = {}
            vulnerable = False
            vulnerability_type = None
            details = []
            
            for response in [preflight_response, get_response]:
                if response:
                    # Check for Access-Control-Allow-Origin
                    acao = response.headers.get('Access-Control-Allow-Origin', '')
                    acac = response.headers.get('Access-Control-Allow-Credentials', '')
                    acam = response.headers.get('Access-Control-Allow-Methods', '')
                    acah = response.headers.get('Access-Control-Allow-Headers', '')
                    acmax = response.headers.get('Access-Control-Max-Age', '')
                    
                    if acao:
                        cors_headers['Access-Control-Allow-Origin'] = acao
                    if acac:
                        cors_headers['Access-Control-Allow-Credentials'] = acac
                    if acam:
                        cors_headers['Access-Control-Allow-Methods'] = acam
                    if acah:
                        cors_headers['Access-Control-Allow-Headers'] = acah
                    if acmax:
                        cors_headers['Access-Control-Max-Age'] = acmax
                    
                    # Analyze for vulnerabilities
                    if acao == '*':
                        if acac.lower() == 'true':
                            vulnerable = True
                            vulnerability_type = 'Wildcard origin with credentials'
                            details.append('Access-Control-Allow-Origin is set to * with Access-Control-Allow-Credentials: true (browsers will reject this)')
                        else:
                            vulnerable = True
                            vulnerability_type = 'Wildcard origin'
                            details.append('Access-Control-Allow-Origin is set to * (allows all origins)')
                    
                    elif acao == origin_header:
                        if acac.lower() == 'true':
                            vulnerable = True
                            vulnerability_type = 'Reflected origin with credentials'
                            details.append(f'Access-Control-Allow-Origin reflects the Origin header ({origin_header}) with credentials enabled')
                        else:
                            vulnerable = True
                            vulnerability_type = 'Reflected origin'
                            details.append(f'Access-Control-Allow-Origin reflects the Origin header ({origin_header}) without validation')
                    
                    elif origin_header == 'null' and acao == 'null':
                        vulnerable = True
                        vulnerability_type = 'Null origin allowed'
                        details.append('Access-Control-Allow-Origin allows null origin')
                    
                    elif origin_header.startswith('http://') and acao == origin_header:
                        vulnerable = True
                        vulnerability_type = 'HTTP origin allowed'
                        details.append(f'Access-Control-Allow-Origin allows insecure HTTP origin: {origin_header}')
            
            return {
                'origin': origin_header,
                'vulnerable': vulnerable,
                'vulnerability_type': vulnerability_type,
                'details': details,
                'cors_headers': cors_headers,
                'status_code': get_response.status_code if get_response else None
            }
            
        except Exception as e:
            return {
                'origin': origin_header,
                'vulnerable': False,
                'error': str(e),
                'cors_headers': {}
            }
    
    def test_subdomain_bypass(self, base_domain):
        """
        Test for subdomain bypass vulnerabilities
        
        Args:
            base_domain: Base domain to test (e.g., example.com)
            
        Returns:
            dict: Test results
        """
        try:
            # Extract base domain from target
            parsed = urllib.parse.urlparse(self.target)
            domain = parsed.netloc.split(':')[0]
            
            # Test various subdomain combinations
            test_origins = [
                f'http://evil.{domain}',
                f'https://evil.{domain}',
                f'http://subdomain.{domain}',
                f'https://subdomain.{domain}',
                f'http://{domain}.evil.com',
                f'https://{domain}.evil.com',
            ]
            
            results = []
            for origin in test_origins:
                result = self.test_cors_headers(origin)
                if result.get('vulnerable'):
                    results.append(result)
            
            return results
            
        except Exception as e:
            return []
    
    def run(self):
        """
        Execute the CORS misconfiguration scan
        """
        self.vulnerabilities = []
        self.test_results = []
        
        print_status("Starting CORS misconfiguration scan...")
        print_info(f"Target: {self.target}")
        print_info("")
        
        # List of origins to test
        test_origins = [
            '*',  # Wildcard
            'null',  # Null origin
            'https://evil.com',  # External domain
            'http://evil.com',  # External HTTP domain
            'https://attacker.com',  # Another external domain
            'http://localhost',  # Localhost
            'http://127.0.0.1',  # Local IP
            'https://example.com',  # Example domain
        ]
        
        # Add target's own origin variations
        try:
            parsed = urllib.parse.urlparse(self.target)
            domain = parsed.netloc.split(':')[0]
            scheme = parsed.scheme or 'http'
            
            # Add variations of the target domain
            test_origins.extend([
                f'{scheme}://{domain}',
                f'http://{domain}',
                f'https://{domain}',
                f'{scheme}://www.{domain}',
                f'http://www.{domain}',
                f'https://www.{domain}',
            ])
        except:
            pass
        
        print_status(f"Testing {len(test_origins)} origin configurations...")
        print_info("")
        
        vulnerable_count = 0
        
        # Test each origin
        for i, origin in enumerate(test_origins, 1):
            print_info(f"[{i}/{len(test_origins)}] Testing origin: {origin}")
            
            result = self.test_cors_headers(origin)
            self.test_results.append(result)
            
            if result.get('vulnerable'):
                vulnerable_count += 1
                print_success(f"\n[!] VULNERABILITY FOUND: {result.get('vulnerability_type')}")
                print_info(f"    Origin: {origin}")
                print_info(f"    Status Code: {result.get('status_code', 'N/A')}")
                
                if result.get('details'):
                    for detail in result['details']:
                        print_warning(f"    {detail}")
                
                if result.get('cors_headers'):
                    print_info("    CORS Headers:")
                    for header, value in result['cors_headers'].items():
                        print_info(f"      {header}: {value}")
                
                print_info("")
                
                self.vulnerabilities.append(result)
        
        # Test subdomain bypass
        print_info("")
        print_status("Testing subdomain bypass scenarios...")
        try:
            parsed = urllib.parse.urlparse(self.target)
            domain = parsed.netloc.split(':')[0]
            subdomain_results = self.test_subdomain_bypass(domain)
            
            if subdomain_results:
                for result in subdomain_results:
                    if result.get('vulnerable'):
                        vulnerable_count += 1
                        print_success(f"\n[!] SUBDOMAIN BYPASS: {result.get('vulnerability_type')}")
                        print_info(f"    Origin: {result.get('origin')}")
                        self.vulnerabilities.append(result)
        except Exception as e:
            print_debug(f"Subdomain bypass test error: {str(e)}")
        
        # Summary
        print_info("")
        print_status("=" * 60)
        print_status("CORS Scan Summary")
        print_status("=" * 60)
        print_info(f"Total origins tested: {len(self.test_results)}")
        print_info(f"Vulnerabilities found: {vulnerable_count}")
        print_status("=" * 60)
        
        if self.vulnerabilities:
            print_success("\nVulnerabilities detected:")
            print_info("")
            
            # Group by vulnerability type
            vuln_groups = {}
            for vuln in self.vulnerabilities:
                vuln_type = vuln.get('vulnerability_type', 'Unknown')
                if vuln_type not in vuln_groups:
                    vuln_groups[vuln_type] = []
                vuln_groups[vuln_type].append(vuln)
            
            # Display grouped results
            table_data = []
            for vuln_type, vulns in vuln_groups.items():
                origins = [v.get('origin') for v in vulns]
                table_data.append([
                    vuln_type,
                    ', '.join(origins[:3]) + ('...' if len(origins) > 3 else ''),
                    len(vulns)
                ])
            
            if table_data:
                print_table(['Vulnerability Type', 'Affected Origins', 'Count'], table_data)
        return finalize_http_scanner_run(
            self,
            self.vulnerabilities,
            title="CORS Misconfiguration",
            severity="medium",
            category="cors",
            findings_key="cors_findings",
            dedupe_keys=("origin", "vulnerability_type"),
        )

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

16 Jul 2026 12:39Current
5.8Medium risk
Vulners AI Score5.8
1