namecheap-dns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited namecheap-dns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Manage DNS records at Namecheap via the XML API. The API has two quirks that bite first-time users:
pre-whitelisted at Namecheap → Profile → Tools → Namecheap API Access → Whitelisted IPs. Sandbox IPs change between sessions; always confirm with `curl -s https://api.ipify.org` first. If you get error 1011150 Invalid request IP: <ip>, ask the user to add that IP to the whitelist.
setHosts REPLACES every record on the domain. You must getHosts first, then resend ALL existing records plus your new one.
NAMECHEAP_API_KEY — present in sandbox envApiUser / UserName — the Namecheap account username (NOT theAPI key). Set this to your Namecheap account username.
Production: https://api.namecheap.com/xml.response Sandbox: https://api.sandbox.namecheap.com/xml.response (separate account; usually you want production)
MY_IP=$(curl -s https://api.ipify.org)
curl -s -G "https://api.namecheap.com/xml.response" \
--data-urlencode "ApiUser=$NAMECHEAP_API_USER" \
--data-urlencode "ApiKey=$NAMECHEAP_API_KEY" \
--data-urlencode "UserName=$NAMECHEAP_API_USER" \
--data-urlencode "ClientIp=$MY_IP" \
--data-urlencode "Command=namecheap.domains.dns.getHosts" \
--data-urlencode "SLD=your-app" \
--data-urlencode "TLD=ai"Parse the XML response — each record looks like:
<host HostId="498699225" Name="www" Type="CNAME"
Address="your-app.fly.dev." MXPref="10" TTL="300"
IsActive="true" />Quick parse with grep:
echo "$RESP" | grep -oE 'Name="[^"]+" Type="[^"]+" Address="[^"]+"'You MUST include every existing record you want to keep, plus the new one. Forgetting any record will silently delete it.
MY_IP=$(curl -s https://api.ipify.org)
curl -s -G "https://api.namecheap.com/xml.response" \
--data-urlencode "ApiUser=$NAMECHEAP_API_USER" \
--data-urlencode "ApiKey=$NAMECHEAP_API_KEY" \
--data-urlencode "UserName=$NAMECHEAP_API_USER" \
--data-urlencode "ClientIp=$MY_IP" \
--data-urlencode "Command=namecheap.domains.dns.setHosts" \
--data-urlencode "SLD=your-app" \
--data-urlencode "TLD=ai" \
--data-urlencode "EmailType=FWD" \
\
`# existing record 1 (apex A)` \
--data-urlencode "HostName1=@" \
--data-urlencode "RecordType1=A" \
--data-urlencode "Address1=66.241.124.148" \
--data-urlencode "TTL1=300" \
\
`# existing record 2 (apex AAAA)` \
--data-urlencode "HostName2=@" \
--data-urlencode "RecordType2=AAAA" \
--data-urlencode "Address2=2a09:8280:1::e7:30bb:1" \
--data-urlencode "TTL2=300" \
\
`# NEW record: docs.example.com → Fly` \
--data-urlencode "HostName5=docs" \
--data-urlencode "RecordType5=CNAME" \
--data-urlencode "Address5=131zmog.your-docs-app.fly.dev." \
--data-urlencode "TTL5=300"Success response contains Status="OK" and IsSuccess="true".
# 1. On Fly: create cert (issues challenge + provisions LB hostname)
fly certs add subdomain.example.com -a my-app
# 2. Get the recommended CNAME target from Fly
fly certs setup subdomain.example.com -a my-app
# → CNAME subdomain.example.com → <hash>.my-app.fly.dev
# 3. Add CNAME at Namecheap (use setHosts pattern above)
# 4. Wait for DNS propagation (60-120s usually)
# Sandbox local DNS is slow; verify via Cloudflare DoH:
curl -s "https://1.1.1.1/dns-query?name=subdomain.example.com&type=CNAME" \
-H "accept: application/dns-json"
# 5. Verify cert issued
fly certs check subdomain.example.com -a my-app
# → "Status = Issued" + "Certificate is verified and active"
# 6. Test (sandbox DNS may lag; use --resolve to force):
APP_IP=$(curl -s -G "https://1.1.1.1/dns-query?name=my-app.fly.dev&type=A" \
-H "accept: application/dns-json" | python3 -c "import sys,json; print(json.load(sys.stdin)['Answer'][0]['data'])")
curl -sI --resolve subdomain.example.com:443:$APP_IP \
https://subdomain.example.com/| Error code | Meaning | Fix |
|---|---|---|
1011150 Invalid request IP | Sandbox IP not whitelisted | Get IP via curl https://api.ipify.org, ask user to whitelist at Namecheap → Profile → Tools → API |
1011102 API Key invalid / API access not enabled | Wrong key, or production/sandbox endpoint mismatch | Check NAMECHEAP_API_KEY env var, use api.namecheap.com (NOT sandbox) |
| Records silently deleted | Forgot to resend in setHosts | Always getHosts first; build full record list including additions |
| MX records on subdomain silently dropped | EmailType=FWD blocks subdomain MX | Use EmailType=MX and resend all apex MX records explicitly (eforward1-5) |
| Long DKIM TXT record dropped | Sometimes works on retry | Resend the same setHosts call once or twice — Namecheap occasionally rejects long TXT silently and accepts it on retry |
Resend gives you 3 records to add:
resend._domainkey TXT (DKIM)send MX → feedback-smtp.us-east-1.amazonses.comsend TXT (SPF)Critical: must use EmailType=MX, not FWD. If domain currently uses Namecheap email forwarding, include eforward1-5 MX records explicitly:
HostName=@ Type=MX Address=eforward1.registrar-servers.com. MXPref=10
HostName=@ Type=MX Address=eforward2.registrar-servers.com. MXPref=10
HostName=@ Type=MX Address=eforward3.registrar-servers.com. MXPref=10
HostName=@ Type=MX Address=eforward4.registrar-servers.com. MXPref=15
HostName=@ Type=MX Address=eforward5.registrar-servers.com. MXPref=20
HostName=@ Type=TXT Address="v=spf1 include:spf.efwd.registrar-servers.com ~all"Reusable helper; takes JSON list of records on stdin, produces the form-encoded request:
#!/bin/bash
# Usage: cat records.json | ./setHosts.sh your-app ai
# records.json: [{"name":"docs","type":"CNAME","address":"...","ttl":"300"}, ...](Build this if you need to do many records; for one-off CNAMEs the inline curl above is fine.)
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.