Files
aitbc/tests/security/test_cors_configuration.py
aitbc 13ada12b49 Security fixes: wildcard CORS, JWT auth, zero-address fallback
Phase 1 security remediation from codebase analysis:

CORS fixes:
- Replace wildcard CORS with safe localhost defaults in agent-coordinator
- Replace wildcard CORS with safe localhost defaults in marketplace
- Fix 8 additional wildcard CORS instances in coordinator-api apps:
  - hermes_enhanced_app.py
  - api_gateway.py
  - modality_optimization_app.py
  - multimodal_app.py
  - gpu_multimodal_app.py
  - marketplace_enhanced_app.py
  - advanced_ai_service.py
  - adaptive_learning_app.py
- Add CORS configuration security tests

Blockchain-node auth fixes:
- JWT authentication now fails closed with clear error message
- X-Wallet-Address already gated behind TRUST_X_WALLET_ADDRESS env var
- Remove zero-address fallback from arbitration vote submission
- Add regression test for zero-address rejection in arbitration

Tests:
- Update dispute auth tests to reflect new JWT error message
- Add test_arbitration_vote_zero_address_rejected
- Add test_cors_configuration.py with 5 CORS validation tests
2026-05-24 19:31:26 +02:00

136 lines
5.1 KiB
Python

"""
CORS configuration security tests.
Validates that wildcard CORS is not used with allow_credentials=True.
"""
import pytest
import os
import sys
from pathlib import Path
def test_agent_coordinator_cors_rejects_wildcard():
"""Test that agent-coordinator config rejects wildcard origins"""
repo_root = Path(__file__).resolve().parents[2]
agent_coordinator_src = repo_root / "apps" / "agent-coordinator" / "src"
if str(agent_coordinator_src) not in sys.path:
sys.path.insert(0, str(agent_coordinator_src))
# Set required secret_key to avoid validation error
os.environ["SECRET_KEY"] = "test_secret_key_for_testing"
from app.config import validated_cors_origins
with pytest.raises(ValueError, match="Wildcard CORS origins are not allowed"):
validated_cors_origins(["*"])
# Clean up
os.environ.pop("SECRET_KEY", None)
def test_agent_coordinator_cors_accepts_localhost():
"""Test that agent-coordinator config accepts localhost origins"""
repo_root = Path(__file__).resolve().parents[2]
agent_coordinator_src = repo_root / "apps" / "agent-coordinator" / "src"
if str(agent_coordinator_src) not in sys.path:
sys.path.insert(0, str(agent_coordinator_src))
# Set required secret_key to avoid validation error
os.environ["SECRET_KEY"] = "test_secret_key_for_testing"
from app.config import validated_cors_origins
origins = [
"http://localhost:8001",
"http://localhost:9001",
"http://127.0.0.1:8001",
]
result = validated_cors_origins(origins)
assert result == origins
# Clean up
os.environ.pop("SECRET_KEY", None)
def test_marketplace_cors_rejects_wildcard():
"""Test that marketplace rejects wildcard origins via environment variable"""
repo_root = Path(__file__).resolve().parents[2]
marketplace_src = repo_root / "apps" / "marketplace"
if str(marketplace_src) not in sys.path:
sys.path.insert(0, str(marketplace_src))
# Set environment variable with wildcard
os.environ["AITBC_MARKETPLACE_CORS_ORIGINS"] = "*"
# The marketplace module raises ValueError on import when wildcard is set
# This is the expected behavior
with pytest.raises(ValueError, match="Wildcard CORS origins are not allowed"):
import importlib.util
spec = importlib.util.spec_from_file_location("agent_marketplace", marketplace_src / "agent_marketplace.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Clean up
os.environ.pop("AITBC_MARKETPLACE_CORS_ORIGINS", None)
def test_marketplace_cors_accepts_localhost():
"""Test that marketplace accepts localhost origins via environment variable"""
repo_root = Path(__file__).resolve().parents[2]
marketplace_src = repo_root / "apps" / "marketplace"
if str(marketplace_src) not in sys.path:
sys.path.insert(0, str(marketplace_src))
os.environ["AITBC_MARKETPLACE_CORS_ORIGINS"] = "http://localhost:8001,http://localhost:9001"
# Import the function directly from the file
import importlib.util
spec = importlib.util.spec_from_file_location("agent_marketplace", marketplace_src / "agent_marketplace.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
result = module.get_cors_origins()
assert "http://localhost:8001" in result
assert "http://localhost:9001" in result
# Clean up
os.environ.pop("AITBC_MARKETPLACE_CORS_ORIGINS", None)
def test_no_wildcard_cors_in_coordinator_api_apps():
"""Scan coordinator-api apps for wildcard CORS with credentials"""
import re
repo_root = Path(__file__).resolve().parents[2]
coordinator_src = repo_root / "apps" / "coordinator-api" / "src"
files_to_check = [
coordinator_src / "app" / "contexts" / "hermes" / "routers" / "hermes_enhanced_app.py",
coordinator_src / "app" / "services" / "enterprise_integration" / "api_gateway.py",
coordinator_src / "app" / "services" / "modality_optimization_app.py",
coordinator_src / "app" / "services" / "multimodal_app.py",
coordinator_src / "app" / "services" / "gpu_multimodal_app.py",
coordinator_src / "app" / "routers" / "marketplace_enhanced_app.py",
coordinator_src / "app" / "services" / "advanced_ai_service.py",
coordinator_src / "app" / "services" / "adaptive_learning_app.py",
]
wildcard_pattern = re.compile(r'allow_origins\s*=\s*\["\*"\]')
credentials_pattern = re.compile(r'allow_credentials\s*=\s*True')
for file_path in files_to_check:
if not file_path.exists():
continue
content = file_path.read_text()
has_wildcard = wildcard_pattern.search(content) is not None
has_credentials = credentials_pattern.search(content) is not None
# If both wildcard and credentials are present, fail the test
if has_wildcard and has_credentials:
pytest.fail(f"File {file_path} contains wildcard CORS with credentials enabled")