blackveil-dns 1.4.2 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -19
- package/dist/index.d.ts +46 -145
- package/dist/index.js +4349 -3177
- package/dist/index.js.map +1 -1
- package/dist/stdio.js +10104 -7556
- package/dist/stdio.js.map +1 -1
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Open-source DNS & email security scanner for Claude, Cursor, VS Code, and MCP cl
|
|
|
9
9
|
[](https://github.com/MadaBurns/bv-mcp/stargazers)
|
|
10
10
|
[](https://www.npmjs.com/package/blackveil-dns)
|
|
11
11
|
[](https://www.npmjs.com/package/blackveil-dns)
|
|
12
|
-
[](https://github.com/MadaBurns/bv-mcp/actions)
|
|
13
13
|
[](https://github.com/MadaBurns/bv-mcp/actions)
|
|
14
14
|
[](LICENSE)
|
|
15
15
|
[](https://modelcontextprotocol.io/)
|
|
@@ -61,9 +61,14 @@ Transport support:
|
|
|
61
61
|
- **57+ checks across 20 categories** — SPF, DMARC, DKIM, DNSSEC, SSL/TLS, MTA-STS, NS, CAA, MX, BIMI, TLS-RPT, subdomain takeover, lookalike domains, HTTP security headers, DANE, shadow domains, TXT hygiene, MX reputation, SRV, zone hygiene
|
|
62
62
|
- **Maturity staging** — Stage 0-4 classification (Unprotected to Hardened) with next steps
|
|
63
63
|
- **Trust surface analysis** — detects shared SaaS platforms (Google, M365, SendGrid) and cross-references DMARC enforcement to determine real exposure
|
|
64
|
-
- **
|
|
64
|
+
- **Guided remediation** — `generate_fix_plan` produces prioritized actions; record generators output ready-to-publish SPF, DMARC, DKIM, and MTA-STS records
|
|
65
|
+
- **Spoofability scoring** — `assess_spoofability` computes a composite 0-100 email spoofability score from SPF trust surface, DMARC enforcement, and DKIM coverage with interaction multipliers
|
|
66
|
+
- **Intelligence layer** — `get_benchmark` and `get_provider_insights` expose anonymized aggregate insights from scan telemetry: percentile rankings, provider cohort comparisons, and 7-day trend analysis
|
|
67
|
+
- **Multi-resolver consistency** — `check_resolver_consistency` queries 4 public DoH resolvers to detect GeoDNS, split-horizon DNS, or poisoning
|
|
68
|
+
- **Interaction scoring** — correlated weaknesses (e.g., weak DKIM + permissive DMARC) receive additional penalties beyond individual finding scores
|
|
65
69
|
- **Self-tuning scoring** — adaptive weights adjust category importance based on patterns seen across scans, so scores reflect real-world failure distributions rather than static assumptions
|
|
66
70
|
- **Provider intelligence** — inbound/outbound email provider inference from MX, SPF, DKIM
|
|
71
|
+
- **Context-optimized** — tool schemas, prompts, and resources are tuned for minimal token consumption in LLM clients
|
|
67
72
|
- **Passive and read-only** — all checks use public Cloudflare DNS-over-HTTPS; no authorization required from the target
|
|
68
73
|
|
|
69
74
|
Full scope and limitations in the coverage table below.
|
|
@@ -72,7 +77,7 @@ Full scope and limitations in the coverage table below.
|
|
|
72
77
|
scan_domain("anthropic.com")
|
|
73
78
|
|
|
74
79
|
████████████████████████████████████████░░░░░ 85 / 100
|
|
75
|
-
Grade: A · Maturity:
|
|
80
|
+
Grade: A · Maturity: Enforcing
|
|
76
81
|
|
|
77
82
|
SPF ·········· 80 MTA-STS ····· 85
|
|
78
83
|
DMARC ········ 90 NS ·········· 95
|
|
@@ -95,7 +100,7 @@ Full scope and limitations in the coverage table below.
|
|
|
95
100
|
## Tools
|
|
96
101
|
|
|
97
102
|
```
|
|
98
|
-
|
|
103
|
+
33 MCP tools · 7 prompts · 6 resources
|
|
99
104
|
|
|
100
105
|
Email Auth Infrastructure Brand & Threats Meta
|
|
101
106
|
──────────── ──────────────── ───────────────── ──────────────
|
|
@@ -104,17 +109,25 @@ Full scope and limitations in the coverage table below.
|
|
|
104
109
|
check_dkim check_caa check_lookalikes compare_baseline
|
|
105
110
|
check_mta_sts check_ssl check_shadow_domains
|
|
106
111
|
check_mx check_http_security
|
|
107
|
-
check_mx_reputation check_dane
|
|
108
|
-
|
|
109
|
-
DNS Hygiene
|
|
110
|
-
────────────
|
|
111
|
-
check_txt_hygiene
|
|
112
|
+
check_mx_reputation check_dane Intelligence Remediation
|
|
113
|
+
check_dane_https ────────────── ──────────────
|
|
114
|
+
DNS Hygiene check_svcb_https get_benchmark generate_fix_plan
|
|
115
|
+
──────────── check_srv get_provider_ generate_spf_record
|
|
116
|
+
check_txt_hygiene check_zone_hygiene insights generate_dmarc_record
|
|
117
|
+
check_resolver_ assess_spoofability generate_dkim_config
|
|
118
|
+
consistency generate_mta_sts_policy
|
|
112
119
|
|
|
113
120
|
+ check_subdomain_takeover (internal — runs inside scan_domain)
|
|
114
121
|
```
|
|
115
122
|
|
|
116
123
|
`explain_finding` takes any finding and returns: what it means, potential impact, adverse consequences, specific steps to fix, and relevant RFCs.
|
|
117
124
|
|
|
125
|
+
`generate_fix_plan` scans a domain and produces a prioritized remediation plan with effort, impact, and dependency metadata. The record generators (`generate_spf_record`, `generate_dmarc_record`, `generate_dkim_config`, `generate_mta_sts_policy`) produce ready-to-publish DNS records based on detected configuration.
|
|
126
|
+
|
|
127
|
+
`get_benchmark` and `get_provider_insights` expose anonymized aggregate data from scan telemetry — percentile rankings, provider cohort scores, and 7-day trend analysis. `assess_spoofability` computes a composite email spoofability score (0-100) from SPF, DMARC, and DKIM with interaction multipliers.
|
|
128
|
+
|
|
129
|
+
`check_resolver_consistency` queries Cloudflare, Google, Quad9, and OpenDNS in parallel to detect GeoDNS, split-horizon DNS, or potential poisoning.
|
|
130
|
+
|
|
118
131
|
**Confidence labels:**
|
|
119
132
|
`deterministic` — direct protocol/record validation | `heuristic` — signal-based inference, may need manual validation | `verified` — high-confidence validation signal
|
|
120
133
|
|
|
@@ -125,6 +138,8 @@ Full scope and limitations in the coverage table below.
|
|
|
125
138
|
|
|
126
139
|
## Client setup
|
|
127
140
|
|
|
141
|
+
The free tier requires no authentication. If you have an API key, see the **With API key** tabs below to bypass rate limits.
|
|
142
|
+
|
|
128
143
|
<details>
|
|
129
144
|
<summary><b>VS Code / Copilot</b></summary>
|
|
130
145
|
|
|
@@ -140,6 +155,30 @@ Full scope and limitations in the coverage table below.
|
|
|
140
155
|
}
|
|
141
156
|
}
|
|
142
157
|
```
|
|
158
|
+
|
|
159
|
+
**With API key:**
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"servers": {
|
|
164
|
+
"blackveil-dns": {
|
|
165
|
+
"type": "http",
|
|
166
|
+
"url": "https://dns-mcp.blackveilsecurity.com/mcp",
|
|
167
|
+
"headers": {
|
|
168
|
+
"Authorization": "Bearer ${input:bv-api-key}"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"inputs": [
|
|
173
|
+
{
|
|
174
|
+
"id": "bv-api-key",
|
|
175
|
+
"type": "promptString",
|
|
176
|
+
"description": "Blackveil DNS API key",
|
|
177
|
+
"password": true
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
```
|
|
143
182
|
</details>
|
|
144
183
|
|
|
145
184
|
<details>
|
|
@@ -163,6 +202,33 @@ Or via CLI:
|
|
|
163
202
|
```bash
|
|
164
203
|
claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.com/mcp
|
|
165
204
|
```
|
|
205
|
+
|
|
206
|
+
**With API key** — use `mcp-remote` to reliably forward the auth header:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"mcpServers": {
|
|
211
|
+
"blackveil-dns": {
|
|
212
|
+
"command": "npx",
|
|
213
|
+
"args": [
|
|
214
|
+
"mcp-remote",
|
|
215
|
+
"https://dns-mcp.blackveilsecurity.com/mcp",
|
|
216
|
+
"--header",
|
|
217
|
+
"Authorization: Bearer YOUR_API_KEY"
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Or via CLI:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
claude mcp add-json blackveil-dns \
|
|
228
|
+
'{"command":"npx","args":["mcp-remote","https://dns-mcp.blackveilsecurity.com/mcp","--header","Authorization: Bearer YOUR_API_KEY"]}'
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
> **Why `mcp-remote`?** Claude Code's native HTTP transport does not currently forward custom `headers` from config files. The `mcp-remote` bridge reliably passes the `Authorization` header to the server. Restart Claude Code after adding the server.
|
|
166
232
|
</details>
|
|
167
233
|
|
|
168
234
|
<details>
|
|
@@ -170,7 +236,25 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
|
|
|
170
236
|
|
|
171
237
|
**Recommended:** Open [claude.ai](https://claude.ai) → **Settings → Connectors → Add custom connector** → paste `https://dns-mcp.blackveilsecurity.com/mcp`.
|
|
172
238
|
|
|
173
|
-
**
|
|
239
|
+
**With API key** — open **Settings → Developer → Edit Config** (`claude_desktop_config.json`) and add:
|
|
240
|
+
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"mcpServers": {
|
|
244
|
+
"blackveil-dns": {
|
|
245
|
+
"command": "npx",
|
|
246
|
+
"args": [
|
|
247
|
+
"mcp-remote",
|
|
248
|
+
"https://dns-mcp.blackveilsecurity.com/mcp",
|
|
249
|
+
"--header",
|
|
250
|
+
"Authorization: Bearer YOUR_API_KEY"
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Without API key (local stdio):** If you want first-party local stdio instead of the hosted HTTP connector:
|
|
174
258
|
|
|
175
259
|
```json
|
|
176
260
|
{
|
|
@@ -184,8 +268,6 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
|
|
|
184
268
|
}
|
|
185
269
|
```
|
|
186
270
|
|
|
187
|
-
> Prefer the direct custom connector above when possible. The stdio route runs the server locally and depends on Node.js being available to Claude Desktop.
|
|
188
|
-
>
|
|
189
271
|
> On macOS GUI apps, `npx` may not resolve from `PATH`; if Homebrew is installed elsewhere, replace `/opt/homebrew/bin/npx` with your actual `npx` path. After editing the config, fully restart Claude Desktop. If you already have other servers, merge `"blackveil-dns"` into your existing `"mcpServers"` object — don't paste a second `{ }` wrapper.
|
|
190
272
|
|
|
191
273
|
</details>
|
|
@@ -204,6 +286,52 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
|
|
|
204
286
|
}
|
|
205
287
|
}
|
|
206
288
|
```
|
|
289
|
+
|
|
290
|
+
**With API key:**
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"mcpServers": {
|
|
295
|
+
"blackveil-dns": {
|
|
296
|
+
"url": "https://dns-mcp.blackveilsecurity.com/mcp",
|
|
297
|
+
"headers": {
|
|
298
|
+
"Authorization": "Bearer YOUR_API_KEY"
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
</details>
|
|
305
|
+
|
|
306
|
+
<details>
|
|
307
|
+
<summary><b>Windsurf</b></summary>
|
|
308
|
+
|
|
309
|
+
`~/.codeium/windsurf/mcp_config.json`
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"mcpServers": {
|
|
314
|
+
"blackveil-dns": {
|
|
315
|
+
"serverUrl": "https://dns-mcp.blackveilsecurity.com/mcp"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**With API key:**
|
|
322
|
+
|
|
323
|
+
```json
|
|
324
|
+
{
|
|
325
|
+
"mcpServers": {
|
|
326
|
+
"blackveil-dns": {
|
|
327
|
+
"serverUrl": "https://dns-mcp.blackveilsecurity.com/mcp",
|
|
328
|
+
"headers": {
|
|
329
|
+
"Authorization": "Bearer YOUR_API_KEY"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
207
335
|
</details>
|
|
208
336
|
|
|
209
337
|
For hosted MCP setup, stdio usage, and legacy fallback endpoints, see `docs/client-setup.md`.
|
|
@@ -231,6 +359,30 @@ Get weekly DNS security reports in Slack or Discord. See [`examples/slack-discor
|
|
|
231
359
|
|
|
232
360
|
---
|
|
233
361
|
|
|
362
|
+
## Pricing
|
|
363
|
+
|
|
364
|
+
Full API and MCP access at every tier — no enterprise gatekeeping.
|
|
365
|
+
|
|
366
|
+
| | **Free** | **Pro** | **Enterprise** |
|
|
367
|
+
|---|---|---|---|
|
|
368
|
+
| **Price** | $0 | $39/mo ($29/mo annual) | [Contact us](https://blackveilsecurity.com) |
|
|
369
|
+
| **Scans/day** | 75 | 500 | 10,000+ |
|
|
370
|
+
| **Checks/day** (per tool) | 200 | 5,000 | Unlimited |
|
|
371
|
+
| **Lookalike / Shadow scans** | 20/day | 200/day | Unlimited |
|
|
372
|
+
| **Rate limit** | 50 req/min | None | None |
|
|
373
|
+
| **API access** | Yes | Yes | Yes |
|
|
374
|
+
| **MCP access** | Yes | Yes | Yes |
|
|
375
|
+
| **GitHub Action** | Yes | Yes | Yes |
|
|
376
|
+
| **Batch API** | — | — | Up to 500 domains/call |
|
|
377
|
+
| **SLA** | Best effort | 99.5% | 99.9% + custom |
|
|
378
|
+
| **Support** | Community | Email | Dedicated |
|
|
379
|
+
|
|
380
|
+
The free tier is generous by design — use it for personal projects, evaluations, and AI agent integrations with no strings attached. Upgrade when you need higher throughput.
|
|
381
|
+
|
|
382
|
+
Get an API key at [blackveilsecurity.com](https://blackveilsecurity.com).
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
234
386
|
## npm package
|
|
235
387
|
|
|
236
388
|
Install from npm when you want to call the scanner from your own Node.js app, script, or service. If you are connecting from VS Code, Claude, Cursor, or another MCP client, use the MCP endpoint configuration above instead.
|
|
@@ -365,9 +517,9 @@ Run `explain_finding` on any result for plain-English remediation.
|
|
|
365
517
|
| `POST` | `/internal/tools/call` | Service binding: single tool call (no auth/rate limits) |
|
|
366
518
|
| `POST` | `/internal/tools/batch` | Service binding: bulk scan up to 500 domains |
|
|
367
519
|
|
|
368
|
-
Supported methods: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`.
|
|
520
|
+
Supported methods: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`, `prompts/list`, `prompts/get`.
|
|
369
521
|
|
|
370
|
-
|
|
522
|
+
7 pre-built prompts guide common workflows: `full-security-audit`, `email-auth-check`, `policy-compliance-check`, `remediation-workflow`, `email-hardening-guide`, `provider-benchmark`, `attack-surface-assessment`.
|
|
371
523
|
|
|
372
524
|
</details>
|
|
373
525
|
|
|
@@ -390,7 +542,7 @@ Prompt methods (`prompts/list`, `prompts/get`) return `-32601 Method not found`.
|
|
|
390
542
|
│
|
|
391
543
|
┌───▼──────────────────────┐
|
|
392
544
|
│ Tool Handlers │
|
|
393
|
-
│
|
|
545
|
+
│ 16 checks in parallel │
|
|
394
546
|
└───┬──────────────────────┘
|
|
395
547
|
│
|
|
396
548
|
┌───▼──────────────────────┐
|
|
@@ -406,6 +558,9 @@ Prompt methods (`prompts/list`, `prompts/get`) return `-32601 Method not found`.
|
|
|
406
558
|
- `scan_domain` capped at 75/day per IP (results cached 5 min)
|
|
407
559
|
- Scan result caching (KV + in-memory fallback)
|
|
408
560
|
- Adaptive scoring via Durable Object telemetry (graceful fallback to static weights)
|
|
561
|
+
- Intelligence layer: score histograms, provider cohort benchmarks, hourly trend snapshots (ProfileAccumulator DO)
|
|
562
|
+
- Category interaction scoring: correlated weaknesses receive additional penalties
|
|
563
|
+
- Context-optimized schemas: tool descriptions, prompts, and resources tuned for minimal LLM token consumption
|
|
409
564
|
- Structured JSON logging
|
|
410
565
|
|
|
411
566
|
Implementation details in `CLAUDE.md`.
|
|
@@ -422,10 +577,18 @@ Full details in `CLAUDE.md` (security and observability sections).
|
|
|
422
577
|
- SSRF protections block unsafe/private targets
|
|
423
578
|
- Error responses sanitized — only known validation errors surface
|
|
424
579
|
- DNS via Cloudflare DoH with optional secondary confirmation
|
|
425
|
-
-
|
|
580
|
+
- Constant-time auth comparison (XOR accumulation on SHA-256 digests)
|
|
581
|
+
- DNS data sanitized at ingestion — HTML/markdown injection stripped before findings are created
|
|
582
|
+
- Outbound response body caps (64 KB for tool checks, 1 MB for provider signatures)
|
|
583
|
+
- Tool parameter validation with allowlists and per-element type/length checks
|
|
584
|
+
- Rate limits: `50/min` and `300/hr` per IP for `tools/call` (free tier; Pro and Enterprise bypass)
|
|
426
585
|
- Control-plane traffic: `60/min` and `600/hr` per IP
|
|
427
586
|
- Global daily cap: `500,000` unauthenticated tool calls/day (cost ceiling)
|
|
428
|
-
-
|
|
587
|
+
- Authenticated requests: per-tier daily quotas keyed by API key hash (see [Pricing](#pricing))
|
|
588
|
+
- Session creation: `60/min` per IP (enforced on both modern and legacy transports)
|
|
589
|
+
- Session TTL: 2 hours idle, dual-write (KV + in-memory) for cross-isolate resilience
|
|
590
|
+
- SSE notification stream exempt from rate limiting (prevents `mcp-remote` reconnection storms)
|
|
591
|
+
- Client IPs redacted in structured logs
|
|
429
592
|
|
|
430
593
|
**Natural-language convenience:**
|
|
431
594
|
`tools/call` supports `scan` as an alias for `scan_domain`. In chat clients, say `scan example.com`. Raw JSON-RPC expects `params.name` to be `scan` or `scan_domain`.
|
|
@@ -464,7 +627,7 @@ npm run dev # localhost:8787/mcp
|
|
|
464
627
|
```
|
|
465
628
|
|
|
466
629
|
```bash
|
|
467
|
-
npm test #
|
|
630
|
+
npm test # 1469 tests
|
|
468
631
|
npm run typecheck
|
|
469
632
|
```
|
|
470
633
|
|
|
@@ -512,6 +675,6 @@ Featured in [SecurityBrief](https://securitybrief.co.nz/story/exclusive-how-cybe
|
|
|
512
675
|
|
|
513
676
|
Want continuous monitoring? [BLACKVEIL](https://blackveilsecurity.com) provides real-time alerting and Buck AI to help you fix what this scanner finds.
|
|
514
677
|
|
|
515
|
-
MIT
|
|
678
|
+
BUSL-1.1 License (converts to MIT on 2030-03-17)
|
|
516
679
|
|
|
517
680
|
</div>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { CheckResult, ScoringConfig, ScanScore, DomainContext } from '@blackveil/dns-checks/scoring';
|
|
2
|
+
export { CATEGORY_DISPLAY_WEIGHTS, CheckCategory, CheckResult, DomainContext, DomainProfile, Finding, FindingConfidence, SEVERITY_PENALTIES, ScanScore, Severity, buildCheckResult, computeCategoryScore, computeScanScore, createFinding, detectDomainContext, getProfileWeights, inferFindingConfidence, scoreToGrade } from '@blackveil/dns-checks/scoring';
|
|
3
|
+
export { parseDmarcTags } from '@blackveil/dns-checks';
|
|
4
|
+
|
|
1
5
|
/** Standard DNS record type codes */
|
|
2
6
|
declare const RecordType: {
|
|
3
7
|
readonly A: 1;
|
|
@@ -14,6 +18,7 @@ declare const RecordType: {
|
|
|
14
18
|
readonly RRSIG: 46;
|
|
15
19
|
readonly PTR: 12;
|
|
16
20
|
readonly SRV: 33;
|
|
21
|
+
readonly HTTPS: 65;
|
|
17
22
|
};
|
|
18
23
|
type RecordTypeName = keyof typeof RecordType;
|
|
19
24
|
/** A single DNS answer record from the DoH JSON response */
|
|
@@ -128,124 +133,6 @@ declare function queryMxRecords(domain: string, opts?: QueryDnsOptions): Promise
|
|
|
128
133
|
exchange: string;
|
|
129
134
|
}>>;
|
|
130
135
|
|
|
131
|
-
type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
132
|
-
type FindingConfidence = 'deterministic' | 'heuristic' | 'verified';
|
|
133
|
-
type CheckCategory = 'spf' | 'dmarc' | 'dkim' | 'dnssec' | 'ssl' | 'mta_sts' | 'ns' | 'caa' | 'subdomain_takeover' | 'mx' | 'bimi' | 'tlsrpt' | 'lookalikes' | 'shadow_domains' | 'txt_hygiene' | 'http_security' | 'dane' | 'mx_reputation' | 'srv' | 'zone_hygiene';
|
|
134
|
-
interface Finding {
|
|
135
|
-
category: CheckCategory;
|
|
136
|
-
title: string;
|
|
137
|
-
severity: Severity;
|
|
138
|
-
detail: string;
|
|
139
|
-
metadata?: Record<string, unknown>;
|
|
140
|
-
}
|
|
141
|
-
interface CheckResult {
|
|
142
|
-
category: CheckCategory;
|
|
143
|
-
passed: boolean;
|
|
144
|
-
score: number;
|
|
145
|
-
findings: Finding[];
|
|
146
|
-
}
|
|
147
|
-
interface ScanScore {
|
|
148
|
-
overall: number;
|
|
149
|
-
grade: string;
|
|
150
|
-
categoryScores: Record<CheckCategory, number>;
|
|
151
|
-
findings: Finding[];
|
|
152
|
-
summary: string;
|
|
153
|
-
}
|
|
154
|
-
/** Display/UI weight distribution for categories. NOT used in scoring — see IMPORTANCE_WEIGHTS for actual scoring weights. Exists for category registry and display purposes only. */
|
|
155
|
-
declare const CATEGORY_DISPLAY_WEIGHTS: Record<CheckCategory, number>;
|
|
156
|
-
/** Severity penalty multipliers applied to the category score */
|
|
157
|
-
declare const SEVERITY_PENALTIES: Record<Severity, number>;
|
|
158
|
-
/**
|
|
159
|
-
* Infer how strongly a finding can be trusted based on available evidence.
|
|
160
|
-
* - verified: explicit proof (currently only supported on takeover checks)
|
|
161
|
-
* - heuristic: signal-based or partial-evidence checks
|
|
162
|
-
* - deterministic: direct record/protocol validation
|
|
163
|
-
*/
|
|
164
|
-
declare function inferFindingConfidence(finding: Finding): FindingConfidence;
|
|
165
|
-
/**
|
|
166
|
-
* Compute the score for a single check category based on its findings.
|
|
167
|
-
* Starts at 100 and deducts points based on finding severities.
|
|
168
|
-
*/
|
|
169
|
-
declare function computeCategoryScore(findings: Finding[]): number;
|
|
170
|
-
/**
|
|
171
|
-
* Build a CheckResult from a category and its findings.
|
|
172
|
-
*/
|
|
173
|
-
declare function buildCheckResult(category: CheckCategory, findings: Finding[]): CheckResult;
|
|
174
|
-
/**
|
|
175
|
-
* Create a finding object with the given parameters.
|
|
176
|
-
*/
|
|
177
|
-
declare function createFinding(category: CheckCategory, title: string, severity: Severity, detail: string, metadata?: Record<string, unknown>): Finding;
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Runtime scoring configuration.
|
|
181
|
-
*
|
|
182
|
-
* All scoring weights, thresholds, and tuning constants are configurable
|
|
183
|
-
* via the `SCORING_CONFIG` environment variable (JSON string). The open-source
|
|
184
|
-
* codebase ships with reasonable defaults; production deployments can override
|
|
185
|
-
* any subset of values.
|
|
186
|
-
*
|
|
187
|
-
* Parse once at request entry and thread through the call chain — never
|
|
188
|
-
* re-parse per tool call.
|
|
189
|
-
*/
|
|
190
|
-
|
|
191
|
-
/** All tunable scoring parameters. */
|
|
192
|
-
interface ScoringConfig {
|
|
193
|
-
/** Base importance weights per check category (used when no profile context). */
|
|
194
|
-
weights: Record<CheckCategory, number>;
|
|
195
|
-
/** Per-profile importance weights. */
|
|
196
|
-
profileWeights: Record<DomainProfile, Record<CheckCategory, number>>;
|
|
197
|
-
/** Scoring thresholds and constants. */
|
|
198
|
-
thresholds: {
|
|
199
|
-
emailBonusImportance: number;
|
|
200
|
-
spfStrongThreshold: number;
|
|
201
|
-
criticalOverallPenalty: number;
|
|
202
|
-
criticalGapCeiling: number;
|
|
203
|
-
};
|
|
204
|
-
/** Grade boundaries (minimum score for each grade). */
|
|
205
|
-
grades: {
|
|
206
|
-
aPlus: number;
|
|
207
|
-
a: number;
|
|
208
|
-
bPlus: number;
|
|
209
|
-
b: number;
|
|
210
|
-
cPlus: number;
|
|
211
|
-
c: number;
|
|
212
|
-
dPlus: number;
|
|
213
|
-
d: number;
|
|
214
|
-
e: number;
|
|
215
|
-
};
|
|
216
|
-
/** Baseline failure rates for adaptive weight computation. */
|
|
217
|
-
baselineFailureRates: Record<string, number>;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
type DomainProfile = 'mail_enabled' | 'enterprise_mail' | 'non_mail' | 'web_only' | 'minimal';
|
|
221
|
-
interface DomainContext {
|
|
222
|
-
profile: DomainProfile;
|
|
223
|
-
signals: string[];
|
|
224
|
-
weights: Record<CheckCategory, ImportanceProfile>;
|
|
225
|
-
detectedProvider: string | null;
|
|
226
|
-
}
|
|
227
|
-
interface ImportanceProfile {
|
|
228
|
-
importance: number;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Detect domain context from completed check results.
|
|
232
|
-
* Pure function — reads findings metadata only, no DNS queries.
|
|
233
|
-
*/
|
|
234
|
-
declare function detectDomainContext(results: CheckResult[]): DomainContext;
|
|
235
|
-
/** Look up the weight table for a given profile, optionally from runtime config. */
|
|
236
|
-
declare function getProfileWeights(profile: DomainProfile, config?: ScoringConfig): Record<CheckCategory, ImportanceProfile>;
|
|
237
|
-
|
|
238
|
-
/** Map numeric score to letter grade */
|
|
239
|
-
declare function scoreToGrade(score: number, config?: ScoringConfig): string;
|
|
240
|
-
/**
|
|
241
|
-
* Compute the overall scan score from individual check results.
|
|
242
|
-
* Uses weighted average of category scores.
|
|
243
|
-
*
|
|
244
|
-
* When a `DomainContext` is provided, uses profile-specific weights,
|
|
245
|
-
* critical gap categories, and email bonus eligibility instead of defaults.
|
|
246
|
-
*/
|
|
247
|
-
declare function computeScanScore(results: CheckResult[], context?: DomainContext, config?: ScoringConfig): ScanScore;
|
|
248
|
-
|
|
249
136
|
/**
|
|
250
137
|
* Input sanitization and validation utilities for the DNS Security MCP Server.
|
|
251
138
|
* Handles domain validation, input cleaning, and MCP error response helpers.
|
|
@@ -272,7 +159,7 @@ declare function sanitizeDomain(input: string): string;
|
|
|
272
159
|
declare function sanitizeInput(input: string, maxLength?: number): string;
|
|
273
160
|
|
|
274
161
|
/** Server version — keep in sync with package.json */
|
|
275
|
-
declare const SERVER_VERSION = "
|
|
162
|
+
declare const SERVER_VERSION = "2.0.6";
|
|
276
163
|
|
|
277
164
|
/**
|
|
278
165
|
* Check BIMI records for a domain.
|
|
@@ -294,9 +181,6 @@ declare function checkCaa(domain: string, dnsOptions?: QueryDnsOptions): Promise
|
|
|
294
181
|
*/
|
|
295
182
|
declare function checkDkim(domain: string, selector?: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
|
|
296
183
|
|
|
297
|
-
/** Parse DMARC tag-value pairs from a DMARC record string. */
|
|
298
|
-
declare function parseDmarcTags(record: string): Map<string, string>;
|
|
299
|
-
|
|
300
184
|
/**
|
|
301
185
|
* Check DMARC records for a domain.
|
|
302
186
|
* Queries _dmarc.<domain> TXT records and validates policy configuration.
|
|
@@ -323,12 +207,6 @@ declare function checkLookalikes(domain: string): Promise<CheckResult>;
|
|
|
323
207
|
*/
|
|
324
208
|
declare function checkMtaSts(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
|
|
325
209
|
|
|
326
|
-
/**
|
|
327
|
-
* MX record check tool for MCP server.
|
|
328
|
-
* Validates presence and quality of MX records for a domain.
|
|
329
|
-
* Returns CheckResult with findings including RFC compliance, redundancy, and provider detection.
|
|
330
|
-
*/
|
|
331
|
-
|
|
332
210
|
interface CheckMxOptions {
|
|
333
211
|
providerSignaturesUrl?: string;
|
|
334
212
|
providerSignaturesAllowedHosts?: string[];
|
|
@@ -350,25 +228,12 @@ declare function checkNs(domain: string, dnsOptions?: QueryDnsOptions): Promise<
|
|
|
350
228
|
*/
|
|
351
229
|
declare function checkSpf(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
|
|
352
230
|
|
|
353
|
-
/**
|
|
354
|
-
* SSL/TLS certificate check tool.
|
|
355
|
-
* Validates SSL certificate by attempting HTTPS connection,
|
|
356
|
-
* checks HSTS configuration,
|
|
357
|
-
* and verifies HTTP→HTTPS redirect.
|
|
358
|
-
* Workers-compatible: uses fetch API only (cert expiry/chain require external APIs).
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
231
|
/**
|
|
362
232
|
* Check SSL/TLS configuration for a domain.
|
|
363
233
|
* Validates HTTPS connectivity, HSTS headers, and HTTP→HTTPS redirect.
|
|
364
234
|
*/
|
|
365
235
|
declare function checkSsl(domain: string): Promise<CheckResult>;
|
|
366
236
|
|
|
367
|
-
/**
|
|
368
|
-
* Subdomain Takeover / Dangling CNAME Detection Tool
|
|
369
|
-
* Scans known/active subdomains for orphaned CNAME records pointing to deleted/unresolved third-party services.
|
|
370
|
-
*/
|
|
371
|
-
|
|
372
237
|
/**
|
|
373
238
|
* Check for dangling CNAME records on known/active subdomains.
|
|
374
239
|
* Flags orphaned records and potential takeover vectors.
|
|
@@ -381,6 +246,8 @@ declare function checkSubdomainTakeover(domain: string, dnsOptions?: QueryDnsOpt
|
|
|
381
246
|
*/
|
|
382
247
|
declare function checkTlsrpt(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
|
|
383
248
|
|
|
249
|
+
type OutputFormat = 'full' | 'compact';
|
|
250
|
+
|
|
384
251
|
interface ImpactNarrative {
|
|
385
252
|
impact?: string;
|
|
386
253
|
adverseConsequences?: string;
|
|
@@ -417,7 +284,22 @@ declare function resolveImpactNarrative(params: {
|
|
|
417
284
|
detail?: string;
|
|
418
285
|
}): ImpactNarrative;
|
|
419
286
|
declare function explainFinding(checkType: string, status: string, details?: string): ExplanationResult;
|
|
420
|
-
declare function formatExplanation(result: ExplanationResult): string;
|
|
287
|
+
declare function formatExplanation(result: ExplanationResult, format?: OutputFormat): string;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Category interaction scoring — post-scoring adjustments for correlated weaknesses.
|
|
291
|
+
*
|
|
292
|
+
* Applied after computeScanScore() as a separate penalty layer.
|
|
293
|
+
* Does NOT modify categoryScores — only adjusts the overall score.
|
|
294
|
+
* Existing compare_baseline CI/CD workflows continue to work identically.
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
/** Result of applying interaction rules to a scan score. */
|
|
298
|
+
interface InteractionEffect {
|
|
299
|
+
ruleId: string;
|
|
300
|
+
penalty: number;
|
|
301
|
+
narrative: string;
|
|
302
|
+
}
|
|
421
303
|
|
|
422
304
|
interface ScanRuntimeOptions {
|
|
423
305
|
providerSignaturesUrl?: string;
|
|
@@ -431,6 +313,8 @@ interface ScanRuntimeOptions {
|
|
|
431
313
|
cacheTtlSeconds?: number;
|
|
432
314
|
/** Custom secondary DoH resolver config (bv-dns). Threaded to scanDns but only active when skipSecondaryConfirmation is false. */
|
|
433
315
|
secondaryDoh?: SecondaryDohConfig;
|
|
316
|
+
/** Bypass cache and run a fresh scan. Useful for troubleshooting after DNS changes. */
|
|
317
|
+
forceRefresh?: boolean;
|
|
434
318
|
}
|
|
435
319
|
|
|
436
320
|
/**
|
|
@@ -465,12 +349,27 @@ interface StructuredScanResult {
|
|
|
465
349
|
scoringSignals: string[];
|
|
466
350
|
scoringNote: string | null;
|
|
467
351
|
adaptiveWeightDeltas: Record<string, number> | null;
|
|
352
|
+
/** Percentile rank within the scoring profile population (0–100). Null when insufficient benchmark data. */
|
|
353
|
+
percentileRank: number | null;
|
|
354
|
+
/** Composite email spoofability score (0–100, higher = more spoofable). Null when not computed. */
|
|
355
|
+
spoofabilityScore: number | null;
|
|
356
|
+
/** Category interaction effects applied as post-scoring adjustments. */
|
|
357
|
+
interactionEffects: Array<{
|
|
358
|
+
ruleId: string;
|
|
359
|
+
penalty: number;
|
|
360
|
+
narrative: string;
|
|
361
|
+
}>;
|
|
468
362
|
timestamp: string;
|
|
469
363
|
cached: boolean;
|
|
470
364
|
}
|
|
365
|
+
/** Optional enrichment data for structured scan results. */
|
|
366
|
+
interface ScanResultEnrichment {
|
|
367
|
+
percentileRank?: number | null;
|
|
368
|
+
spoofabilityScore?: number | null;
|
|
369
|
+
}
|
|
471
370
|
/** Build a machine-readable structured result from a scan. */
|
|
472
|
-
declare function buildStructuredScanResult(result: ScanDomainResult): StructuredScanResult;
|
|
473
|
-
declare function formatScanReport(result: ScanDomainResult): string;
|
|
371
|
+
declare function buildStructuredScanResult(result: ScanDomainResult, enrichment?: ScanResultEnrichment): StructuredScanResult;
|
|
372
|
+
declare function formatScanReport(result: ScanDomainResult, format?: OutputFormat): string;
|
|
474
373
|
|
|
475
374
|
/**
|
|
476
375
|
* scan-domain orchestrator tool.
|
|
@@ -492,6 +391,8 @@ interface ScanDomainResult {
|
|
|
492
391
|
timestamp: string;
|
|
493
392
|
scoringNote: string | null;
|
|
494
393
|
adaptiveWeightDeltas: Record<string, number> | null;
|
|
394
|
+
/** Category interaction effects applied as post-scoring adjustments. Empty when no interactions triggered. */
|
|
395
|
+
interactionEffects: InteractionEffect[];
|
|
495
396
|
}
|
|
496
397
|
/**
|
|
497
398
|
* Run a full DNS security scan on a domain.
|
|
@@ -503,4 +404,4 @@ interface ScanDomainResult {
|
|
|
503
404
|
*/
|
|
504
405
|
declare function scanDomain(domain: string, kv?: KVNamespace, runtimeOptions?: ScanRuntimeOptions): Promise<ScanDomainResult>;
|
|
505
406
|
|
|
506
|
-
export {
|
|
407
|
+
export { type CaaRecord, type CheckMxOptions, type DnsAnswer, type DnsAuthority, DnsQueryError, type DohResponse, type ExplanationResult, type MaturityStage, type QueryDnsOptions, RecordType, type RecordTypeName, SERVER_VERSION, type ScanDomainResult, type ScanRuntimeOptions, type StructuredScanResult, buildStructuredScanResult, checkBimi, checkCaa, checkDkim, checkDmarc, checkDnssec, checkLookalikes, checkMtaSts, checkMx, checkNs, checkSpf, checkSsl, checkSubdomainTakeover, checkTlsrpt, explainFinding, formatExplanation, formatScanReport, parseCaaRecord, queryCaaRecords, queryDns, queryDnsRecords, queryMxRecords, queryTxtRecords, resolveImpactNarrative, sanitizeDomain, sanitizeInput, scanDomain, validateDomain };
|