ATT&CK Coverage🔗
rsigma rule coverage maps a rule set onto the MITRE ATT&CK matrix. It answers "what does my rule set cover, and where are the holes" by reading the attack.* tags off your rules, exporting an ATT&CK Navigator heatmap, and diffing your coverage against external references.
Where rule backtest tells you whether your rules fire correctly, rule coverage tells you whether you have rules for the techniques you care about. Together they are the two halves of a detection-as-code pipeline.
How techniques are extracted🔗
Coverage reads the tags: block of every detection and correlation rule (filter rules are excluded, since they suppress rather than detect):
attack.t1059,attack.t1059.001become technique IDsT1059,T1059.001.attack.execution,attack.privilege-escalation, ... become tactic annotations. Both the hyphenated spelling SigmaHQ uses (privilege-escalation) and the underscore spelling from the Sigma spec (privilege_escalation) are accepted and normalized to the canonical Navigator slug.- Any other
attack.*tag (ATT&CK groups, software, or a custom taxonomy) counts the rule as tagged but contributes no technique.
A rule carrying no attack.* tag at all is reported under untagged_rules, a tagging-hygiene signal worth driving to zero.
# A rule that contributes T1059.001 under the "execution" tactic.
title: PowerShell Download Cradle
logsource: { category: process_creation, product: windows }
detection:
sel: { Image|endswith: '\powershell.exe', CommandLine|contains: DownloadString }
condition: sel
tags:
- attack.execution
- attack.t1059.001
Sub-technique roll-up🔗
A rule on a sub-technique covers its parent for gap analysis: a rule tagged attack.t1059.001 makes a target of T1059 count as covered (reported as covered_via_subtechnique). The reverse does not hold. A rule on the parent T1059 does not vouch for a specific sub-technique target like T1059.002, because the coarser rule does not guarantee detection of that exact variant. The exported Navigator layer always keeps exact per-ID scores; the roll-up only affects the gap math.
Export an ATT&CK Navigator layer🔗
The layer is ATT&CK Navigator format 4.5. Each technique is scored by the number of rules that reference it, the same "score function count" semantics SigmaHQ uses for its published heatmap, so your layer and the SigmaHQ baseline share a gradient and overlay cleanly. Open coverage.json in the Navigator (Open Existing Layer) to see the heatmap, or commit it as a coverage artifact.
Cross-references🔗
Each cross-reference is optional and additive. Combine as many as you like in one run.
Atomic Red Team🔗
A bare --atomics fetches the upstream Atomic Red Team atomics/Indexes/index.yaml (cached for 7 days). Pass a local index.yaml, an atomic-red-team atomics/ checkout, or a URL to use your own copy. The report splits the gap two ways:
atomics_without_rule: techniques that have an atomic test but no detection rule. These are your detection gaps, the highest-value place to write a new rule, because there is a known way to exercise the technique that nothing would catch.rules_without_atomic: techniques you detect that have no atomic test. These are validation gaps, where you cannot easily prove the rule works.
SigmaHQ baseline🔗
A bare --baseline fetches the SigmaHQ coverage heatmap (itself a Navigator layer), so the diff is layer-to-layer. The report shows baseline_not_covered (techniques the public corpus covers that you do not) and ahead_of_baseline (techniques you cover that the baseline does not, often your environment-specific detections).
Target technique list🔗
A target list is your own prioritized set of techniques (an internal threat model, the M-Trends top techniques, a red-team engagement scope), one technique ID per line with # comments allowed:
# Q3 threat model
T1059 # command and scripting
T1003 # credential dumping
T1486 # data encrypted for impact
The report's targets.uncovered is the list to work down.
Gate CI on coverage🔗
--fail-on-gaps turns any requested cross-reference's uncovered set into a non-zero exit, so coverage becomes a CI gate. The most common use is a target list that must stay fully covered:
This exits 1 (findings) the moment a targeted technique loses its last rule, so deleting or renaming a rule that was your only coverage for a priority technique fails the build. The exit codes follow the house scheme: 0 clean, 1 gaps, 2 unreadable rules, 3 a bad cross-reference input.
See CI/CD for the full detection-as-code pipeline that runs lint, validate, backtest, and coverage together.
Configuration🔗
The cross-reference inputs can be set as project defaults in a config file so CI invocations stay short:
coverage:
atomics: https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/Indexes/index.yaml
targets: ./threat-model-techniques.txt
fail_on_gaps: true
CLI flags always win over the config file. rules is intentionally not a config key: it is the one required, invocation-specific argument.
See also🔗
rule coveragefor the full flag reference.rule backtestfor the corpus-replay test harness.- Linting Rules for tag-format validation that keeps
attack.*tags well-formed.