The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Dns listing page.
Know where you stand.
Source-available DNS & email security scanner for Claude, Cursor, VS Code, and MCP clients across Streamable HTTP, stdio, and legacy HTTP+SSE.
Claude Desktop (one-click install):
Download the Blackveil DNS extension and open it — the current 80-tool surface is available instantly. Verify your download.
Claude Code (one command):
Then ask: scan anthropic.com
Smithery (one command):
Verify the endpoint is live:
No install. No API key. One URL for hosted HTTP:
Transport support:
Streamable HTTP: POST /mcp, GET /mcp, DELETE /mcpNative stdio: blackveil-dns-mcp CLI from the blackveil-dns npm packageLegacy HTTP+SSE: GET /mcp/sse bootstrap stream plus POST /mcp/messages?sessionId=...For Streamable HTTP, clients should retain the Mcp-Session-Id returned by initialize and send it on every subsequent request, including notifications. Send the negotiated version in MCP-Protocol-Version; unsupported values are rejected with HTTP 400, while expired or terminated sessions return 404 and require a fresh initialize.
spf delegation label, then cross-references DMARC enforcement to determine real exposuregenerate (artifact=fix_plan) produces provider-aware prioritized actions; its record artifacts (spf_record, dmarc_record, dkim_config, mta_sts_policy, rollout_plan) output ready-to-publish records; validate_fix confirms whether a fix was applied successfullymap_supply_chain correlates DNS signals to build a full third-party dependency graph with trust levels and risk signalssimulate_attack_paths enumerates specific paths (spoofing, takeover, hijack) with severity, steps, and mitigationsmap_compliance maps scan findings to NIST 800-177, PCI DSS 4.0, SOC 2, and CIS Controlscheck_authoritative_dns_infra and check_root_server_set query authoritative and root nameservers directly over TCP/53, and for authenticated callers check_authoritative_dns_infra also tests whether a domain's nameservers refuse a zone transfer (no zone data is retrieved)_meta)tools/list returns every tool with server-specific discovery metadata under each tool's _meta (the MCP-sanctioned extension point), so a client can group or filter the surface without hard-coding tool names:
group — functional group (email_auth, infrastructure, brand_threats, dns_hygiene, intelligence, remediation, discovery, identity_secops, meta).tier — scoring tier (core / protective / hardening); absent for non-scoring tools.scanIncluded — true when the tool runs inside scan_domain's parallel audit.recommended — present (true) only on the curated starter set (scan_domain, explain_finding, compare_baseline); omitted otherwise. A client facing the full surface can lead with tools.filter(t => t._meta.recommended) to avoid overwhelming an LLM with all tools flat. Every tool is still listed — this is an additive signal, not a filter.check_authoritative_dns_infra measures authoritative DNS infrastructure posture for a hostname over direct DNS-over-TCP/53 from a single vantage, via the BV_INFRA_PROBE service binding: TCP/53 reachability, the authoritative AA flag, recursion exposure, SOA serial consistency across nameservers, DNSKEY/RRSIG presence (not validation), IPv4/IPv6 answer parity, and unsupported-query handling. For authenticated callers only, it also runs a zone-transfer refusal test (first response only — no zone data is ever retrieved) and CHAOS version.bind/id.server disclosure. It does not measure, and reports as inconclusive: UDP/53 reachability, amplification, EDNS large-response/truncation, DNS cookies/RRL, BGP origin, RPKI, route-leak signals, anycast diversity, vantage latency, and RIR/RDAP.
check_root_server_set queries a rotating sample of 3 root servers per call and compares the priming NS set, glue, SOA serials, and cross-root consistency with the embedded official root hints, via BV_INFRA_PROBE.
Self-hosted or local deployments without BV_INFRA_PROBE still return structured partial results. The worker-only mode records the embedded root hints and marks every live-probe capability inconclusive rather than pretending it ran; both tools then withhold their verdict (checkStatus: 'error', excluded from scoring) instead of grading reference data.
The server classifies detected MCP clients by their default response format:
claude_mobile, claude_code, cursor, vscode, claude_desktop, claude_connector, windsurf (auto-format: compact)mcp_remote, blackveil_dns_action, bv_claude_dns_proxy, unknown (auto-format: full)The bv_load_test class identifies internal load/chaos/tranco-scan traffic so it stays out of real-client analytics segments.
The comprehensive chaos suite validates session stability, authentication precedence, format negotiation, and transport-specific edge cases across Streamable HTTP and Legacy SSE for its supported client fixtures. Without an API key it exercises the public/free-tier path; with a valid key exported as BV_API_KEY, it covers Bearer authentication, legacy self-host ?api_key= compatibility, authenticated SSE bootstrap, and authenticated batch behavior.
Run the client/session chaos suite locally: python3 scripts/chaos/chaos-test-clients.py.
Run repeat force-refresh scans to detect production scoring drift:
The stability harness negotiates MCP protocol 2025-06-18, accepts JSON and Streamable HTTP SSE responses, and exits non-zero on any transport/tool error or score/category drift. Use --from <json-file> with a JSON array of domains for a targeted provider-diversity sweep.
SSOT guardrails are enforced by focused audit tests:
TOOLS registry, not hand-written — npm run generate:tool-surface rewrites every advertised count, and npm run check:tool-surface fails CI if any drifts. Counts advertised to clients use the public surface (TOOLS minus internal-only tools), so the number in the docs, the badge, the VS Code listing and the resources/read copy is the number tools/list actually returns.Every scan_domain / batch_scan result carries three reproducibility stamps. They are three different namespaces — do not compare them to each other, and do not read any of them as the npm package version unless it says so:
| Field | What it tracks | How often it moves |
|---|---|---|
scoringModelVersion | The scoring policy: category weights, profile weights, grade thresholds, severity penalties, the passed/missing-control rule, profile detection. | Only when a change alters scores or grades. Slowly — most releases do not touch it. |
dnsChecksPackageVersion | The @blackveil/dns-checks engine package version bundled by the running build. | Every package release — code, new detections, bug fixes. |
scoringConfigHash | Fingerprint of the effective scoring configuration that produced this result, including any SCORING_CONFIG override. | Whenever the effective config differs. |
scoringModelVersion is independent of dnsChecksPackageVersion and is normally lower — for example model 1.10.0 alongside package 1.18.0. That is not a version gap, and it does not mean a consumer's vendored copy scores differently from the hosted service: the package advanced eight minors without changing scoring policy. Reading the model version as the package version has twice triggered a false "engine version gap" investigation, which is why both are now emitted side by side.
When you publish or cite a score, record scoringConfigHash — not either version number. It is the value that identifies the exact scoring configuration behind a result, so two scans carrying the same hash were graded under the same rules.
GET /badge/<domain> returns an embeddable SVG — the badge at the top of this README is a live scan of our own domain. It needs no authentication and is subject to the same anonymous rate limits and daily caps as a public scan.
The badge shows the same customer-facing letter scan_domain reports — the NIST-aligned 6-band grade (A+ ≥95, A ≥90, B ≥80, C ≥70, D ≥60, F <60) — so a domain cannot show one grade on its badge and a different one in its report. Two further states are stated rather than papered over:
<grade> partial — the scan was graded, but did not complete every check (a WAF challenge, a timeout, an unreachable host). The hover/aria title gives the exact coverage, e.g. 17 of 19 checks measured. The grade and its colour are unchanged: coverage and posture are different axes.unknown — the domain could not be measured at all. The badge says so instead of substituting a letter, which would publish a failing grade nobody measured.See docs/scoring.md for the grade scales and the evidence rules behind them.
BV_INFRA_PROBE service binding supplies live DNS-over-TCP/53 authoritative DNS and root-server evidence for the authoritative DNS infrastructure profilebv-wasm-corecompact vs full) based on client User-Agentdiscover_brand_domains / brand_audit_*)The discovery_mode argument accepts two values:
classic (the default everywhere this repo runs out-of-the-box) — the public, BUSL-licensed signal-sweep pipeline. Uses only public-internet data sources (DNS, RDAP, CT logs, MX/TXT inspection). This is the only mode supported for self-hosted deployments and the only mode the open test suite covers end-to-end.tiered — layers a portfolio-aware Tier 0 / infrastructure-graph Tier 1 / declared-evidence Tier 2 pipeline in front of the classic sweep. Tiered mode requires private BlackVeil-internal cross-Worker bindings (BV_INFRA_GRAPH, BV_INTEL_GATEWAY, BV_ENTERPRISE) that are not packaged with the open distribution — they live in BlackVeil's production deploy overlay (.dev/wrangler.deploy.jsonc) and call into proprietary Workers. Self-hosters cannot enable tiered mode without those bindings.BlackVeil's hosted production at dns-mcp.blackveilsecurity.com flips its runtime default to tiered via the env var BRAND_AUDIT_DISCOVERY_MODE_DEFAULT="tiered" in the private overlay; the public schema default in src/schemas/tool-args.ts stays 'classic' permanently so anyone building from main gets the BUSL-licensed behaviour unchanged. An explicit caller-supplied discovery_mode always wins over the env default.
The free tier requires no authentication. Authenticated requests bypass per-IP rate limits and follow your tier's daily quota. Hosted production supports:
Authorization: Bearer <KEY>X-API-Key: <KEY> — for clients that cannot set Authorization. If both are sent, Authorization: Bearer wins.ENABLE_OAUTH=true; owner-key consent is separately gated by ENABLE_OWNER_OAUTH=true.The ?api_key=<KEY> fallback is legacy/self-host compatibility only. BlackVeil hosted production sets REJECT_QUERY_API_KEY=true; clients that cannot send headers should use OAuth or an mcp-remote header bridge.
For full hosted setup examples, stdio usage, OAuth setup, and legacy fallback endpoints, see docs/client-setup.md.
These settings apply to operators running their own deployment. They are optional — self-hosted (BUSL) deployments fall back to privacy-preserving defaults when they are unset.
The public /mcp path writes a per-event access log enriched with geolocation and network identity. The write path, PII depth, and retention are operator-controlled:
| Binding / var | Type | Purpose |
|---|---|---|
MCP_ANALYTICS_QUEUE | Queue | Operator-deploy only. Batches access-log writes off the request path. Absent on self-hosts → inline-insert fallback (no reverse-DNS lookup). |
ANALYTICS_PII_LEVEL | var | coarse (default) | standard | full. Controls access-log PII depth: coarse = country/region/ASN + hashed/masked IP; standard adds encrypted IP + city; full adds lat/long + reverse-DNS (PTR). |
ANALYTICS_RETENTION_DAYS | var | Access-log retention window in days (default 90, clamped 1–365). Rows older than the window are pruned by the scheduled handler. |
| PTR third-party disclosure | — | At ANALYTICS_PII_LEVEL=full, caller-IP PTR lookups resolve through the configured DoH chain, whose final fallback is Google Public DNS — an external disclosure of caller-IP-derived queries that operators should weigh before enabling full. Per-subject erasure: POST /internal/analytics/erase?key_hash=…|ip_hash=… (strict internal bearer; self-audited). |
These live under the internal auth gate (/internal/*) and are called by bv-web, not the public surface:
| Endpoint | Source | Notes |
|---|---|---|
GET /internal/analytics/usage?days=&key_hash= | D1 | Precise per-customer usage report. |
GET /internal/analytics/geo?days= | Analytics Engine | Geographic rollup (country/region/city/ASN) for dashboards. |
GET /internal/analytics/forensics?days=&ip_hash=&key_hash= | D1 | STRICT-gated, operator-only. Returns decrypted client IP + PTR for abuse investigation; every call writes a self-audit row. |
| Free | Pro | Enterprise | |
|---|---|---|---|
| Price | $0 | $39/mo | Contact us |
| Scans/day | 25 | 500 | 10,000+ |
| Checks/day | Tool-specific limits | Tool-specific limits | Contract limits |
| Rate limit | 50 req/min | None | None |
| API access | Yes | Yes | Yes |
| MCP access | Yes | Yes | Yes |
Offensive/recon and multi-domain tools (subdomain discovery, attack-path simulation, lookalike/shadow-domain detection, fast-flux detection, supply-chain mapping, real-time threat feed, bucket/OSINT investigations, batch_scan, compare_domains, brand audits) require a paid plan (Pro / developer tier or higher); free, unauthenticated, and agent-tier callers get an HTTP 403 upgrade-required response. Unauthenticated callers are additionally capped at a small number of distinct domains per day (best-effort, fail-open). The OSINT/bucket status and report pollers stay free.
These demonstrate core functionality — paste any of them into Claude with the Blackveil DNS connector enabled:
| Prompt | What it does |
|---|---|
Scan blackveilsecurity.com and tell me what needs fixing | Full security audit — score, grade, prioritized findings |
Compare the email security of google.com and microsoft.com | Side-by-side comparison of two domains' postures |
Generate a DMARC record for example.com with reject policy | Produces a ready-to-publish DNS record |
What attack paths exist for example.com? | Enumerates spoofing, takeover, and hijack vectors |
Map example.com's compliance against NIST 800-177 | Maps findings to compliance framework controls |
This tool is intended for authorized security assessments of domains you own or have explicit permission to test. Do not use it for unauthorized reconnaissance, harassment, or any activity that violates applicable laws. Findings from attack simulation, spoofability, and subdomain discovery tools should be used to improve your own security posture, not to exploit others.
If you discover a vulnerability in a third-party domain, please follow coordinated disclosure practices.
Built and maintained by BLACKVEIL — NZ-owned cybersecurity consultancy.
Privacy Policy · License (BUSL-1.1 → MIT on 2030-03-17)