Skip to content

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

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

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

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

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

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

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

All SecurityTrails API requests require authentication via API key in the APIKEY header.

Get Your API Key:

  1. Create account at SecurityTrails website
  2. Navigate to API section in account settings
  3. Generate or view existing API key
  4. 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

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

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

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

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

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

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

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

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

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

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

#!/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

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

# 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

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

# 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

#!/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

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

PracticeDetails
API Key SecurityNever commit keys to Git; use environment variables or .env files
Rate LimitingImplement delays between requests; use time.sleep(0.5) in Python
CachingCache results locally; don’t repeat API calls for same domain
Error HandlingCheck HTTP status codes; handle 429 (rate limit) gracefully
Data ValidationVerify DNS records with live queries before using in tests
PaginationUse page/limit parameters for domains with many subdomains (>100)
Historical PivotsTrack IP/NS/MX changes over time to identify infrastructure evolution
Combine SourcesUse SecurityTrails + Subfinder + crt.sh for comprehensive enumeration
Bulk OperationsUse batch/script mode; avoid manual lookup loops
DocumentationLog which tool discovered which subdomain for reporting
ToolPurposeComplementary Use
SubfinderFast subdomain enumerationValidate SecurityTrails findings
AmassDeep OSINT + subdomain intelCombine results from both sources
DNSDumpsterVisual DNS reconnaissanceCompare against SecurityTrails
crt.shCertificate transparency logsFind new subdomains from CT
CensysIP/certificate databaseEnrich IP intelligence data
ShodanOpen port discoveryFind services on SecurityTrails IPs
MaltegoGraph visualizationImport SecurityTrails data for mapping
WHOIS CLIDirect WHOIS lookupsValidate SecurityTrails WHOIS data
dig/nslookupLive DNS queriesVerify SecurityTrails historical data
Burp SuiteWeb scanningUse SecurityTrails scope for enumeration