SecurityTrails
SecurityTrails provides comprehensive DNS and domain intelligence for attack surface mapping and reconnaissance. It combines historical DNS data, subdomain discovery, WHOIS information, and IP intelligence into a single platform with both web interface and RESTful API for automation.
Overview
Section titled “Overview”SecurityTrails aggregates DNS resolution history, domain relationships, and IP intelligence to help identify exposed infrastructure. The platform maintains 20+ years of DNS records and enables attackers/defenders to map attack surfaces, discover forgotten subdomains, and track infrastructure changes over time.
Free vs Paid Tiers:
- Free: Limited lookups, basic domain/IP search, restricted API calls
- Researcher: 10K API calls/month, full historical DNS, WHOIS, subdomains
- Professional: 100K+ API calls/month, priority support, custom integrations
- Enterprise: Custom limits, dedicated support, white-label options
API Access:
- REST API with JSON responses
- Rate limiting based on tier (typically 1-10 requests/second)
- API key authentication required for all endpoints
- No OAuth/complex auth — simple header-based API keys
Web Interface
Section titled “Web Interface”Domain Lookup
Section titled “Domain Lookup”Navigate to the search bar and enter a domain (e.g., example.com). Results show:
- Current DNS records (A, AAAA, MX, NS, SOA, TXT)
- Subdomain list with record counts
- Historical snapshots (hover over dates)
- WHOIS details
- IP neighbors and related infrastructure
Subdomain Discovery
Section titled “Subdomain Discovery”Click Subdomains tab on any domain to view:
- Complete subdomain enumeration
- DNS record types per subdomain
- Last seen date and first seen date
- Filter by record type (A, CNAME, MX, etc.)
- Export as CSV or JSON
Historical DNS Data
Section titled “Historical DNS Data”Switch to History tab to examine:
- DNS changes over years/months/days
- Multiple historical snapshots
- IP address migration patterns
- DNS provider changes
- Deleted or inactive records
- Timeline view showing infrastructure evolution
Associated Domains
Section titled “Associated Domains”Expand Associated Domains section to find:
- Domains sharing the same IP address
- Shared nameservers (NS lookup reverse)
- Shared MX records
- Parent/child domain relationships
- Domains registered to same entity
IP Explorer
Section titled “IP Explorer”From any result, click an IP to access IP intelligence:
- All domains pointing to that IP
- Reverse DNS (PTR records)
- CIDR block ownership
- Autonomous System (AS) information
- Geolocation and ISP details
- Open ports and services (if available)
API Authentication
Section titled “API Authentication”All SecurityTrails API requests require authentication via API key in the APIKEY header.
Get Your API Key:
- Create account at SecurityTrails website
- Navigate to API section in account settings
- Generate or view existing API key
- Keep key private — regenerate if exposed
Rate Limits:
- Free: 50 requests/month
- Researcher: 10,000 requests/month (~330/day)
- Professional: 100,000 requests/month
- Enterprise: Custom limits
- All plans: 10 requests/second max
Basic cURL Syntax:
curl -H "APIKEY: your_api_key_here" \
"https://api.securitytrails.com/v1/domain/example.com/details"
Check Rate Limit Status:
curl -I -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | \
grep "X-RateLimit"
Handle Rate Limit Errors:
# Check headers for remaining quota
# X-RateLimit-Remaining: 499
# X-RateLimit-Reset: 1609459200 (Unix timestamp)
# HTTP 429: Too Many Requests — wait until reset time
Domain Information API
Section titled “Domain Information API”GET /domain/{hostname}/details
Section titled “GET /domain/{hostname}/details”Retrieve comprehensive information about a domain in a single request.
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | jq
Response Structure:
{
"domain": "example.com",
"last_dns_records": {
"a": [{"value": "93.184.216.34"}],
"aaaa": [{"value": "2606:2800:220:1:248:1893:25c8:1946"}],
"mx": [{"value": "mail.example.com", "priority": 10}],
"ns": [{"value": "a.iana-servers.net"}],
"soa": [{"value": "a.iana-servers.net hostmaster.iana.org 1 7200 3600 1209600 3600"}],
"txt": [{"value": "v=spf1 -all"}]
},
"subdomains": ["www", "mail", "ftp"],
"whois": {
"created": "1995-08-15",
"updated": "2021-08-06",
"expires": "2025-08-14",
"registrar": "VeriSign Global Registry Services"
}
}
Extract Specific Data:
# Get only A records
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | \
jq '.last_dns_records.a[].value'
# Get all subdomains
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | \
jq '.subdomains[]'
Subdomain Discovery
Section titled “Subdomain Discovery”GET /domain/{hostname}/subdomains
Section titled “GET /domain/{hostname}/subdomains”List all known subdomains for a domain with optional filtering.
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/domain/example.com/subdomains?query=api"
Parameters:
query: Filter subdomains by string (e.g.,api,admin,dev)page: Pagination (default 1, max 100 results per page)limit: Results per page (1-100, default 100)
Example — Find Development Subdomains:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/subdomains?query=dev" | \
jq '.subdomains[] | .subdomain'
# Output: api-dev.example.com, staging-dev.example.com, etc.
Pagination Example:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/subdomains?page=2&limit=50"
Detect Wildcard DNS:
# If wildcard exists, *.example.com resolves
# Look for unusual subdomains that shouldn't exist
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/subdomains" | \
jq '.subdomains | length'
Historical DNS
Section titled “Historical DNS”GET /history/{hostname}/dns/{type}
Section titled “GET /history/{hostname}/dns/{type}”Retrieve historical DNS records (supports A, AAAA, MX, NS, SOA, TXT, CNAME, PTR).
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/history/example.com/dns/a"
Track A Record Changes Over Time:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/history/example.com/dns/a" | \
jq '.records[] | {first_seen: .first_seen, last_seen: .last_seen, values: .values[]}'
Monitor Infrastructure Changes:
# Check if domain moved to CDN
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/history/example.com/dns/a" | \
jq '.records[].values[] | .ip' | sort | uniq -c
# Identify IP pattern (CloudFlare IPs all start with 104.*)
MX Record History (Email Provider Changes):
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/history/example.com/dns/mx" | \
jq '.records[] | {first_seen, last_seen, value: .values[].exchange}'
NS Record Changes (Registrar Migrations):
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/history/example.com/dns/ns" | \
jq '.records[] | {seen: .first_seen, nameservers: .values[].nameserver}'
IP Intelligence
Section titled “IP Intelligence”GET /ips/nearby/{ip}
Section titled “GET /ips/nearby/{ip}”Find other IP addresses near a target IP (useful for discovering related infrastructure).
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/ips/nearby/93.184.216.34"
Example Output:
{
"ips": [
{"ip": "93.184.216.33", "domains": ["example-mirror.com"]},
{"ip": "93.184.216.34", "domains": ["example.com", "www.example.com"]},
{"ip": "93.184.216.35", "domains": ["example-test.com"]}
]
}
Reverse DNS Lookup:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/ips/nearby/93.184.216.34" | \
jq '.ips[] | select(.ip=="93.184.216.34") | .domains'
Map IP Neighbors:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/ips/nearby/93.184.216.34" | \
jq '.ips[] | "\(.ip) — \(.domains | join(", "))"'
WHOIS Data
Section titled “WHOIS Data”GET /domain/{hostname}/whois
Section titled “GET /domain/{hostname}/whois”Retrieve WHOIS information including registrar, dates, and name servers.
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/domain/example.com/whois"
Extract Key WHOIS Fields:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/whois" | \
jq '{
created: .created_date,
expires: .expires_date,
updated: .updated_date,
registrar: .registrar,
registrant: .registrant,
nameservers: .nameservers
}'
Check Domain Expiration:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/whois" | \
jq '.expires_date'
# Output: 2025-08-14 or similar
Find Domains by Registrar:
# Use bulk WHOIS API (if available in your plan)
# Pivot on registrar name to find related domains
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/whois" | \
jq '.registrar'
Associated Domains
Section titled “Associated Domains”GET /domain/{hostname}/associated
Section titled “GET /domain/{hostname}/associated”Find domains related via shared infrastructure (same IP, nameservers, MX records).
curl -H "APIKEY: your_api_key" \
"https://api.securitytrails.com/v1/domain/example.com/associated"
Reverse Nameserver Lookup (Shared NS):
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/whois" | \
jq '.nameservers[]'
# Then search for other domains using same nameservers
Find Sibling Domains (Same Organization):
# Use registrant info to pivot
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/whois" | \
jq '{registrant_org: .registrant_organization, admin: .admin_name}'
Shared IP Discovery:
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | \
jq '.last_dns_records.a[0].value' | \
xargs -I {} curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/ips/nearby/{}"
Python Integration
Section titled “Python Integration”Using Requests Library
Section titled “Using Requests Library”import requests
import json
API_KEY = "your_api_key_here"
HEADERS = {"APIKEY": API_KEY}
def get_domain_info(domain):
url = f"https://api.securitytrails.com/v1/domain/{domain}/details"
resp = requests.get(url, headers=HEADERS)
return resp.json()
def get_subdomains(domain, query=""):
url = f"https://api.securitytrails.com/v1/domain/{domain}/subdomains"
params = {"query": query}
resp = requests.get(url, headers=HEADERS, params=params)
return resp.json()["subdomains"]
# Example usage
info = get_domain_info("example.com")
print(f"Subdomains: {info['subdomains']}")
subs = get_subdomains("example.com", query="api")
for sub in subs:
print(sub["subdomain"])
Bulk Enumeration Script
Section titled “Bulk Enumeration Script”import requests
import time
API_KEY = "your_api_key"
HEADERS = {"APIKEY": API_KEY}
DOMAINS = ["example.com", "example.org", "example.net"]
def enumerate_all(domain):
results = {}
url = f"https://api.securitytrails.com/v1/domain/{domain}/details"
resp = requests.get(url, headers=HEADERS)
data = resp.json()
results["domain"] = domain
results["subdomains"] = data.get("subdomains", [])
results["a_records"] = [r["value"] for r in data["last_dns_records"].get("a", [])]
results["mx_records"] = [r["value"] for r in data["last_dns_records"].get("mx", [])]
time.sleep(0.5) # Rate limiting
return results
for domain in DOMAINS:
data = enumerate_all(domain)
print(json.dumps(data, indent=2))
Using securitytrails-py Wrapper
Section titled “Using securitytrails-py Wrapper”pip install securitytrails
from securitytrails import SecurityTrails
st = SecurityTrails(api_key="your_api_key")
# Domain lookup
domain = st.get_domain("example.com")
print(domain.subdomains)
print(domain.dns)
# Subdomain enumeration
subs = st.get_subdomains("example.com", query="api")
# Historical DNS
history = st.get_dns_history("example.com", "a")
# IP intelligence
ip_data = st.get_ips_nearby("93.184.216.34")
Attack Surface Mapping Workflows
Section titled “Attack Surface Mapping Workflows”Subdomain Enumeration
Section titled “Subdomain Enumeration”#!/bin/bash
API_KEY="your_api_key"
TARGET="example.com"
# Get all subdomains
curl -s -H "APIKEY: $API_KEY" \
"https://api.securitytrails.com/v1/domain/$TARGET/subdomains?limit=100" | \
jq -r '.subdomains[] | .subdomain' > subdomains.txt
# Count results
wc -l subdomains.txt
Infrastructure Discovery
Section titled “Infrastructure Discovery”#!/bin/bash
# Map IP space of target organization
API_KEY="your_api_key"
DOMAIN="example.com"
# Get main IP
IP=$(curl -s -H "APIKEY: $API_KEY" \
"https://api.securitytrails.com/v1/domain/$DOMAIN/details" | \
jq -r '.last_dns_records.a[0].value')
echo "Main IP: $IP"
# Find nearby IPs
curl -s -H "APIKEY: $API_KEY" \
"https://api.securitytrails.com/v1/ips/nearby/$IP" | \
jq '.ips[] | {ip, domains}' | tee infrastructure.json
DNS Change Monitoring
Section titled “DNS Change Monitoring”import requests
import json
from datetime import datetime
API_KEY = "your_api_key"
DOMAIN = "example.com"
HEADERS = {"APIKEY": API_KEY}
def track_dns_changes(domain, record_type="a"):
url = f"https://api.securitytrails.com/v1/history/{domain}/dns/{record_type}"
resp = requests.get(url, headers=HEADERS)
records = resp.json()["records"]
for record in records:
print(f"Record: {record['values']}")
print(f"First seen: {record['first_seen']}")
print(f"Last seen: {record['last_seen']}")
print()
track_dns_changes(DOMAIN)
Certificate Transparency Feed
Section titled “Certificate Transparency Feed”# Combine SecurityTrails with crt.sh data
# Get subdomains from SecurityTrails
SUBS=$(curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/subdomains" | \
jq -r '.subdomains[] | .subdomain')
# Cross-reference with CT logs
for sub in $SUBS; do
echo "Checking CT logs for: $sub.example.com"
# Use curl to query crt.sh API
done
Integration with Other Tools
Section titled “Integration with Other Tools”Feed Subfinder
Section titled “Feed Subfinder”# SecurityTrails data enriches Subfinder results
# Use API to get subdomains, then validate with Subfinder
API_KEY="your_api_key"
DOMAIN="example.com"
curl -s -H "APIKEY: $API_KEY" \
"https://api.securitytrails.com/v1/domain/$DOMAIN/subdomains" | \
jq -r '.subdomains[] | .subdomain' | \
sed "s/^/$DOMAIN/" > st_subs.txt
# Combine with Subfinder
subfinder -d $DOMAIN -o subfinder_subs.txt
cat st_subs.txt subfinder_subs.txt | sort -u > all_subs.txt
Enrich Maltego Graphs
Section titled “Enrich Maltego Graphs”# Export SecurityTrails data to Maltego-compatible format
import requests
import csv
API_KEY = "key"
DOMAIN = "example.com"
HEADERS = {"APIKEY": API_KEY}
url = f"https://api.securitytrails.com/v1/domain/{DOMAIN}/details"
data = requests.get(url, headers=HEADERS).json()
with open("maltego_import.csv", "w") as f:
writer = csv.writer(f)
writer.writerow(["Entity Type", "Value", "Notes"])
for sub in data["subdomains"]:
writer.writerow(["Domain", sub, "SecurityTrails"])
for ip in [r["value"] for r in data["last_dns_records"]["a"]]:
writer.writerow(["IPv4Address", ip, "SecurityTrails"])
Combine with Shodan
Section titled “Combine with Shodan”#!/bin/bash
# Find open ports on SecurityTrails IPs using Shodan
API_KEY_ST="securitytrails_key"
API_KEY_SHODAN="shodan_key"
DOMAIN="example.com"
# Get IPs from SecurityTrails
IPS=$(curl -s -H "APIKEY: $API_KEY_ST" \
"https://api.securitytrails.com/v1/domain/$DOMAIN/details" | \
jq -r '.last_dns_records.a[].value')
for IP in $IPS; do
echo "Searching Shodan for: $IP"
curl -s "https://api.shodan.io/shodan/host/$IP?key=$API_KEY_SHODAN" | \
jq '.ports[]'
done
Troubleshooting
Section titled “Troubleshooting”API Key Not Working:
- Verify key in account settings (may have been regenerated)
- Check for leading/trailing whitespace in key
- Ensure APIKEY header is exact case (not apikey or Api-Key)
Rate Limit Exceeded:
# Check when limit resets
curl -I -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | \
grep -i ratelimit
# Wait until X-RateLimit-Reset timestamp
# Implement exponential backoff in automation
No Subdomains Found:
- Domain may be private/protected
- SecurityTrails may not have indexed it yet
- Use multiple enumeration sources (Subfinder, Amass, crt.sh)
Missing Historical Data:
- Not all domains have complete history
- Paid tiers have access to more snapshots
- Older records (pre-2010) may not be available
JSON Parse Errors:
# Check raw response
curl -v -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details"
# Validate with jq
curl -s -H "APIKEY: key" \
"https://api.securitytrails.com/v1/domain/example.com/details" | jq . > /dev/null
Best Practices
Section titled “Best Practices”| Practice | Details |
|---|---|
| API Key Security | Never commit keys to Git; use environment variables or .env files |
| Rate Limiting | Implement delays between requests; use time.sleep(0.5) in Python |
| Caching | Cache results locally; don’t repeat API calls for same domain |
| Error Handling | Check HTTP status codes; handle 429 (rate limit) gracefully |
| Data Validation | Verify DNS records with live queries before using in tests |
| Pagination | Use page/limit parameters for domains with many subdomains (>100) |
| Historical Pivots | Track IP/NS/MX changes over time to identify infrastructure evolution |
| Combine Sources | Use SecurityTrails + Subfinder + crt.sh for comprehensive enumeration |
| Bulk Operations | Use batch/script mode; avoid manual lookup loops |
| Documentation | Log which tool discovered which subdomain for reporting |
Related Tools
Section titled “Related Tools”| Tool | Purpose | Complementary Use |
|---|---|---|
| Subfinder | Fast subdomain enumeration | Validate SecurityTrails findings |
| Amass | Deep OSINT + subdomain intel | Combine results from both sources |
| DNSDumpster | Visual DNS reconnaissance | Compare against SecurityTrails |
| crt.sh | Certificate transparency logs | Find new subdomains from CT |
| Censys | IP/certificate database | Enrich IP intelligence data |
| Shodan | Open port discovery | Find services on SecurityTrails IPs |
| Maltego | Graph visualization | Import SecurityTrails data for mapping |
| WHOIS CLI | Direct WHOIS lookups | Validate SecurityTrails WHOIS data |
| dig/nslookup | Live DNS queries | Verify SecurityTrails historical data |
| Burp Suite | Web scanning | Use SecurityTrails scope for enumeration |