v2.1.5
Security and correctness (self-driven bug-hunt)
A five-area parallel bug-hunt (inference, ingestion, merge/cache, CLI/formatter,
fingerprints/server). Fifteen findings fixed; four inference-layer items are held
for maintainer review because they would shift calibrated posteriors.
Security:
- Rich markup injection in
recon <domain> --verbose: the per-source line
printed attacker-controlledauth_type/dmarc_policy/errorthrough
console.printwithout escaping; both are now escaped and control-stripped. - Control-character and markup scrub gaps closed on attacker-controlled paths
that bypassed the central merger scrub: the OIDC discovery fields
(cloud_instance,tenant_region_sub_scope,msgraph_host), the resolver's
related-domain enrichment services, the unclassified-CNAME and surface panels,
the conflicting-tenant-ID insight, and the--mdrelated-domains list. - crt.sh
name_valueis length-capped before the per-character SAN scan, so a
single newline-free field cannot turn the whole response body into a scan. - Non-capturing-group ReDoS:
(?:a|aa)+cslipped past the alternation-overlap
guard because(?:corrupted the first branch; the guard now normalizes
non-capturing and inline-flag groups before splitting branches. inject_ephemeral_fingerprintreturns a clean error instead of crashing when
a detection element is not a dict;simulate_hardeningno longer echoes the
raw caller-supplied fix string;analyze_posturecaps the profile name.- The v2.1.4 cache
mkstempnow uses the resolved cache dir, so a symlinked
RECON_CONFIG_DIRcannot move the temp off-volume and makeos.replace
non-atomic.
Correctness:
merge_conflictsnow survives the cache round-trip; it was serialized but
never read back, so a cached result lost its conflict data and the Bayesian
n_eff conflict penalty.- The CT semaphore and rate-limiter maps key on the loop object through a weak
map instead ofid(loop), which could be reused after GC and return stale
state. - The
cname_targetspecificity corpus is now the CNAME corpus rather than the
mismatched generic one, so the ephemeral-injection gate is meaningful for the
most common detection type.
Held for maintainer review (each would shift calibrated posteriors): a possible
alpha double-count in compute_slug_posteriors, the spf_strict -all
substring match, declarative group-absence LR=1, and the signed
entropy-reduction total.
Gate: full pytest, ruff, pyright (0 errors), validate_fingerprint (841).