Changelog: 0.13.x¶
Archived verbatim from CHANGELOG.md. Newer releases are in the changelog; the archive index lists every older series.
[0.13.0] — 2026-08-17¶
Added¶
- Full
HostnameAnalysisacross the Node, Ruby, and Java/Kotlin bindings (#549). A newanalyzeHostname/analyze_hostnamereturns the complete analysis (verdict + all granular signals, includingwhole_script_confusable) — previously those bindings exposed only the.suspiciousboolean. Node returns aHostnameAnalysisobject, Ruby a Hash, and Java/Kotlin adev.disarm.HostnameAnalysisrecord (theList<List<String>>labelScriptsandList<Boolean>labelWholeScriptConfusableare marshalled directly across the JNI boundary). The booleanisSuspiciousHostnamepredicate is unchanged. Mirrors how the anomaly report is already exposed. The C-ABI gains the matching structured entry points in the same window (see below). - Structured reports across the C-ABI (#553). Five new
#[ffi_export]entry points return their report as a JSON string (freed with the existingdisarm_string_free):disarm_analyze_hostname(the fullHostnameAnalysis, includingwhole_script_confusable/label_whole_script_confusable),disarm_inspect_anomalies(per-findingkind/token/start/end/detail/reason, taking a JSON word-array lexicon so theleet/segmentationbranches match the other bindings, not just the structural ones),disarm_inspect_auto_lang(script + chosen language + discriminators), and the fallibledisarm_lang_info/disarm_script_infometadata lookups. JSON is the one transport for every nested shape (List<List<String>>,List<Boolean>, optionals) — norepr(C)mirror structs, trivially parsed by any C/Go/Swift/ ctypes consumer.serde_jsonis a C-ABI-only dependency; the pure core still carries no serde. The scalar predicates (disarm_is_suspicious_hostname, …) are unchanged. - Whole-script-confusable signal on
HostnameAnalysis(#545). Two additive fields —whole_script_confusable(any label qualifies) and the per-labellabel_whole_script_confusable— name the fact that discriminates a whole-script spoof (аррӏе.com→ skeletonapple.com, every letter a confusable) from a genuine non-Latin domain (москва.рф, whoseм/к/вsurvive the skeleton). A label qualifies when it is single-script, non-Latin, and its confusable skeleton is entirely Latin. It is a graded signal, not a verdict, and is deliberately not folded intosuspicious: on its own it fires on short non-Latin ccTLDs (ру→py) and on real words whose every letter is a confusable (оса→oca). The precise, low-false-positive policy —whole_script_confusable(non-TLD label) ∧ Latin TLD— is caller-side (disarm does not model registrable boundaries). Exposed on the Rust and Python surfaces; the other bindings expose only.suspicioustoday and are tracked separately (#549).
Documentation¶
- Clarified that
is_suspicious_hostname'ssuspiciousflag is a maximally conservative screen (an any-character confusable test flags essentially every non-Latin hostname), not a precise verdict, and moved whole-script confusables inTHREAT_MODEL.mdfrom out of scope to a defined mechanism with its stated irreducible false-positive class. Completed theHostnameAnalysisfield table in the predicates docs. - Upgrading guide + stability-contract clarifications (#546, #547, #548). Added
docs/upgrading.md(a new top-level nav section, distinct from Migration) with the cumulative table of public renames since 0.9 and a!!! dangernote on theis_safe_hostname→is_suspicious_hostnameboolean-polarity inversion. RestatedSECURITY.md's supported-version window as a self-maintaining rule (was the stale0.6.x). Extended the semver data-change clause indocs/RUST_API.mdto name the security surfaces (is_suspicious_hostname,normalize_confusables, …), recorded the bundled Unicode/UTS#39 data versions indocs/provenance.md(+ provenance headers on the two confusables tables), and clarified that "removed in 1.0" refers to the RELEASING.md commercial-support milestone, not the next release. - Surfaced disarm's measured BitAbuse recovery in the coverage docs (#543). Re-ran the
adversarial-eval harness against the full corpus on v0.12.0 (325,580 rows) —
strip_obfuscationnow recovers 65.3% word-level (up from 64.1% on 0.6.3) with 81.7% of non-ASCII perturbation occurrences folded — and added disarm's own row to the coverage spectrum indocs/security/adversarial-defense.mdandTHREAT_MODEL.md(previously only the ~35% class baseline and ~96% ceiling appeared, inviting readers to transfer ~35% onto disarm). The word-level metric is defined inline with line-exact (5.8%) stated alongside, and the BitAbuse figure is explicitly separated from the near-identical TR39-space XMR = 0.634. Retired the divergent pre-harness baseline in the benchmark README in favour of the committed report, and documented a manual pre-release refresh cadence.