HIGH cors wildcarddjangomutual tls

Cors Wildcard in Django with Mutual Tls

Cors Wildcard in Django with Mutual Tls — how this specific combination creates or exposes the vulnerability

A CORS wildcard (Access-Control-Allow-Origin: *) combined with Mutual TLS (mTLS) in Django can weaken origin-based isolation. With mTLS, the server validates the client certificate, but CORS is a browser-enforced mechanism. If you configure Django to respond with a wildcard Access-Control-Allow-Origin while also requiring client certificates, a browser may still allow a malicious page from any origin to make authenticated requests, because the browser completes the TLS handshake (presenting a valid client cert) and then applies CORS rules. If the wildcard is too permissive, the browser will accept the response, potentially exposing authenticated sessions or sensitive endpoints to a malicious site that can supply a valid client certificate (e.g., via a compromised device or a user who installed a rogue CA).

Consider an API endpoint that returns sensitive data and uses mTLS for client authentication. If CORS_ALLOW_ALL_ORIGINS = True (or Access-Control-Allow-Origin: *) and the view relies on mTLS for authorization, any origin that can provide a valid client certificate (e.g., through a user-installed certificate) can read the response. This blurs the boundary between transport-layer authentication and application-layer authorization. While mTLS ensures the client is trusted, CORS should still restrict which origins are permitted in the browser. A wildcard in this context allows any site to initiate requests that the browser will accept, making it easier for an attacker to chain mTLS client credentials with a malicious frontend to perform actions on behalf of the user, such as reading PII or triggering state changes.

Moreover, if preflight requests (OPTIONS) respond with a wildcard and allow any headers or methods, an attacker can probe which HTTP verbs and headers the mTLS-protected endpoint supports, aiding in crafting further attacks. In Django, common misconfiguration is using django-cors-headers with CORS_ALLOW_ALL_ORIGINS = True while also enforcing mTLS at the load balancer or application layer. This setup doesn’t break mTLS, but it weakens the effectiveness of origin-based security in the browser, because the CORS policy is more permissive than intended.

Mutual Tls-Specific Remediation in Django — concrete code fixes

Remediate by tightening CORS to specific origins and ensuring mTLS validation is correctly integrated. Avoid wildcards when mTLS is used for authentication-like decisions. Below are concrete Django settings and view examples.

  • Install and configure django-cors-headers with specific origins:
# settings.py
CORS_ALLOWED_ORIGINS = [
    "https://trusted.example.com",
    "https://app.example.com",
]

# Only allow specific methods and headers for preflight
CORS_ALLOW_METHODS = [
    "GET",
    "POST",
    "PUT",
    "DELETE",
]
CORS_ALLOW_HEADERS = [
    "authorization",
    "content-type",
    "x-requested-with",
]

# Ensure cookies are not sent cross-origin unless necessary
CORS_ALLOW_CREDENTIALS = True  # only if you need to send cookies
  • Enforce mTLS at the server/reverse proxy and map the client certificate to a user in Django. For example, using a middleware that reads the verified client certificate from the request:
# middleware.py
import ssl
from django.http import HttpResponseForbidden
from django.conf import settings

def get_cert_subject_dn(cert):
    # Example: extract subject DN from the PEM certificate
    import ssl
    from cryptography import x509
    from cryptography.hazmat.backends import default_backend
    cert_obj = x509.load_pem_x509_certificate(cert.encode('utf-8'), default_backend())
    subject = cert_obj.subject.rfc4514_string()
    return subject

class MutualTlsAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        cert = request.META.get('SSL_CLIENT_CERT')
        if not cert:
            return HttpResponseForbidden('Client certificate required')
        subject = get_cert_subject_dn(cert)
        # Map subject to a Django user (example logic)
        user = self.map_subject_to_user(subject)
        if user is None:
            return HttpResponseForbidden('Certificate not authorized')
        request.user = user
        return self.get_response(request)

    def map_subject_to_user(self, subject):
        # Implement your mapping, e.g., look up by CN or OU
        from django.contrib.auth.models import User
        # Example: subject like 'CN=alice,O=Example'
        if 'CN=alice' in subject:
            return User.objects.get(username='alice')
        return None
  • Ensure the middleware is placed after authentication middleware and HTTPS is enforced:
# settings.py
MIDDLEWARE = [
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'yourapp.middleware.MutualTlsAuthMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # should be near top but after security middlewares
    ...
]

# Require HTTPS in production
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
  • In your views, rely on request.user set by the middleware instead of re-checking the certificate. Combine with Django’s permission system:
# views.py
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required

@login_required
def sensitive_data(request):
    # request.user is already validated via mTLS middleware
    data = {"message": "confidential", "user": request.user.username}
    return JsonResponse(data)

By aligning CORS origins with your trusted frontends and enforcing mTLS via middleware, you maintain defense-in-depth: mTLS provides strong client authentication, and CORS ensures only permitted origins can access the browser context.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Does using a CORS wildcard with mTLS break TLS encryption?
No, CORS does not affect TLS encryption. mTLS still provides transport-layer authentication and confidentiality. The risk is about browser-origin policy: a wildcard allows any origin to make authenticated requests in the browser if a valid client certificate is supplied, potentially exposing endpoints to malicious sites.
Should I disable CORS when using mTLS?
Not necessarily. You can keep CORS for browser-based clients, but avoid wildcards. Specify exact origins that are trusted. For non-browser clients (e.g., mobile apps), CORS is irrelevant; mTLS at the transport layer remains the primary control.