Dangling Dns in Fastapi with Hmac Signatures
Dangling Dns in Fastapi with Hmac Signatures — how this specific combination creates or exposes the vulnerability
A dangling DNS record occurs when a hostname remains in DNS but no service is configured to accept traffic at that address. In FastAPI applications that use HMAC signatures for request authentication, relying on DNS resolution to validate the source of a request can introduce a security boundary that does not exist. HMAC signatures typically ensure integrity and origin authenticity by signing a canonical representation of the request with a shared secret. The verification step in the application compares the computed signature with the signature provided by the caller, but it does not inherently validate the network path or the ongoing existence of a trusted DNS name.
When a FastAPI service resolves a hostname used for signature verification or for routing decisions, a dangling DNS record can cause the application to mistakenly attribute a request to a trusted source. For example, if the application uses a DNS name to scope tenant identifiers or to derive key selection logic, and that DNS record later points to an unintended host, the logical boundary enforced by HMAC can be misaligned with the network boundary. An attacker who can influence DNS—through cache poisoning, compromise of a third-party DNS provider, or a stale record after infrastructure decommission—might redirect resolution to a malicious endpoint that still passes HMAC checks if the shared secret is inadvertently shared or if key derivation depends on the resolved hostname. The HMAC layer will still validate the signature, but the assumption that the signed request originated from the expected service is no longer valid due to the dangling mapping between name and address.
Additionally, during infrastructure migrations or rollouts, a FastAPI deployment might temporarily reference a DNS name that does not yet point to the new service. If the application uses that name in signature material—such as including a hostname claim in a custom header that is signed—clients or services might inadvertently sign requests against an old or unconfigured endpoint. MiddleBrick scans this attack surface by testing unauthenticated endpoints and evaluating how runtime behavior aligns with OpenAPI/Swagger specifications, including $ref resolution across spec versions. This helps surface mismatches between documented routing and actual resolution behavior, highlighting cases where DNS instability can weaken the effective security of HMAC-based schemes.
Hmac Signatures-Specific Remediation in Fastapi — concrete code fixes
Remediation focuses on removing reliance on DNS for security decisions and hardening HMAC verification in FastAPI. Avoid deriving keys or selecting secrets based on resolved hostnames. Instead, use explicit configuration and pin expected values. When verifying signatures, ensure the canonical string excludes any hostname that could be influenced by DNS. Below are concrete code examples that demonstrate secure HMAC handling in FastAPI.
import hmac
import hashlib
import time
from fastapi import FastAPI, Request, Header, HTTPException
from pydantic import BaseModel
import os
import json
app = FastAPI()
# Use a centrally managed secret, not derived from DNS
SHARED_SECRET = os.environ.get("HMAC_SHARED_SECRET").encode()
# Canonicalization function that excludes hostname
async def canonical_for_hmac(method: str, path: str, timestamp: str, body: str) -> str:
parts = [method.upper(), path, timestamp, body]
return "\n".join(parts)
@app.post("/webhook")
async def webhook(
request: Request,
x_signature: str = Header(None, alias="X-Signature"),
x_timestamp: str = Header(None, alias="X-Timestamp"),
):
timestamp = x_timestamp
body = await request.body()
body_text = body.decode("utf-8")
method = request.method
path = request.url.path
# Reject if timestamp is too old to prevent replay
try:
req_time = int(timestamp)
except ValueError:
raise HTTPException(status_code=400, detail="Invalid timestamp")
if abs(req_time - int(time.time())) > 300:
raise HTTPException(status_code=400, detail="Timestamp out of window")
canonical = await canonical_for_hmac(method, path, timestamp, body_text)
expected = hmac.new(SHARED_SECRET, canonical.encode("utf-8"), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, x_signature):
raise HTTPException(status_code=401, detail="Invalid signature")
return {"status": "ok"}
This example avoids any DNS-dependent logic. The shared secret is loaded from environment variables, and the canonical string is built from method, path, timestamp, and body. Using a constant-time comparison mitigates timing attacks. For production, rotate secrets via a secure vault and enforce strict header validation to prevent injection of hostname-like values into signed material.
In CI/CD workflows, the middleBrick GitHub Action can be added to fail builds if risk scores exceed your threshold, ensuring that changes do not reintroduce DNS-related misconfigurations. The CLI allows local scanning with middlebrick scan <url>, producing JSON output that includes per-category findings. For teams using AI coding assistants, the MCP Server enables scanning APIs directly from the IDE, surfacing issues before deployment.