UnveilTech

UnveilScan Blog

← All articles

Try UnveilScan free

Wildcard DNS: the silent attack surface

Posted 2026-04-29 · 7 min read · DNSrecon

A wildcard DNS record (*.example.com IN A 1.2.3.4) is a thirty-second operational shortcut that often outlives the team that added it. Five years later it's catching every probe an attacker throws at you, every typo by your customers, and every subdomain you forgot you had. The cleanup cost grows with time. Here's why it matters.

What a wildcard actually does

RFC 1034 §4.3.3 specifies the wildcard semantics. The DNS server returns the wildcard's RR for any QNAME that doesn't have a more-specific match. So:

example.com.        IN A   192.0.2.10
www.example.com.    IN A   192.0.2.10
*.example.com.      IN A   192.0.2.20

dig api.example.com         → 192.0.2.20  (wildcard match)
dig www.example.com         → 192.0.2.10  (specific match)
dig admin.example.com       → 192.0.2.20  (wildcard match)
dig totally-fake.example.com → 192.0.2.20  (wildcard match)

There's no NXDOMAIN. Every label your customers, attackers, or random scanners try will resolve to something.

Attack surface multiplier

Three concrete consequences:

  1. CT log invisibility. A wildcard cert *.example.com covers all subdomains. Each subdomain you actually use never appears in CT logs because there's no per-subdomain cert issuance. crt.sh shows you a wildcard, not the inventory. You lose passive recon on your own infra.
  2. Subdomain enumeration is free. An attacker probes jenkins.example.com, grafana.example.com, vault.example.com, prometheus.example.com. All resolve. They land on your default vhost, which is hopefully a 404 — but if your origin is misconfigured, they hit the actual app.
  3. SSO/cookie scope leaks. A cookie set on .example.com with a wildcard will be sent to any attacker-suggested label. Combine with a stored XSS on a forgotten internal app: cookie exfiltration scope multiplies.

The vhost-as-a-firewall pattern

A wildcard at the DNS level can be safe if your reverse proxy strictly drops requests whose Host header doesn't match an explicitly-allowed list. nginx:

server {
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;  # close connection
}

server {
    listen 443 ssl;
    server_name app.example.com api.example.com www.example.com example.com;
    # ... real config ...
}

Without the explicit default-server reject, nginx falls through to the first server block — which may serve your real app to jenkins.example.com. In that case the wildcard becomes a real attack surface, not a theoretical one.

How UnveilScan detects wildcards

Our subdomain_wildcard checker generates 3 random hex labels (e.g., a3f2bc9d.example.com, e7c1a8b2.example.com, f4d9e2c0.example.com) and resolves them. Heuristic: if all 3 resolve and share at least one IP, we conclude wildcard. The IP-matching guard avoids false positives on split-horizon DNS where every random label gets a different answer.

Once we've detected a wildcard, downstream checkers compensate: dev_staging probes ~30 labels (dev/staging/admin/grafana/...) but skips them if they all resolve to the wildcard IP unless the response actually differs from the wildcard response on the HTTP layer. api_surface always adds a canary label (__unveilscan_canary_nx_404.example.com) and uses its HTTP response as a baseline to detect catch-all responses.

This dance — canary labels everywhere — is annoying but necessary. Without it, every scanner produces a wall of false positives on wildcard domains.

Cleaning up a long-lived wildcard

You inherited a wildcard. Removal is high-risk. Some labels actively in use, no inventory. Process:

  1. Phase 1 — observability. Enable per-vhost access logs on your reverse proxy (or just the load balancer). Run for 30 days. The list of distinct Host values seen is your inventory.
  2. Phase 2 — promote. Convert each Host you saw into an explicit DNS record (A or CNAME). Now every real subdomain has a non-wildcard answer.
  3. Phase 3 — narrow the wildcard. Change the wildcard to point to a "deprecated" vhost that returns 410 Gone with a Slack webhook for any hit. Run for 30 days.
  4. Phase 4 — delete. If the deprecated vhost saw zero legitimate traffic for 30 days, delete the wildcard. Now random labels return NXDOMAIN.

Phase 1 takes longer than expected because seasonal traffic exists (a quarterly batch job hits an obscure subdomain once every 90 days). Don't skip the wait.

The subdomain takeover wrinkle

A wildcard hides subdomain takeovers. old-blog.example.com CNAMEs to a deprovisioned Heroku app: with no wildcard, old-blog returns NXDOMAIN if the Heroku app is gone. With a wildcard, it resolves to the wildcard IP, hiding the fact that the CNAME lookup actually fails — until an attacker re-registers the Heroku app and the CNAME starts succeeding to their infra. Wildcard masks the takeover until exploitation.

Map your real subdomain inventory

Free Basic scan flags wildcards. Extended runs CT-log enumeration + canary-aware probes for ~30 sensitive labels.

Run a scan