Files
rengine/toolbox/tools
Yogesh OjhaandClaude Opus 5 b7e9d8d15b feat(dns): a zone that transfers is a source of names and a finding of its own
dnsx answers every -axfr query with an object — {"host": …} when refused,
{"host": …, "chain": [{…, "all": [zone lines]}]} when it succeeded — and
parse_dnsx_record nulled the whole field out because it was typed list[str]:

    if isinstance(raw.get("axfr"), dict):
        raw["axfr"] = None

So a successful transfer was discarded on the way in, and the Toolbox's DNS
tool printed "Zone transfer: refused" unconditionally. Measured against
zonetransfer.me: 45 names came back, 0 were kept. SubdomainSource.ZONE_TRANSFER
had been declared with no producer since the enum was written.

- DnsxAxfr models what dnsx actually returns. `transferred` is
  `any(entry.all …)`, never the truthiness of the object, and
  `zone_transferred` / `zone_names` are the one place every caller asks.
- hostnames() reads the presentation format by its tab-separated columns, not
  a whitespace split (a TXT value may contain the word NS), taking each
  record's owner and the names CNAME/NS/PTR/MX/SRV/DNAME point at, dropping
  `*` owners.
- subdomain_discovery asks each apex's own nameservers before it guesses
  (SubdomainConfig.zone_transfer, on by default, gated on intensity exactly as
  bruteforce is). The names merge through merge_and_filter like every other
  source, so they are scoped, resolved and probed.
- stages/zone_transfer/ reads back the hosts whose sources name the transfer
  and writes one HIGH rengine-zone-transfer finding per zone, so it inherits
  triage, is:new, alerting and reports. It is deliberately its own stage:
  putting vulnerabilities in subdomain_discovery.produces would make every
  name-only scan claim to cover that dimension and report "0 findings" where
  the honest answer is "never scanned".
- to_db_records writes one AXFR row stating the outcome and the true count,
  never a row per name — that would be a second, capped copy of an inventory
  that already lives in subdomains.

Measured end to end through the real client: zonetransfer.me 45 names in 6.0s,
35 in scope; hamropatro.com refused in 4.2s with no error. 21 tests, each
proven to fail against 8 mutations including the original discard and the
truthiness bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dKUV96WkQQETZBMoAG98C
2026-09-11 07:48:51 +05:30
..