Dangling Dns with Hmac Signatures
How Dangling Dns Manifests in Hmac Signatures
Dangling DNS records in HMAC signatures create a unique attack vector where expired or deleted domain records point to services that still accept HMAC-authenticated requests. This occurs when DNS records are removed without properly revoking associated HMAC credentials.
The attack pattern typically follows this sequence: An organization provisions HMAC credentials for a service endpoint, creates DNS records pointing to that endpoint, then later removes the DNS record (due to service migration, decommissioning, or configuration changes) while leaving the HMAC credentials active on the backend service.
Attackers exploit this by registering the expired domain, creating DNS records that resolve to their own infrastructure, and intercepting HMAC-signed requests intended for the legitimate service. Since HMAC signatures verify message integrity but not endpoint authenticity, the backend service processes requests from the attacker-controlled domain.
Consider this vulnerable pattern in HMAC-based API authentication:
import hmac
import hashlib
import time
def generate_hmac_signature(key, message):
return hmac.new(key.encode(), message.encode(), hashlib.sha256).hexdigest()
def verify_hmac_signature(key, message, signature):
expected = generate_hmac_signature(key, message)
return hmac.compare_digest(expected, signature)
# Vulnerable: No domain verification
message = f"timestamp={int(time.time())}&action=delete_user&user_id=12345"
signature = generate_hmac_signature("secret-key-123", message)
# Request sent to potentially compromised domain
# http://api.example.com/delete?msg=timestamp=...&sig=abcd1234
The critical vulnerability here is that HMAC verification only confirms the message hasn't been tampered with, not that it's reaching the intended service. If api.example.com has a dangling DNS record pointing to an attacker's server, the backend accepts the valid HMAC signature and executes the destructive action.
Another manifestation occurs in webhook HMAC verification. Services often validate HMAC signatures on incoming webhooks without verifying the source domain:
def verify_webhook_signature(signature, payload, secret):
expected = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
# Vulnerable: Accepts webhook from any domain with valid HMAC
webhook_data = request.data
webhook_sig = request.headers['X-Hub-Signature-256']
if verify_webhook_signature(webhook_sig, webhook_data, "webhook-secret"):
process_webhook(webhook_data) # Executes even from attacker-controlled domain
Cloud storage services with pre-signed HMAC URLs present another vulnerability. If a pre-signed URL's DNS record becomes dangling, attackers can serve the URL from their own domain, and the storage service validates the HMAC signature without checking the actual request origin.
HMAC Signatures-Specific Detection
Detecting dangling DNS vulnerabilities in HMAC signature systems requires a multi-layered approach that examines both DNS infrastructure and HMAC implementation patterns.
Start with DNS reconnaissance to identify expired or recently removed records pointing to HMAC-enabled services. Use tools like dig, nslookup, or specialized DNS history services:
# Check current DNS records
dig api.example.com
# Check DNS history for expired records
# Services like SecurityTrails, DNSDumpster, or Wayback Machine
# Look for CNAME records pointing to external services
dig +short api.example.com CNAME
For HMAC implementations, scan for services that accept HMAC signatures without domain verification. This includes:
- APIs that only verify HMAC signatures without checking the request origin
- Webhook endpoints accepting HMAC-authenticated requests from any domain
- Services with pre-signed URLs that validate signatures without origin checks
middleBrick's black-box scanning approach is particularly effective for detecting these vulnerabilities. The scanner tests HMAC endpoints by:
- Identifying HMAC signature patterns in API responses
- Testing whether valid HMAC signatures are accepted from unexpected domains
- Checking for missing origin verification in HMAC validation logic
middleBrick's LLM/AI security module also detects AI-specific HMAC vulnerabilities in services that use HMAC for model API authentication, testing for prompt injection through HMAC-signed requests.
Code analysis for HMAC implementations should look for these anti-patterns:
# Vulnerable pattern - missing domain verification
import hmac
import hashlib
def verify_hmac_without_domain_check(key, message, signature):
expected = hmac.new(key.encode(), message.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
# Secure pattern - includes domain verification
from urllib.parse import urlparse
def verify_hmac_with_domain_check(key, message, signature, expected_domain):
# Verify HMAC signature
expected_sig = hmac.new(key.encode(), message.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected_sig, signature):
return False
# Verify domain in message or headers
parsed = urlparse(message)
if parsed.netloc != expected_domain:
return False
return True
Automated scanning with middleBrick can identify these patterns across your API surface in seconds, providing a security risk score and specific findings for HMAC-related dangling DNS vulnerabilities.
HMAC Signatures-Specific Remediation
Remediating dangling DNS vulnerabilities in HMAC signature systems requires both infrastructure changes and code-level fixes. The most effective approach combines DNS hygiene practices with enhanced HMAC verification.
First, implement a comprehensive HMAC credential lifecycle management system. When DNS records are removed or changed, automatically revoke associated HMAC credentials:
# Credential management system
hmac_credentials = {
"api.example.com": {
"key": "secret-key-123",
"active": True,
"dns_record": "api.example.com",
"last_verified": None
}
}
def verify_hmac_with_dns_check(key, message, signature, domain):
# Check if credentials are still active
if domain not in hmac_credentials:
return False
cred = hmac_credentials[domain]
if not cred["active"]:
return False
# Verify HMAC signature
expected = hmac.new(cred["key"].encode(), message.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature):
return False
# Update last verified timestamp
cred["last_verified"] = time.time()
return True
Second, implement domain binding in your HMAC messages. Include the intended domain as part of the signed message or use domain-specific keys:
def generate_bound_hmac_signature(key, message, domain):
bound_message = f"{domain}::{message}"
return hmac.new(key.encode(), bound_message.encode(), hashlib.sha256).hexdigest(), bound_message
def verify_bound_hmac_signature(key, bound_message, signature, expected_domain):
domain, message = bound_message.split("::", 1)
if domain != expected_domain:
return False
expected = hmac.new(key.encode(), bound_message.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Third, use HMAC with additional authentication mechanisms. Combine HMAC with TLS certificate pinning or mTLS to ensure both message integrity and endpoint authenticity:
import ssl
def verify_hmac_with_tls_pinning(key, message, signature, expected_domain, cert_fingerprint):
# Verify HMAC signature
expected = hmac.new(key.encode(), message.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature):
return False
# Verify TLS certificate matches expected fingerprint
# This ensures connection to legitimate server
context = ssl.create_default_context()
# Implementation would verify server certificate matches cert_fingerprint
return True
For webhook HMAC verification, implement origin verification using multiple factors:
def secure_webhook_verification(signature, payload, secret, expected_domain, expected_ip_ranges):
# Verify HMAC signature
expected_sig = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected_sig, signature):
return False
# Verify request origin
client_ip = request.remote_addr
if not is_ip_in_ranges(client_ip, expected_ip_ranges):
return False
# Verify domain via reverse DNS or certificate
if not verify_domain(client_ip, expected_domain):
return False
return True
Finally, implement continuous monitoring with middleBrick's Pro plan features. The continuous scanning capability detects when HMAC endpoints become vulnerable due to DNS changes, alerting your team before attackers can exploit dangling records.