cybersecurity #supplychain #whois #rapidapi #devsecops #domainsecurity #subdomaintakeover
When attackers hit the software supply chain, we usually picture malicious code slipped into a popular package. But the recent Shai-Hulud campaign, which reportedly impacted Keyv and related dependencies, is a reminder that supply-chain attacks often start with infrastructure, not source code. Hijacked subdomains, expired maintainer domains, and weak email-security posture can all become footholds for injecting malicious updates or redirecting users.
A domain and DNS audit won’t patch your code, but it can spot the infrastructure drift that lets these attacks succeed. In this post I’ll show how to use the Domain WHOIS API to audit dependency-related domains, detect subdomain takeover risk, and score email-security posture (SPF, DMARC, DKIM, DNSSEC, MTA-STS) from your CI pipeline.
Why supply-chain attackers love domains and DNS
Most packages list a homepage, documentation site, or author email. If an attacker can:
- Take over an expired domain tied to a maintainer,
- Hijack a dangling subdomain that once hosted package docs or a CDN,
- Spoof a maintainer because DMARC/SPF are missing,
…they can redirect installs, publish fake updates, or phish credentials without ever touching the registry’s source code.
The good news: these weaknesses are visible from public DNS and WHOIS data. The Domain WHOIS API combines RDAP WHOIS, DNS records, SSL certificates, subdomain discovery, takeover-risk scoring, email-security scoring, and historical snapshots in one endpoint.
- RapidAPI listing: https://rapidapi.com/On13uka/api/domain-whois2
- GitHub examples: https://github.com/On13uka/domain-whois-api
What the API gives you
A single query can return:
| Capability | Why it matters for supply-chain defense |
|---|---|
| RDAP WHOIS | Domain age, registrar, expiry, status flags |
| DNS records | A, AAAA, CNAME, MX, TXT (SPF/DMARC/DKIM) |
| SSL certificate | Cert validity, issuer, SANs |
| Subdomain discovery | Shadow infrastructure and dangling hosts |
| Subdomain takeover risk | CNAME chains pointing to unclaimed services |
| Email-security score | SPF, DMARC, DKIM, DNSSEC, MTA-STS |
/history snapshots |
Track when SPF/DMARC or subdomains changed |
That is exactly the intelligence you need to turn “trust this domain” into a measurable check.
Auditing dependency-related domains
Let’s build a tiny Python script that scans the domains behind your npm dependencies. It extracts hostnames from resolved/homepage URLs, then queries the API for each one.
import json
import subprocess
import urllib.parse
import requests
RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY"
API_URL = "https://domain-whois2.p.rapidapi.com/whois"
HEADERS = {
"x-rapidapi-key": RAPIDAPI_KEY,
"x-rapidapi-host": "domain-whois2.p.rapidapi.com",
}
def extract_domain(url: str) -> str | None:
if not url:
return None
parsed = urllib.parse.urlparse(url)
host = parsed.netloc
if host.startswith("www."):
host = host[4:]
return host or None
def audit_domain(domain: str):
params = {
"domain": domain,
"subdomains": "true",
"takeover": "true",
"email_security": "true",
}
r = requests.get(API_URL, headers=HEADERS, params=params, timeout=30)
r.raise_for_status()
return r.json()
def main():
# Pull installed npm dependencies
npm_ls = subprocess.run(
["npm", "ls", "--json", "--silent"],
capture_output=True, text=True, check=False
)
tree = json.loads(npm_ls.stdout or "{}")
domains = set()
def walk(node):
for pkg, info in (node or {}).items():
if not isinstance(info, dict):
continue
for url_field in ("resolved", "homepage"):
domains.add(extract_domain(info.get(url_field, "")))
walk(info.get("dependencies", {}))
walk(tree.get("dependencies", {}))
print(f"Auditing {len(domains)} unique dependency-related domains...")
for d in sorted(domains):
if not d:
continue
try:
report = audit_domain(d)
whois = report.get("whois", {})
email = report.get("email_security", {})
takeovers = report.get("takeover_risk", [])
flags = []
if whois.get("domain_age_days", 9999) < 90:
flags.append("very young domain")
if whois.get("expiry_date") and "2025" not in str(whois.get("expiry_date")):
flags.append("check expiry")
if email.get("score", 0) < 50:
flags.append("weak email security")
if takeovers:
flags.append(f"{len(takeovers)} takeover risks")
print(f" {d}: {', '.join(flags) if flags else 'OK'}")
except Exception as e:
print(f" {d}: error ({e})")
if __name__ == "__main__":
main()
Run it in a repo after npm install and you’ll get a quick risk map of the domains your build pipeline implicitly trusts.
Detecting subdomain takeover risk
Subdomain takeover happens when a DNS CNAME still points to a cloud service (GitHub Pages, Heroku, AWS S3, etc.) that no longer claims the target. The API flags these for you.
Example JSON excerpt:
{
"takeover_risk": [
{
"subdomain": "docs.example-package.dev",
"cname": "example-package.github.io.",
"service": "GitHub Pages",
"claimable": true,
"http_status": 404
}
]
}
If docs.example-package.dev hosts your package README or install instructions, an attacker can register the missing GitHub Pages repo and serve malicious content under your official subdomain. Fix: remove the dangling CNAME or reclaim the cloud resource immediately.
Verifying email-security posture
Package registries and CI systems often email maintainers about publish events, password resets, or security advisories. If a maintainer’s domain lacks SPF, DMARC, DKIM, DNSSEC, or MTA-STS, phishing that domain becomes trivial.
The API returns a normalized score:
report = audit_domain("example.com")
email = report.get("email_security", {})
print(f"Email security score: {email.get('score')}/100")
for check in email.get("checks", []):
print(f" {check['name']}: {check['status']}")
Aim for:
-
SPF
~allor-all -
DMARC
p=rejectorp=quarantine - DKIM valid selector present
- DNSSEC enabled
- MTA-STS policy published
How to use Domain WHOIS API
Sign up at the RapidAPI listing: https://rapidapi.com/On13uka/api/domain-whois2, subscribe, and copy your API key.
cURL
curl --request GET \
--url 'https://domain-whois2.p.rapidapi.com/whois?domain=example.com&subdomains=true&takeover=true&email_security=true' \
--header 'x-rapidapi-key: YOUR_RAPIDAPI_KEY' \
--header 'x-rapidapi-host: domain-whois2.p.rapidapi.com'
Python
import requests
url = "https://domain-whois2.p.rapidapi.com/whois"
headers = {
"x-rapidapi-key": "YOUR_RAPIDAPI_KEY",
"x-rapidapi-host": "domain-whois2.p.rapidapi.com",
}
params = {
"domain": "example.com",
"subdomains": "true",
"takeover": "true",
"email_security": "true",
}
r = requests.get(url, headers=headers, params=params)
print(r.json())
For more examples and issue tracking, check the GitHub repo: https://github.com/On13uka/domain-whois-api.
Historical snapshots with /history
Supply-chain infrastructure changes over time. A domain that had strong DMARC last quarter might drop it today. Use the /history endpoint to diff email-security and subdomain states:
curl --request GET \
--url 'https://domain-whois2.p.rapidapi.com/history?domain=example.com&days=90' \
--header 'x-rapidapi-key: YOUR_RAPIDAPI_KEY' \
--header 'x-rapidapi-host: domain-whois2.p.rapidapi.com'
Store these diffs in a security dashboard and alert when SPF/DMARC degrade or new subdomains appear.
Conclusion
The Shai-Hulud/Keyv incident is another wake-up call: supply-chain security is not just about code signing and dependency pinning. Attackers exploit the edges of the software ecosystem—expired domains, dangling subdomains, and weak email authentication.
Adding a Domain WHOIS API audit to your CI/CD or threat-intel pipeline gives you a low-noise, high-signal way to catch those infrastructure risks before they become backdoors. Start by auditing the domains behind your top dependencies, flag takeover risks, and enforce a minimum email-security score. It won’t stop every attack—but it will close a door that too many attackers still find wide open.
Top comments (0)