HIGH dangling dnsdjangobasic auth

Dangling Dns in Django with Basic Auth

Dangling Dns in Django with Basic Auth — how this specific combination creates or exposes the vulnerability

A dangling DNS record occurs when a hostname (e.g., legacy.internal.example.com) still resolves to an IP address but is no longer actively managed or intentionally configured by the application owner. In a Django project that uses HTTP Basic Auth, this combination can unintentionally expose administrative or internal endpoints to external actors if the DNS entry points to a public-facing server while the Django app erroneously trusts the hostname for access control.

When Basic Auth is used in Django, access decisions often rely on a combination of credentials (username and password) and request metadata such as the HTTP Host header, referer, or resolved origin IP. If the Django configuration includes hostname-based allowlists (e.g., permitting access only from certain domains) and a dangling DNS record resolves to the same server, an attacker who can route traffic to that IP may bypass intended network-level restrictions. This happens because the application validates the hostname against the dangling record, which still resolves, instead of also enforcing strict credential validation and origin checks.

Consider a Django service that protects an internal admin interface with Basic Auth and also checks that requests originate from an internal domain like admin.internal.example.com. If admin.internal.example.com becomes a dangling DNS record pointing to the public server, an unauthenticated external request that manually sets the Host header to admin.internal.example.com might appear to originate from an allowed domain. Without robust server-side enforcement of authentication and strict hostname validation, the dangling record effectively becomes an unintended entry point.

Moreover, in environments where DNS changes lag behind infrastructure changes, developers might assume a hostname is internal-only, but if it still resolves, the assumption creates a false sense of security. Basic Auth protects the endpoint only if the client can provide valid credentials; a dangling DNS record does not weaken the authentication mechanism itself but can mislead developers into thinking network-level controls are sufficient. The risk is compounded if the view or middleware relies on request.get_host() to make authorization decisions without verifying that the host is truly authoritative for the service.

To detect this specific risk profile, middleBrick scans unauthenticated attack surfaces and validates assumptions about hostname-based controls alongside Basic Auth behavior. By cross-referencing OpenAPI/Swagger specifications with runtime requests, it identifies mismatches between intended access boundaries and actual DNS reachability, including dangling records that could be abused in conjunction with weak hostname checks.

Basic Auth-Specific Remediation in Django — concrete code fixes

Remediation focuses on ensuring that Basic Auth is the primary gatekeeper and that hostname-based checks are strict, explicit, and never relied upon alone. Always treat the Host header as untrusted for access control. Use Django’s built-in authentication mechanisms and avoid custom host allowlists for security decisions.

Example of secure Django Basic Auth using a decorator that enforces credentials without relying on hostname checks for access decisions:

from django.contrib.auth import authenticate
from django.http import HttpResponse, HttpResponseForbidden
from functools import wraps
def basic_auth_required(view_func):
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        auth = request.META.get('HTTP_AUTHORIZATION', '')
        if not auth.lower().startswith('basic '):
            return HttpResponse('Unauthorized', status=401, headers={'WWW-Authenticate': 'Basic realm="Access"'})
        import base64
        try:
            decoded = base64.b64decode(auth.split(' ', 1)[1]).decode('utf-8')
            username, password = decoded.split(':', 1)
        except Exception:
            return HttpResponseForbidden()
        user = authenticate(request, username=username, password=password)
        if user is not None and user.is_active:
            return view_func(request, *args, **kwargs)
        return HttpResponseForbidden()
    return _wrapped_view
@basic_auth_required
def admin_view(request):
    return HttpResponse('Admin area')

If you must incorporate hostname checks, validate against a hardcoded set of canonical names and ensure DNS records are actively managed:

from django.http import HttpResponseForbidden
ALLOWED_HOSTS = {'api.example.com', 'app.example.com'}
def strict_host_check(view_func):
    def _wrapped_view(request, *args, **kwargs):
        host = request.get_host().split(':')[0]
        if host not in ALLOWED_HOSTS:
            return HttpResponseForbidden()
        return view_func(request, *args, **kwargs)
    return _wrapped_view
@basic_auth_required
@strict_host_check
def protected_view(request):
    return HttpResponse('Secured')

Additionally, remove any dangling DNS records from your zones and verify that internal hostnames do not resolve to public endpoints. Use middleware to log unexpected Host headers for further investigation, but do not use them to grant access.

middleBrick’s LLM/AI Security checks and OpenAPI analysis can surface scenarios where hostname-based logic interacts with authentication mechanisms, providing prioritized findings and remediation guidance to address these edge cases.

Frequently Asked Questions

Can Basic Auth alone protect an endpoint if the DNS record is dangling?
No. Basic Auth protects only if valid credentials are provided. A dangling DNS record can mislead developers into assuming network-level restrictions are sufficient, but it does not weaken authentication. Always enforce credentials explicitly and avoid relying on hostname checks for access control.
How does middleBrick detect risks involving dangling DNS records and Basic Auth in Django?
middleBrick performs unauthenticated scans that test hostname-based assumptions alongside authentication behavior. By resolving hostnames, validating against OpenAPI/Swagger definitions, and simulating requests with varied Host headers, it identifies configurations where dangling records could bypass intended controls.