MITRE ATT&CK Coverage
Overview
The MITRE ATT&CK Coverage module gives SOC teams a visual, interactive view of which adversary tactics and techniques the ThreatOps detection rule library currently covers. In a managed security operations service, customers and analysts need to answer a single critical question: which attack paths can we detect today? Without this visibility, coverage gaps remain invisible until an attacker exploits them.
This module maps every active detection rule's mitre_tactic and mitre_technique_id fields against all 12 MITRE ATT&CK Enterprise tactics (TA0001–TA0040) and their representative techniques, producing a real-time heat-map matrix, per-tactic progress bars, an overall coverage score, and a prioritized gap analysis with actionable recommendations. It is directly driven by the 372 detection rules in platform/api/app/rules/.
What Was Proposed
- Visual ATT&CK matrix heat-map showing detection coverage across all enterprise tactics and techniques
- Automatic computation of coverage percentage derived from the live detection rule library
- Technique drill-down showing which specific detection rules are mapped to each ATT&CK technique
- Gap analysis identifying uncovered or partially-covered techniques ranked by risk severity
- Actionable remediation recommendations per identified gap
- Recalculate-on-demand to reflect newly deployed detection rules immediately
- Integration with the Detection Rules module so rule MITRE tags are the single source of truth
- Framework export capability for customer compliance reporting
What's Built
| Feature | Status |
|---|---|
| 12-tactic ATT&CK matrix (TA0001–TA0040) | ✓ Complete |
| Per-tactic coverage progress bars with color thresholds | ✓ Complete |
| Overall coverage score card (full / partial / uncovered counts) | ✓ Complete |
| Interactive technique cells with click-to-drill-down modal | ✓ Complete |
| Technique detail modal listing mapped detection rules with severity badges | ✓ Complete |
Live rule ingestion via GET /api/v1/detection-rules/?limit=1000 | ✓ Complete |
| Graceful fallback to deterministic mock data when API is unavailable | ✓ Complete |
| Gap analysis section sorted by risk severity (critical → low) | ✓ Complete |
| Actionable recommendations per gap with Lightbulb icon | ✓ Complete |
| Matrix coverage legend (full / partial / no coverage) | ✓ Complete |
| Recalculate button for on-demand refresh | ✓ Complete |
| Dedicated MITRE-specific backend router | ⚠ Not needed — uses detection-rules router |
| Framework export for compliance reporting | ⚠ Not yet built |
mitre.py backend router. Coverage is computed entirely on the frontend by consuming GET /api/v1/detection-rules/ and grouping rules by their mitre_tactic field. This keeps the module stateless and always in sync with the live rule library without requiring any additional database queries or backend services.
Architecture
Coverage Computation Pipeline
The coverage calculation runs client-side in src/app/mitre-coverage/page.tsx inside the fetchData useCallback hook, executing three steps on every recalculation:
- Rule Fetch — Calls
GET /api/v1/detection-rules/?limit=1000via the sharedapiclient (src/lib/api-client.ts). Handles three API response shapes: plain array,{ items: [...] }, and{ data: [...] }. - Coverage Mapping — For each of the 12 MITRE tactics, filters rules where
rule.mitre_tactic(case-insensitive) matches the tactic name. Techniques are then scored: more than 2 matching rules marks a technique asfull; 1–2 rules aspartial; zero rules asnone. - Score Calculation — Overall coverage percent uses the weighted formula
((full_count + partial_count × 0.5) / total_techniques) × 100. Identical formula is applied per-tactic for the progress bars.
When the API call fails or returns zero rules, the page falls back to generateMockCoverage() and generateMockGaps(), displaying an amber warning banner. This ensures the UI remains fully functional during development or connectivity issues.
Detection Rule Backend Integration
Detection rules exist in two stores, both surfaced by the same API endpoint:
- Rule library — 372 hand-authored rules in
platform/api/app/rules/(20+ modules), loaded viaget_all_rules(). Each rule carriesmitre_tactics: [...]andmitre_techniques: [...]arrays. The router normalizesmitre_tactics[0]to the singularmitre_tacticresponse field. - Database — Tenant-created rules in the
detection_rulesPostgreSQL table, withmitre_tactic(string) andmitre_technique_id(string) columns directly.
The coverage page queries both sources through the same endpoint, so library rules and tenant-specific rules both contribute to the ATT&CK heat-map.
Gap Analysis
The gap analysis section uses a curated static list of eight high-signal technique gaps representing the most commonly exploited and under-detected attack patterns in enterprise environments:
- T1566 Phishing (Critical) — Deploy email gateway rules and user-reported phishing playbook
- T1059 Command & Scripting Interpreter (Critical) — Enable PowerShell script block logging and Sigma rules for encoded commands
- T1003 OS Credential Dumping (Critical) — Monitor for LSASS access patterns and deploy credential guard
- T1486 Data Encrypted for Impact (High) — Create canary file detection rules and monitor mass file modification events
- T1021 Remote Services (High) — Monitor anomalous RDP/SSH sessions with baseline deviation rules
- T1071 Application Layer Protocol (High) — Deploy DNS analytics and HTTP anomaly detection rules
- T1543 Create or Modify System Process (Medium) — Monitor new service installations and systemd unit file creation
- T1082 System Information Discovery (Low) — Baseline normal discovery activity per host to detect anomalies
Tactics & Techniques Covered
The module covers all 12 MITRE ATT&CK Enterprise tactics. Each tactic maps to a technique bank of 4–7 representative techniques drawn from the most prevalent sub-techniques in each category:
| Tactic ID | Tactic Name | Technique Count | Sample Techniques |
|---|---|---|---|
TA0001 | Initial Access | 6 | Phishing, Valid Accounts, Exploit Public-Facing App, External Remote Services, Drive-by Compromise, Supply Chain Compromise |
TA0002 | Execution | 6 | Command & Scripting Interpreter, PowerShell, WMI, Scheduled Task/Job, User Execution, Native API |
TA0003 | Persistence | 6 | Boot/Logon Autostart, Create Account, Scheduled Task/Job, Registry Run Keys, Browser Extensions, Office App Startup |
TA0004 | Privilege Escalation | 5 | Access Token Manipulation, Exploitation for Priv Esc, Process Injection, Sudo Caching, Abuse Elevation Control |
TA0005 | Defense Evasion | 7 | Obfuscated Files, Masquerading, Indicator Removal, Process Injection, Rootkit, Signed Binary Proxy, Virtualization Evasion |
TA0006 | Credential Access | 6 | Brute Force, OS Credential Dumping, Credentials from Password Stores, Steal Web Session Cookie, Kerberoasting, Input Capture |
TA0007 | Discovery | 6 | System Information Discovery, Account Discovery, Network Service Discovery, Permission Groups Discovery, Process Discovery, Remote System Discovery |
TA0008 | Lateral Movement | 5 | Remote Services, Lateral Tool Transfer, RDP, SMB/Windows Admin Shares, Exploitation of Remote Services |
TA0009 | Collection | 5 | Data from Local System, Screen Capture, Clipboard Data, Email Collection, Archive Collected Data |
TA0011 | Command & Control | 6 | Application Layer Protocol, Encrypted Channel, Proxy, Ingress Tool Transfer, Non-Standard Port, Web Service |
TA0010 | Exfiltration | 4 | Exfiltration Over Web Service, Over C2 Channel, Automated Exfiltration, Over Alternative Protocol |
TA0040 | Impact | 5 | Data Encrypted for Impact, Service Stop, Inhibit System Recovery, Account Access Removal, Defacement |
API Endpoints
The MITRE Coverage module does not have a dedicated backend router. It relies entirely on the Detection Rules API, which exposes MITRE tactic and technique metadata on every rule record.
Detection Rules API (consumed by this module)
Router file: platform/api/app/routers/detection_rules.py — Prefix: /api/v1/detection-rules
GET /api/v1/detection-rules/?limit=1000 Query parameters used by coverage page: limit=1000 # Fetch all rules in a single request Response fields consumed by coverage computation: id string Rule UUID name string Human-readable rule name severity string critical / high / medium / low mitre_tactic string? ATT&CK tactic name (e.g. "Initial Access") mitre_technique_id string? ATT&CK technique ID (e.g. "T1566") enabled boolean Whether the rule is active
Response Shape Handling
The frontend handles multiple API response shapes to accommodate both the library and DB-backed rules endpoints:
// All three shapes are supported:
rulesRes // Plain array
rulesRes.items // Paginated response { items: [...] }
rulesRes.data // Alternative envelope { data: [...] }
Frontend Routes
| Layer | Path | Description |
|---|---|---|
| /mitre-coverage | Next.js App Router page — main ATT&CK coverage UI | |
| /api/v1/detection-rules/ | Backend endpoint consumed for live rule-to-coverage mapping | |
Frontend Page File
File: platform/frontend/src/app/mitre-coverage/page.tsx
The page is a single React client component ('use client') with two primary state objects: tacticCoverage (a Record<string, TacticCoverage> keyed by tactic ID) and gaps (the prioritized gap list). A single fetchData callback populates both on mount and on manual recalculation. The selectedTechnique state drives the detail modal visibility.
Data Model
The MITRE Coverage module is stateless on the backend — there is no dedicated database table. All coverage data is computed in-memory on the frontend from the detection rule records. The relevant TypeScript types are defined at the top of page.tsx:
TacticCoverage
| Field | Type | Description |
|---|---|---|
tactic_id | string | MITRE tactic ID (e.g. "TA0001") |
tactic_name | string | Tactic display name (e.g. "Initial Access") |
total_techniques | number | Total techniques in the bank for this tactic |
covered_techniques | number | Count of fully covered techniques |
partial_techniques | number | Count of partially covered techniques |
coverage_percent | number | Weighted score: (full + partial×0.5) / total × 100, rounded to integer |
techniques | TechniqueCoverage[] | Array of technique-level coverage details |
TechniqueCoverage
| Field | Type | Description |
|---|---|---|
technique_id | string | ATT&CK technique ID (e.g. "T1566") |
technique_name | string | Technique display name |
coverage | 'full' | 'partial' | 'none' | Coverage classification: full (>2 rules), partial (1–2 rules), none (0 rules) |
rule_count | number | Number of detection rules mapped to this technique |
rules | { id, name, severity }[] | Up to 5 detection rules shown in the drill-down modal |
GapItem
| Field | Type | Description |
|---|---|---|
technique_id | string | ATT&CK technique ID (e.g. "T1566") |
technique_name | string | Technique name |
tactic_name | string | Parent tactic name |
risk_severity | 'critical' | 'high' | 'medium' | 'low' | Analyst-assigned risk classification for missing coverage |
recommendation | string | Actionable guidance for closing the coverage gap |
Detection Rule (MITRE fields — from backend)
Model: platform/api/app/models/detection_rule.py — Table: detection_rules
| Column | Type | Description |
|---|---|---|
mitre_tactic | String | Single tactic name string. Normalized from mitre_tactics[0] for library rules. Used for coverage grouping. |
mitre_technique_id | String | Single technique ID string. Normalized from mitre_techniques[0] for library rules. Used for technique-level mapping. |
UI Layout
Page Structure
The page is contained in a max-w-7xl mx-auto wrapper and divided into five vertical sections rendered top-to-bottom:
- Header — Orange
Grid3X3icon in a rounded-lg tile, "MITRE ATT&CK Coverage" title, subtitle text, and a "Recalculate" button that re-callsfetchData. - Stats Row — 4-column grid of metric cards: Overall Coverage % with a color-coded progress bar (green ≥70%, yellow 40–69%, red <40%); Fully Covered count (green background); Partial Coverage count (yellow background); Uncovered Gaps count (red background).
- Per-Tactic Progress Bars — A 2-column grid inside a white card, one row per tactic. Each row shows the tactic name truncated to 144px, a flex-grow colored progress bar, and the percentage value.
- ATT&CK Matrix Grid — Horizontal CSS grid with one column per tactic (
minmax(100px, 1fr)). Tactic headers show the tactic name in 10px bold uppercase and a covered/total fraction. Below the headers, each technique renders as a small color-coded button cell:bg-green-500(full),bg-yellow-400(partial),bg-slate-200(none). Clicking any cell setsselectedTechniquestate and opens the modal. - Gap Analysis — A list of
GapItemrows, each showing: a risk severity badge, the technique ID and name in bold, the parent tactic name in muted gray, and a lightbulb icon followed by the recommendation string.
Technique Detail Modal
Triggered by clicking any matrix cell. Renders as a fixed full-viewport overlay with a centered white card (max-w-lg). Contents:
- Technique name (large bold) and ID + tactic name (small muted) in the header row
- Coverage status badge (Full Coverage / Partial Coverage / No Coverage) and rule count string
- If rules exist: a list of detection rule cards, each showing a Shield icon, rule name, and severity badge
- If no rules: empty state with
AlertTriangleicon and "No detection rules mapped" message
Modal closes on clicking the backdrop or the X icon button.
Prerequisites
- Detection Rules Endpoint —
GET /api/v1/detection-rules/?limit=1000must be reachable. The page degrades gracefully to deterministic mock data if unavailable, with an amber warning banner. - Rule MITRE Tags — Detection rules must have
mitre_tacticpopulated with exact MITRE tactic names (case-insensitive match). Rules withoutmitre_tacticdo not contribute to coverage scores. - API Client —
src/lib/api-client.tsmust be configured withNEXT_PUBLIC_API_URLpointing to the FastAPI backend (e.g.,https://api.threatops.roconpaas.io). - Detection Rules Router Registered —
platform/api/app/routers/detection_rules.pymust be included inapp/main.pyunder the/api/v1/detection-rulesprefix. - Rules Module —
platform/api/app/rules/must be importable andget_all_rules()must succeed. This supplies the 372 library rules with their MITRE metadata arrays. - No dedicated backend service required — Coverage computation is fully client-side. No additional database tables, background workers, or scheduled jobs are needed for this module.