# Reported issues for BlackVeil DNS & Email Security Scanner

Pod holds 18 of 34 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to [BlackVeil DNS & Email Security Scanner](/mcp/blackveil-dns-email-security-scanner).

## Most discussed

### v3.58.0 live-verification follow-ups: timeout guidance names the wrong source, Certspotter no longer attempted, BV_CERTSTREAM bound but reports not-consulted

Found by live verification of v3.58.0 immediately after deploy (version `f89d6101`, 100%). #734's fix verifies correctly; these are defects in #735's messaging that I shipped, plus one observation that needs investigating before anyone trusts the new `BV_CERTSTREAM` binding.

## 1. Source-specific measurements are attributed to whichever source timed out

Live output for `meta.com` **and** `anthropic.com`:

```
crtsh timed out — this is deterministic for this domain, not transient, so an…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/738) · 2026-08-20 · closed · 5 comments

### check_dane_https scores a STALE TLSA pin as 100 — presence is checked, correctness is not

## Summary

`check_dane_https` scores a TLSA record **100 / "Valid TLSA record configured"** without verifying that the pinned hash matches the certificate the host actually serves. A stale DANE-EE pin — which actively breaks every DANE-validating client — is reported as a pass.

Found by scanning our own production domain during a zone audit on 2026-08-30.

## Evidence

`blackveilsecurity.com` published `_443._tcp` TLSA `3 1 1` (DANE-EE / SPKI / SHA-256):

```
pinned SPKI sha256:…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/841) · 2026-08-30 · closed · 4 comments

### Unprovisioned / tier-denied OSINT + recon tools return `passed: true, score: 100`

An unavailable lane returns a result that reads as a clean pass. A consumer keying on `passed`/`score` — a dashboard, a proposal generator, or an LLM skimming the response — records "no findings" where **no measurement was performed**.

### Observed (hosted deployment, 2026-08-18, v3.52.0)

```json
{"category":"osint_investigation","passed":true,"score":100,
 "findings":[{"category":"osint_investigation","title":"OSINT investigation unavailable",
 "severity":"info","detail":"OSINT domain…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/695) · 2026-08-18 · closed · 4 comments

### check_dnssec_chain: false 'unverified root' from cached transient-empty (edge-cache hypothesis refuted)

## Summary

`check_dnssec_chain` reports a false **HIGH "Broken DNSSEC chain at ."** for every correctly-signed domain in **production**, because the root (and TLD) `DNSKEY`/`DS` DoH queries return **empty** in prod — even though the records exist.

Surfaced during the full-tool QA pass. Reproduced on cloudflare.com and ietf.org (both broke at `.`, walk stopped at the TLD).

## Root cause — isolated to the prod edge, NOT the code

A real-network test in the **workerd** runtime (same engine as…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/199) · 2026-05-24 · closed · 4 comments

### check_ssl and check_ptr time out against fastmail.com in a full scan

Found by a live post-deploy accuracy sweep of prod 3.43.0.

## Observed

`scan_domain(fastmail.com, force_refresh: true)`:

```json
"checkStatuses": {"ssl": "timeout", "ptr": "timeout", ...},
"inconclusiveCategories": ["ssl", "ptr"],
"categoryScores": {"ssl": null, "ptr": null},
"evidence": {"attempted": 19, "completed": 17, "ratio": 0.894...}
```

Two of nineteen checks timed out against a major, highly-available mail provider. The same scan completed all other 17 checks normally, and…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/641) · 2026-08-07 · closed · 2 comments

### check_dane_https: bv-tls-probe's Browser Rendering vantage is TLS-intercepted (Mockttp) — 3.75.0 scores correct DANE pins as a high mismatch

## Summary

3.75.0 (PR #901, closing #841) verifies DANE-HTTPS TLSA pins against the certificate captured by bv-tls-probe. That capture is **not the origin's certificate**: Cloudflare Browser Rendering egresses the headless browser through a TLS-terminating proxy that re-signs every non-Cloudflare origin with a per-session `O=Mockttp Cert - DO NOT TRUST` CA. Every DANE-EE / DANE-TA comparison from that vantage is therefore a guaranteed mismatch, and prod scored a **correct** pin as a `high`…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/906) · 2026-09-04 · closed · 1 comment

### discover_subdomains: no CT source survives a high-volume domain — certspotter times out deterministically (not transiently) while the error says 'retry shortly'

Found during the same Meta estate sweep as #734, 2026-08-21. Adjacent to #573 (closed) but a **different failure mode**: #573 is about *silent truncation* of a successful query; this is *total failure with no surviving source*, plus an error string that misdescribes it as transient.

## Observed

`discover_subdomains({ domain: 'meta.com' })`:

```
Subdomain Discovery: meta.com — Certificate Transparency source unavailable
(the CT log endpoint returned an error or was unreachable); could not…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/735) · 2026-08-20 · closed · 1 comment

