HIGH dangling dnsflaskbasic auth

Dangling Dns in Flask with Basic Auth

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

A dangling DNS record occurs when a hostname (for example, legacy.api.example.com) points to an IP that no longer hosts the intended service, yet the DNS entry remains. In a Flask application that uses HTTP Basic Auth, this combination can expose internal or unintended endpoints if the application resolves the dangling name at runtime and uses the result for routing or authorization decisions.

Consider a Flask app that validates incoming requests by checking a hostname against a Basic Auth credential. If the app resolves a user-supplied host header or a configured backend hostname (e.g., via socket.gethostbyname or a reverse proxy that forwards to the dangling record), the request may be directed to an unexpected server. That server might have a relaxed security posture, different authentication handling, or even be controlled by an attacker who has registered the now-dangling IP. Because Basic Auth sends credentials in an easily decodable header, an attacker who can influence DNS resolution could redirect authentication traffic and potentially observe or manipulate credentials or session tokens.

In practice, this risk arises when:

  • Flask uses a hardcoded or configuration-derived hostname that later becomes dangling, and the app does not validate or sanitize host inputs.
  • Reverse proxies or load balancers forward requests based on a header like Host without strict hostname allowlists, enabling host header attacks that exploit the dangling record.
  • Service discovery or internal routing relies on DNS names that are not actively maintained, causing the app to route authenticated requests to unpredictable endpoints.

Because the scan checks for Authentication weaknesses and Input Validation issues in parallel, middleBrick will flag this as a finding under both categories. The scanner tests whether the application resolves hostnames dynamically and whether Basic Auth is applied consistently to all routes, highlighting cases where dangling DNS could lead to authorization bypass or credential exposure.

Basic Auth-Specific Remediation in Flask — concrete code fixes

To mitigate risks related to dangling DNS in Flask when using HTTP Basic Auth, focus on removing dynamic hostname resolution, enforcing strict host validation, and ensuring credentials are protected in transit. Below are concrete, safe patterns.

1. Avoid dynamic DNS lookups for authentication

Do not resolve hostnames at runtime to decide access control. Instead, use explicit IPs or stable, verified endpoints. If you must use host-based routing, validate against a strict allowlist.

2. Validate the Host header

Use a before-request hook to reject requests with unexpected hostnames. This prevents host header attacks that could exploit dangling records.

from flask import Flask, request, abort

app = Flask(__name__)

ALLOWED_HOSTS = {"api.example.com", "www.example.com"}

@app.before_request
def validate_host():
    if request.host not in ALLOWED_HOSTS:
        abort(400, "Host not allowed")

3. Use Basic Auth safely with explicit credentials

Check credentials directly without relying on external resolution. Use environment variables for secrets and enforce HTTPS to protect the credentials in transit.

from flask import Flask, request, abort
import os

app = Flask(__name__)

VALID_USERNAME = os.environ.get("API_USER")
VALID_PASSWORD = os.environ.get("API_PASS")

@app.route("/secure")
def secure():
    auth = request.authorization
    if not auth or auth.username != VALID_USERNAME or auth.password != VALID_PASSWORD:
        return abort(401, "Authentication required")
    return "OK"

4. Enforce HTTPS

Basic Auth transmits credentials in base64, which is easily reversible if intercepted. Always use TLS. In production, terminate TLS at a reverse proxy or load balancer and configure Flask to require secure cookies and HSTS where applicable.

# Example configuration for production-grade security
if __name__ == "__main__":
    # Do not use this in production; use a WSGI server with TLS termination
    app.run(ssl_context="adhoc")  # adhoc仅用于测试,生产环境应使用有效证书

5. Use a production-grade auth mechanism

For new projects, prefer token-based authentication (e.g., OAuth 2.0, JWT) over Basic Auth. If you must keep Basic Auth, ensure credentials are stored server-side (e.g., hashed in a database) and never passed in URLs or logs.

# Example token validation instead of Basic Auth
from flask import request, abort

def require_token(token):
    VALID_TOKENS = {os.environ.get("API_TOKEN")}
    return token in VALID_TOKENS

@app.route("/token-secure")
def token_secure():
    token = request.args.get("token")
    if not require_token(token):
        return abort(403, "Invalid token")
    return "OK"

6. Scan and monitor with middleBrick

Use the middlebrick CLI to validate your authentication and input validation posture:

middlebrick scan https://api.example.com/secure

In CI/CD, add the GitHub Action to fail builds if the security score drops below your chosen threshold. For ongoing assurance, the Pro plan provides continuous monitoring and Slack/Teams alerts.

Frequently Asked Questions

Can a dangling DNS record cause authentication bypass in Flask apps using Basic Auth?
Yes. If the app resolves a dangling hostname to an unexpected server and applies Basic Auth inconsistently, an attacker may redirect authenticated traffic and observe or manipulate credentials.
What is the recommended way to secure Basic Auth in Flask?
Avoid dynamic DNS lookups for access control, validate the Host header against an allowlist, store credentials in environment variables, enforce HTTPS, and prefer token-based authentication for new projects.