You deleted the staging server. You closed the Jira ticket. You told your team the migration is done.
But somewhere out there, a publicly searchable database has been quietly logging every TLS certificate your company has ever issued, including the one for internal-api.yourapp.com you spun up two years ago and forgot about.
That database is open to anyone with a browser. Attackers use it every single day.
What is Certificate Transparency and why does it exist?
Certificate Transparency (CT) is a public, append-only logging system for TLS certificates. It was designed with good intentions: in 2013, Google introduced it after a CA (DigiCert Malaysia) was caught issuing unauthorized certificates for Google's own domains. The idea was to make every certificate publicly auditable so rogue certs could be detected quickly.
Today, all major browsers require that certificates be submitted to at least two public CT logs before they're considered trusted. That means every certificate issued for your domains, past or present, is recorded in a permanent, searchable, publicly accessible ledger.
The logs are operated by Google, Cloudflare, DigiSign, and others. You can query them directly at crt.sh, or tap into the real-time stream with tools like Certstream.
This is great for defenders. It's also a goldmine for attackers.
The recon phase nobody talks about
Before any actual attack happens, there's reconnaissance. Certificate transparency logs have become one of the most reliable recon techniques out there, because they're passive, legal, and the data is just sitting there.
Step 1: Enumerate every subdomain you've ever had
curl "https://crt.sh/?q=%.yourapp.com&output=json" \
| jq -r '.[].name_value' \
| sed 's/\*\.//g' \
| sort -u
This one command returns a complete historical list of every subdomain you've ever issued a certificate for. Not just what's live today, everything, ever.
That includes:
-
staging.yourapp.com(the one you decommissioned last spring) -
internal-dashboard.yourapp.com(set up for a contractor who left) -
beta-v2.yourapp.com(the failed product launch from 2021) -
jenkins.yourapp.com(please tell me you took this offline)
The attacker didn't scan your network. They didn't need to. You published this list yourself every time you provisioned a certificate.
Step 2: Check which ones are still alive
Once they have the list, it's trivial to check which subdomains still resolve, and more importantly, which ones resolve to something they can claim.
cat subdomains.txt | dnsx -silent -a -resp
Tools like dnsx, massdns, and shuffledns can resolve thousands of subdomains in seconds. The attacker is looking for a specific pattern: a CNAME that still exists in your DNS, pointing at a service that no longer has your app registered on it.
Step 3: Find dangling records and take them over
If staging.yourapp.com has a CNAME pointing to yourapp-staging.herokuapp.com, and that Heroku app was deleted six months ago, it's available to claim. Anyone can register a new Heroku app at that address. The attacker now controls a subdomain under your brand, with a valid HTTPS certificate and no browser warnings.
This isn't theoretical. It has happened to Uber, Microsoft, and hundreds of smaller companies. The EdOverflow/can-i-take-over-xyz repository tracks dozens of platforms, Heroku, Netlify, GitHub Pages, S3, Fastly, Shopify, Azure, that are all exploitable in exactly this way.
What they do once they're in
A subdomain takeover under your domain isn't just an embarrassment. Consider what the attacker actually has.
A login page at staging.yourapp.com looks completely legitimate. The SSL padlock is valid. The URL is your brand. Security-aware users who check the URL before entering credentials will see nothing wrong.
If your session cookies are set on .yourapp.com, they're readable by any subdomain, including the one the attacker just claimed. Depending on your cookie configuration, this can mean direct session hijacking without ever touching your main application.
And if your CSP includes *.yourapp.com as a trusted source (which is common), scripts served from the attacker's subdomain are treated as trusted by your main application. Arbitrary JavaScript, injected from a domain that looks like yours, passing all your security checks.
Your browser has no way of knowing the subdomain changed hands.
The CertStream problem: real-time exposure
CT logs aren't just queryable in retrospect. They're also streamable in real time.
CertStream exposes a WebSocket feed of every certificate being issued right now, across all major CT logs. Attackers use it to monitor for newly issued certificates matching patterns they care about: your company name, your product, your domain.
The moment your developer issues a cert for new-feature.yourapp.com, it appears in that stream. Before the feature is deployed, before any internal announcement, an attacker watching CertStream already knows it exists.
This matters especially for acquisitions. When you start setting up infrastructure for a company you're acquiring, the subdomain pattern is often a dead giveaway. Competitors and researchers monitor these logs. Developers who issue certs for internal services and assume nobody will find them are usually wrong.
Wildcards don't help as much as you think
A common response to subdomain enumeration concerns is switching to wildcard certificates (*.yourapp.com). If you're not issuing individual certs for each subdomain, they won't appear in CT logs.
This is partially true. But most organizations issue a mix of wildcard and specific certs. Historical certs from before any wildcard migration are still in the logs forever.
More importantly, CT logs reveal what subdomains you've certificated, not what's actually exposed. Your DNS zone file is the real source of truth. Wildcard certs don't clean up dangling CNAME records.
There's also the question of blast radius. A single compromised wildcard key signs everything under your domain. The cert covering *.yourapp.com is a high-value target.
How to audit your exposure
Pull your full historical subdomain list:
curl "https://crt.sh/?q=%.yourdomain.com&output=json" \
| jq -r '.[].name_value' \
| sed 's/\*\.//g' \
| sort -u > subdomains.txt
Resolve which ones are still live:
cat subdomains.txt | dnsx -silent -a -resp -o live_subdomains.txt
Check CNAMEs for dangling records:
cat subdomains.txt | while read sub; do
cname=$(dig CNAME +short $sub)
if [ -n "$cname" ]; then
echo "$sub -> $cname"
curl -s -o /dev/null -w "%{http_code}" "https://$cname" | grep -q "404\|no such app\|doesn't exist" && echo " ⚠ POTENTIALLY DANGLING"
fi
done
Run subjack for automated takeover checks:
subjack -w subdomains.txt -t 100 -timeout 30 -o results.txt -ssl
For most teams, this is a one-time audit that surfaces something uncomfortable. For ongoing monitoring, ZeroHook automates the whole thing: it watches your DNS records, flags dangling CNAMEs, and alerts you before someone else finds them. Worth bookmarking: zerohook.org.
What to actually fix
Delete the DNS record before you tear down any service. Same day. Not "we'll clean it up next sprint," because that sprint doesn't come.
Export your zone file and go through it line by line. If you can't explain what a record is for, it probably shouldn't be there.
Get CT log monitoring in place. CertStream or anything that wraps it will tell you when a certificate is issued for your domains. You want to know before someone else does.
Check your cookie scope. Session cookies set on .yourapp.com are readable by any subdomain. Tighten this if you can.
Review your CSP. Wildcard allowances like *.yourapp.com are common and dangerous. Enumerate sources explicitly where possible.
DNS cleanup belongs on your decommissioning checklist, next to revoking API keys and removing IAM roles. It's the same category of problem.
TL;DR
Every certificate you've ever issued is in a public, searchable, permanent log. Attackers use that log to find subdomains you forgot about, check which ones are still live, and claim the ones pointing at services you've already shut down.
The recon is free. The takeover is five minutes of work. The damage, phishing campaigns on your domain, session hijacking, CSP bypass, is harder to explain to your users.
Run the commands above. It takes 20 minutes and you'll almost certainly find something.
Top comments (0)