### scan_domain on a www. host applies a mail profile and reports a critical "No SPF record found" for a name that cannot carry SPF

## Summary

Passing a `www.` hostname to `scan_domain` scores it as if it were a registrable domain. Because SPF, DMARC and MX are published at the apex, the `www` host legitimately has none of them — so the scanner reports a **`critical` "No SPF record found"** and related mail-auth deficiencies against a name that cannot carry those records in the first place.

It also selects a *mail* scoring profile for a hostname that has no MX.

## Observed

Same organisation, two names, scanned minutes…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/688) · 2026-08-16 · closed · 1 comment

## Most recent

### dns-transport arms the DoH timeout before the semaphore slot is acquired — queued scan_domain queries abort unsent under load (same class as #867/#903)

## Summary

`src/lib/dns-transport.ts` arms each DoH query's `AbortSignal.timeout(timeoutMs)` **before** the query enters the shared semaphore (`SCAN_DNS_CONCURRENCY = 12`): the signal is composed at line 174-175 and only then does `sem.run(() => fetch(input, init), callerSignal)` (line 159) queue the fetch. A query that waits in the semaphore for most of its timeout is dispatched with almost nothing left, or aborts unsent — it then reads as a resolver failure (`checkStatus: 'error'` /…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/904) · 2026-09-04 · open · 0 comments

### Package abstentions in check-caa / check-mx / check-ns return checkStatus 'error' with score 100 — never retried, cached, and misreadable as a pass

## Summary

Four package abstention paths return `checkStatus: 'error'` **with `score: 100`**, so `scan_domain`'s transient-zero retry never fires for them and the abstention is cached as if it were a stable measurement.

Sites (`packages/dns-checks/src/checks/`, origin/main @ 85e63ee8d):

- `check-caa.ts` — the `delegationStatus === 'unknown'` early return and the `lookupCaa` catch (two sites)
- `check-mx.ts` — the `queryDNS(domain, 'MX')` catch
- `check-ns.ts` — the NS-query catch (the two…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/900) · 2026-09-03 · open · 0 comments

### cf-connecting-ip is absent for nearly all custom-domain traffic — every anonymous caller shares one rate-limit bucket and owner-tier auth degrades

## Summary

While fixing #876 (PR #891), read-only D1 aggregates over the last 30 days showed that `cf-connecting-ip` is **absent for essentially all traffic that reaches the Worker via the public custom domain** (`dns-mcp.blackveilsecurity.com`), while traffic via the workers.dev URL carries it. #876's "1,082 monitor rows" hypothesis was wrong: the sentinel rows are ~3,560 of ~15,229 public rows and are overwhelmingly real clients (`claude_code` 2,842, `claude_connector` 232, most of them…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/896) · 2026-09-03 · open · 0 comments

### check-mta-sts: two bare catch paths emit SCORED findings on the scanner's own network failure (abstention-doctrine defect)

## What happens

`@blackveil/dns-checks` **1.32.0** (`BUILD_INFO.json` commit `bb736baa`), `packages/dns-checks/src/checks/check-mta-sts.ts`, inside `checkMTASTS`. Two bare `catch` blocks convert an exception thrown by the **scanner's own** I/O into a scored finding against the scanned domain. Line numbers are from the shipped `dist/index.js.map` `sourcesContent`; dist line numbers in the vendored `dist/index.js` are given alongside.

**1. Policy fetch — `check-mta-sts.ts:135-144` (dist…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/889) · 2026-09-03 · closed · 0 comments

