"…". Prefix a term or phrase with - to exclude rules containing it (e.g. powershell -o365, "data exfiltration" -"hubspot").third_party_alert)Each rule listed here is one whose LEQL query contains strings, file names, command-line fragments, registry paths or other literal values that actually appear in the log you uploaded — but the rule was written for a different event_type and field schema than your log.
Why this matters: a strong content match is hard evidence that your log records the same kind of activity the rule was designed to catch. The rule just expects a different event_type and field names than your custom log has.
How to use these: you can\'t set a custom log\'s event_type by parsing, so don\'t try to re-tag the log. Instead, send a rule to the Rule Designer — it produces a custom version that removes the event_type filter and maps each field path to the field names that already exist in your log. Then verify it on the Rule Analysis tab.
Why only some rules show: we require a "strong" content match (at least one needle of length ≥ 8 OR ≥ 2 distinct shorter needles). Without this filter, very generic substrings (exe, true, etc.) would surface every other rule in the library.
Click the 🔬 Analyze button on any rule detail panel to send it here. The button appears in:
If you haven\'t uploaded a log yet, head to Log Analysis first so this page has something to compare against.
event_type filter (a custom log's event_type can't be set by parsing) and maps the rule's field paths to the field names that actually appear in your log. Save as a custom rule, then verify it on the Rule Analysis tab.
Detect categories, hit Find analogue rules, then click any candidate below to start adapting it here.
Detect categories first, then hit "Find analogue rules" to surface rules from other vendors.
A self-contained HTML viewer over your full Rapid7 InsightIDR detection-rule library, with MITRE ATT&CK coverage analytics, threat-group overlays, infrastructure scoping, and progress tracking.
localStorage.The viewer lets you:
It's read-only with respect to Rapid7 itself — it doesn't make API calls. The 21,733 rules were exported from Rapid7's API in a prior session and packed into the HTML.
rapid7_rules_viewer.html in Chrome / Edge / Firefox / Safari (any modern browser).Top-bar buttons:
State is saved in your browser. Open the file from the same browser profile to resume where you left off.
The full searchable rule list.
"quoted phrases". Multiple terms are AND-matched. Example: kerberos "service = X" finds rules containing both kerberos and the exact phrase service = X.The ↗ next to a rule name opens it in InsightIDR. The deep-link URL is configurable: override the base URL with localStorage.setItem('r7_base_url', 'https://<region>.idr.insight.rapid7.com/op/<orgId>'). (For older single-region tenants, localStorage.setItem('r7_org_uuid', '<uuid>') still works as a fallback.)
This is the analytical heart of the viewer.
Top of the page — overall coverage stats: matching rules, MITRE tactics covered, distinct techniques observed, Customer/MDR split.
Infrastructure picker — a grid of cards grouped by category (Endpoints, Cloud Compute, Azure, SaaS, Identity, Edge / Network, Custom Platform). Click any card to include it in scope. Each card shows the rule count it pulls in. Cards have three flavours:
Quick-action buttons: Use all ingested infra (everything onboarded, incl. ingested-but-not-parsed), Use infra with detection coverage (only Parsed/Live sources with working rule coverage), Include planned sources, Exclude planned, Clear.
Log Sources picker — your 15 Rapid7 log sources. Selecting one auto-toggles the matching event types below.
Event types & subtypes — chips you can toggle individually if the infra/log-source level isn't fine-grained enough. Search box filters the chip list.
MITRE ATT&CK matrix — one column per tactic (14 columns), techniques inside each column. Heat intensity shows rule density. The Hide sub-techniques toggle rolls everything up to parent techniques. The Show coverage gaps toggle re-colours cells to show what you have vs what you'd have if you onboarded missing sources (red dashed cells = "you have 0 rules here, others have N").
Gap Analysis by Source Category — a heatmap showing, for each MITRE tactic × security category (Endpoint, Identity, Cloud, SaaS, EDR/XDR, Edge, Custom, Other), how many rules you currently cover live vs total available. +N annotations show extra rules your selected planned sources would unlock.
Matching rules list — sortable, paginated, with the same expandable detail rows as the Rules tab. Updates live as you change scope or click a matrix cell.
How well your rules cover real-world adversary behaviour. Two modes via a segmented toggle at the top:
170 named MITRE intrusion-sets (APT29, Lazarus, Volt Typhoon, FIN7, etc.).
↗ opens the group on attack.mitre.org. The ▸ N expander reveals the group's MITRE-tracked campaigns inline, each selectable independently with its own coverage %.15 curated technique groupings — Phishing, Ransomware & Extortion, Wiper / Destructive, Credential Theft, MFA Bypass, Lateral Movement, Persistence, Privilege Escalation, Living off the Land, Defense Evasion, Command & Control, Data Exfiltration, Cloud Account & Resource Abuse, Supply Chain, Discovery & Recon.
Each card shows the % of parent techniques in that category your rules cover. Click to overlay on the matrix.
Per-source documentation and config guidance.
source_json.event_data.script_block_text) sorted by frequency. Useful for knowing what your log format must contain.event_types / subtypes / name keywords used to associate rules with this source.script_block_text — Script Block Logging must be on".The View matching rules button at the top of each source detail switches to the Coverage tab pre-scoped to just that source.
Track coverage progress over time.
Storage is browser localStorage. Use Export JSON to back up across browsers/machines.
This is the conceptual core of how rules get associated with your environment. Read this if you want to understand or change the matching behaviour.
Every link between "your environment" and "the rule library" passes through a matcher object:
matcher = {
et: ['cloud_service_activity', ...], // event types
es: ['microsoft_defender_xdr', ...], // event subtypes (optional)
kw: ['azure', 'workspace', ...] // name keywords (optional)
}
A rule passes a matcher if:
et array shares at least one value with the matcher's et list (or matcher's et is empty).es array shares at least one value with the matcher's es list (or matcher's es is empty).kw is empty).All three conditions must hold (AND across et/es/kw, OR within each list). Empty constraints don't filter.
et — event types this infra produces
- es — event subtypes it produces (often empty for non-Defender sources)
- nameKeywords — vendor-identifying words you'd expect in rule namesExample:
js
{
key: 'azure_resources',
name: 'Azure Resources',
cat: 'Azure',
et: ['cloud_service_activity', 'cloud_service_admin', 'firewall', 'flow'],
es: [],
nameKeywords: ['azure', 'microsoft azure', 'arm', 'app service',
'key vault', 'keyvault', 'sql server', 'sql database',
'vnet', 'nsg', 'azure firewall', 'azure storage']
}
So an Azure-Resources matcher is {et: [...4 types...], es: [], kw: [...12 keywords...]}. A rule named "AWS CloudTrail …" wouldn't match because no keyword hits.
js
{ key: 'cloud_act', name: 'Cloud Service Activity', et: ['cloud_service_activity'] }
By itself this would match every rule with cloud_service_activity in its event-type list — including AWS, GCP, Salesforce, OCI rules even if you don't have them. That was the historical bug. See the next subsection.
kw.To avoid the over-pull described above, log-source matchers are now built dynamically at call time by the helper logSourceMatcher(ls):
function logSourceMatcher(ls) {
const lsEt = ls.et || [];
const kws = new Set();
for (const inf of INFRA) {
if (!cstate.infra.has(inf.key)) continue; // only currently-selected infras
const infEt = (inf.et || []).concat(inf.potential ? (inf.potential.et || []) : []);
if (!infEt.some(e => lsEt.includes(e))) continue; // must share at least one event type
for (const k of (inf.nameKeywords || [])) kws.add(k.toLowerCase());
}
return { et: lsEt, es: [], kw: [...kws] };
}
The vendor keyword set is the union of nameKeywords from every selected INFRA that shares at least one event type with the log source. If no selected infra contributes keywords (e.g. for process_start_event from win_laptops which has no nameKeywords), the keyword filter stays empty — broadest behaviour, no over-restriction.
Worked example. User has Azure Resources + Google Workspace + Azure Entra ID selected. They click the "Cloud Service Activity" log source.
| Selected infra | shares cloud_service_activity? |
contributes keywords |
|---|---|---|
| Azure Resources | yes (et has it) | azure, arm, app service, key vault, vnet, … |
| Google Workspace | yes (et has it) | workspace, gmail, gsuite, google apps, … |
| Azure Entra ID | no (et has sso, cloud_service_admin, ad_admin, ingress_auth — not this one) |
— (skipped) |
Resulting matcher: {et: ['cloud_service_activity'], es: [], kw: ['azure','arm','app service','workspace','gmail',...]}.
Verified against the real library: this drops the rule count for "Cloud Service Activity" from 225 (which included 108 AWS rules and 5 GCP rules) to 42 (only Azure + Google Workspace rules).
This table is the source of truth for which log sources scope to which infrastructure components. The 15 log sources in the viewer are the ones in your Rapid7 setup. INFRA components are everything in the Coverage tab's Infrastructure picker (live + planned + gap).
| Log Source | event_types produced |
Selected INFRAs that share these types (and therefore scope the matcher) |
|---|---|---|
| Active Directory Admin Activity | ad_admin |
Entra ID (kw: azure, entra, aad, …), JumpCloud (kw: jumpcloud) |
| Asset Authentication | asset_auth |
Win Laptops, Mac Laptops, Win VMs, Linux VMs (no kw → no vendor restriction) |
| Audit Logs (InsightIDR internal) | rapid7_product_alert |
(none — vendor-agnostic by design) |
| Cloud Service Activity | cloud_service_activity |
Azure Resources (kw: azure, …), Google Workspace (kw: workspace, gmail, …), GitHub (kw: github), HubSpot (kw: hubspot), HiBob (kw: hibob), Atlassian (kw: jira, confluence, …), Other SaaS (no kw — catch-all) |
| Cloud Service Admin Activity | cloud_service_admin |
Entra ID (kw: azure, entra, …), Azure Resources, Google Workspace, GitHub, HubSpot, HiBob, Atlassian, Other SaaS |
| Endpoint Activity | endpoint_activity, process_start_event, local_service_installed, file_access, file_modification, dns |
Win Laptops, Mac Laptops, Win VMs, Linux VMs (no kw) |
| Endpoint Agent | endpoint_health |
Win Laptops, Mac Laptops (no kw) |
| Endpoint Health | endpoint_health |
(same as above) |
| General Activity | raw, general_activity |
Platform User Activity (no kw — gap card) |
| Ingress Authentication | ingress_auth |
Entra ID, Google Workspace, HubSpot, HiBob, Atlassian, Descope, JumpCloud, Platform Activity, Other SaaS |
| Internal Logs | raw, log_deletion |
Platform Activity (raw) |
| SSO Authentication | sso |
Entra ID (kw: azure, entra, …), Descope (kw: descope), JumpCloud (kw: jumpcloud) |
| Third Party Alert | third_party_alert |
EDR Agent + Defender (subtype-scoped to Defender products only) |
| Unparsed Logs | unparsed |
(none — by design) |
| Virus Alert | virus, advanced_malware |
(none — vendor-agnostic) |
Reading the table: when you click Cloud Service Activity, the matcher's keyword filter is the union of nameKeywords from every INFRA in column 3 that you currently have selected. If none of those INFRAs are selected (or none have nameKeywords), the matcher has no keyword filter and pulls everything.
For endpoint-type log sources (Endpoint Activity, Asset Authentication, etc.) the contributing INFRAs all have empty nameKeywords because Windows/Mac/Linux rules aren't vendor-tagged in their names. The matcher's kw stays empty — that's intentional and correct. Endpoint rules are filtered by event type alone.
Example 1 — A Windows endpoint rule (event-type only, no keyword needed)
Rule: "PowerShell - Encoded Command Execution"
et: [process_start_event]
es: []
text: "...PowerShell command using -EncodedCommand or -enc flag..."
With Win Laptops selected: matcher = {et:[process_start_event, ...], es:[], kw:[]}. Rule's et matches. No keyword to satisfy. Match.
Example 2 — A SaaS rule passes vendor-keyword scoping
Rule: "Google Workspace - MFA Disabled for User"
et: [cloud_service_admin]
es: []
text: "Detects when an administrator disables MFA in Google Workspace..."
User has Google Workspace selected. Click "Cloud Service Admin Activity":
- LS matcher = {et:[cloud_service_admin], es:[], kw:[..., 'workspace','gmail','gsuite',...]}
- Rule's et matches ✓
- Rule's text contains "google workspace" → kw matches ✓
- Match.
Example 3 — Vendor-keyword scoping correctly filters AWS rules
Rule: "AWS CloudTrail - API Gateway Triggering Specific Version of Lambda Function"
et: [cloud_service_activity]
es: []
text: "Detects when an attacker triggers a specific version of an AWS Lambda function..."
User has Azure Resources + Google Workspace selected (no AWS infra). Click "Cloud Service Activity":
- LS matcher = {et:[cloud_service_activity], es:[], kw:['azure','arm','workspace','gmail',...]}
- Rule's et matches ✓
- Rule's text does NOT contain any of azure, arm, workspace, etc. — it contains "aws", "cloudtrail", "lambda"
- Filtered out ✓ (this was the bug we fixed)
Example 4 — Defender alerts use subtype scoping, not keywords
INFRA: EDR Agent + Defender
et: [third_party_alert]
es: [microsoft_defender_xdr, microsoft_defender_for_cloud, microsoft_defender_for_identity,
microsoft_defender_for_cloud_apps, microsoft_defender_for_office_365,
microsoft_security, microsoft_sentinel, aad_identity_protection]
nameKeywords: []
A rule with et=[third_party_alert] and es=[microsoft_defender_xdr] would match the Defender INFRA. A rule with et=[third_party_alert] and es=[crowdstrike_falcon] would not — wrong subtype. That's why subtype precision matters here even when keyword scoping doesn't apply.
A few different percentages appear throughout the viewer. Each is computed slightly differently:
(rules currently in scope) / (total rules in dataset) × 100.
This is just "how much of the rule library applies to me right now". Shown on the Coverage tab top stats and Trends scopePct.
(tactics where at least one in-scope rule fires) / 14 × 100.
The MITRE Enterprise matrix has 14 tactics. This metric is almost always 100% for any realistically-sized environment because the matrix is wide.
(distinct parent T-ids tagged by in-scope rules) / (distinct parent T-ids in the dataset, source-filtered) × 100.
More meaningful than tactic coverage. The dataset reference (denominator) is "every parent technique that any rule in the library mentions", not the full 700+ MITRE techniques — so this is a coverage-vs-available metric.
(parent T-ids attacked by ANY group AND covered by in-scope rules) / (parent T-ids attacked by ANY group) × 100.
The most important number on the Attack Coverage tab. It tells you: of all the techniques real-world adversaries are known to use, how many do your rules cover?
Cross-platform parent equivalence is built in: a rule tagged T1078.004 (Cloud Accounts) covers an attacker using T1078.001 (Default Accounts) because both share the parent T1078 (Valid Accounts). The premise is that detection logic for one sub-technique of a family usually generalises to its siblings.
For a single threat group, same logic restricted to that group's technique repertoire.
(parent T-ids attacked by THIS group AND covered) / (parent T-ids attacked by THIS group) × 100.
(parent T-ids in this curated category AND covered) / (parent T-ids in this category) × 100.
Every selection, filter, and tab state lives in browser localStorage:
| Key | Contents |
|---|---|
r7v |
Rules tab — query, filters, sort, page-size |
r7c |
Coverage tab — infra, log sources, event types/subtypes, matrix selection, gap category, source filter, last opened source |
r7a |
Attack Coverage — mode, selected groups/campaigns/categories, tag filters, expanded groups, sort, search, matrix cell |
r7v_view |
Currently-active tab |
r7v_collapse_* |
Per-section collapsed state |
r7v_export_fields |
CSV export field selection |
r7_snapshots |
Trends snapshots array |
r7t_series |
Trends chart series toggles |
r7_org_uuid |
Rapid7 tenant UUID for deep-links |
Snapshots are an array of objects shaped like:
{
v: 1,
ts: '2026-05-12T14:30:00.000Z',
date: '2026-05-12',
scope: '8 live · 4 planned · 15 log src',
filters: { src:[], ls:[...], et:[...], es:[...], infra:[...] },
metrics: {
rulesInScope: 1234, rulesTotal: 21733, scopePct: 5.7,
tacCovered: 14, tacTotal: 14, tacPct: 100,
techCovered: 188, techTotalDataset: 203, techPct: 92.6,
attackPct: 93.5, attackCovered: 188, attackTotal: 201,
catPct: { phishing: 100, ransomware: 100, ... },
cust: 800, mdr: 300, both: 134
}
}
Use Export JSON on the Trends tab to back this up to a file. Import JSON merges in (dedupes by ts).
Why is my rule count higher than expected after clicking a log source?
Most likely your matcher has no keyword filter because no selected INFRA shares an event type with this log source. Either select the relevant INFRA (e.g. Google Workspace, not just the "Cloud Service Activity" log source) or use the Sources tab to see the matcher details for that log source.
Why does my coverage % drop after I onboard a new source?
It shouldn't — onboarding adds rules, never removes them. If the % dropped, check the source filter chip (Customer / MDR) at the top of the Coverage tab. With no source picked you get both; picking only one restricts.
My snapshot from yesterday shows a different rules-in-scope than today, but I haven't changed anything.
The viewer is a static export of the rule library. As long as you're using the same HTML file, the rule library hasn't changed. Most likely the Coverage scope did — recheck the snapshot's scope column and the current Coverage filters.
Can I refresh the rule data from Rapid7?
The 21,733 rules are baked into the HTML. To refresh, re-export from Rapid7's API and rebuild the HTML — outside the scope of the viewer itself. The handoff document explains the build process.
Does the viewer share my data anywhere?
No. It's an offline HTML file. There are no network calls, no telemetry, no analytics. Everything stays in your browser's localStorage until you clear it.
How do I move my snapshots to a different browser or machine?
Trends tab → Export JSON. Open the viewer in the new browser, Trends tab → Import JSON.
A technique I expect to see in the matrix isn't there.
The matrix only shows techniques that at least one rule in the dataset references or (in Attack Coverage with a selection) that an attacker uses. If a technique isn't on the MITRE radar of any rule, it won't appear. Check the Rules tab Meta search scope for the technique ID to confirm.
Colours look off to me — can I switch palette?
The viewer ships with an Okabe-Ito-inspired colourblind-safe palette. Status (live/planned/gap) and coverage tiers are also conveyed via icons (✓/⏳/⚠/✗) and patterns (striped fill for attacked-and-gap), so the palette swap shouldn't lose meaning. There's no built-in switch — if you need a different one, edit the :root CSS variables block at the top of the file.
Last updated alongside the v2 handoff. If you're reading this in a new Cowork session, also attach rapid7_handoff_v2.md to bring full development context.
—