### Public SSE-path access-log rows record ip_hash='unknown' despite live cf geo — anonymous traffic unattributable

## Summary

`mcp_access_log` rows on the **public path** can record the sentinel `ip_hash = 'unknown'` while carrying real `request.cf` geo (country populated). Over the last 30 days this affects **1,082 rows** — 1,072 with `transport='sse'` (legacy HTTP+SSE door) and 10 with `transport='json'` — spanning six countries (NZ, US, JP, DE, IE, NL).

The migration header (`scripts/intelligence/sql/0001_mcp_access_log.sql`) states unauthenticated callers are "attributed by `ip_hash` only". These rows…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/876) · 2026-09-01 · closed · 0 comments

### @blackveil/dns-checks version has been frozen at 1.27.0 across three scoring-model bumps — the version no longer identifies the code

`packages/dns-checks/package.json` and `PARITY_CORPUS_VERSION` are both **1.27.0**, and have been since #794. Since then `SCORING_MODEL_VERSION` has advanced **three times**:

| model | shipped in | dns-checks source it changed | package version |
| --- | --- | --- | --- |
| 1.13.0 | — | — | bumped to 1.24.0 by #777, then 1.27.0 by #794 |
| 1.14.0 | | scoring | **1.27.0** |
| 1.15.0 | 3.70.0 (#846) | `scoring/classifiers/dmarc.ts`, `parity-fixtures.ts` | **1.27.0** |
| 1.16.0 | 3.71.0 (#850) |…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/855) · 2026-08-30 · closed · 0 comments

### robots gate fails open on an unreachable robots.txt, so a scan result depends on the target's uptime — and nothing records which branch fired

## Summary

`withRobotsGate` is fail-open on **any** unusable robots.txt. That is a defensible policy — a broken robots.txt must not block a scan — but it makes a scan result depend on whether the target's web server happened to be up during a 3-second window, and **nothing in the output records which branch fired**. Two runs minutes apart can produce a scored result and an unscored one for the same domain, with no way to tell them apart after the fact.

## Mechanism…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/745) · 2026-08-20 · closed · 0 comments

### brand_discovery: a PARTIAL signal failure scores 95/pass — #670's guard only fires when ALL signals fail (meta.com surfaced 1 of ≥152 domains, passed:true)

Found while running a third-party estate sweep (Meta) from bv-web-prod, 2026-08-21. Same defect family as #670 — a discovery run that could not measure properly reporting a healthy result — but in the code path #670's fix does **not** reach.

## The gap

#670 added the unmeasured guard at `src/tools/discover-brand-domains.ts:1517`:

```ts
const allFailed = signals.length > 0 && signals.every((s) => signalCouldNotComplete(signalStatus[s]?.status));
if (allFailed) { ... return { ...unmeasured,…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/734) · 2026-08-20 · closed · 0 comments

### map_compliance publishes PCI DSS 6.4.2 (CSP) as PASS on a policy allowing unsafe-inline + unsafe-eval — requirePass controls backed by checks that never emit recordPresent are unguarded

`isSatisfiedControl` (#721) closes the false-affirmative **only for the 9 checks that emit `recordPresent`**. For a `requirePass: true` control backed by a check that never emits it, the predicate degrades silently to bare `passed` — the exact defect #705/#706 fixed. `control-presence.ts` documents the gap in a comment; this issue is one customer-visible control where it currently produces a wrong verdict.

### The control

`src/tools/map-compliance.ts:150-156`

```ts
{
  framework:…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/726) · 2026-08-20 · closed · 0 comments

### scan_domain with profile='authoritative_dns_infra' can report 100 (A+) / "No security issues found." when the infra probe establishes nothing

**Preconditions, both required:** the caller must explicitly pass the non-default
`profile: 'authoritative_dns_infra'` to `scan_domain`, **and** the infra probe must establish nothing
measurable (either the binding is absent, or it is present and every capability comes back
inconclusive). Neither happens on a default scan. This is a code-path finding on `main` @ `d37f1724`;
it has **not** been verified against the live production surface.

Split out of #695, which covers the same defect class —…

[Read the thread](https://github.com/MadaBurns/bv-mcp/issues/696) · 2026-08-18 · closed · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/MadaBurns/bv-mcp/issues).
