# Risk Event Summarization

> Summarize risk events with impact assessment, affected controls, contributing factors, and recommended mitigation actions

- Skill: `happy-technologies-llc/risk-event-summarization` (Agent Skill)
- Install (CLI): `npx skillmds@latest add happy-technologies-llc/risk-event-summarization`
- Raw SKILL.md: https://api.skillmd.com/api/skills/happy-technologies-llc/risk-event-summarization/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- Author: Happy-Technologies-LLC (https://skillmd.com/u/happy-technologies-llc)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/happy-technologies-llc/risk-event-summarization

---


# GRC Risk Event Summarization

## Overview

This skill generates comprehensive summaries of risk events in ServiceNow GRC, providing stakeholders with a complete picture of what happened, why it happened, what was affected, and what should be done in response.

Key capabilities:
- **Event Context:** Aggregate risk event details including timeline, category, and triggering conditions
- **Impact Assessment:** Quantify financial, operational, reputational, and regulatory impact of risk events
- **Control Analysis:** Identify which controls failed, were bypassed, or were absent when the event occurred
- **Contributing Factor Analysis:** Determine root causes and contributing factors leading to the event
- **Mitigation Recommendations:** Generate prioritized mitigation actions based on event severity and control gaps
- **Trend Detection:** Identify patterns across related risk events to surface systemic issues

**When to use:**
- After a risk event materializes and stakeholders need a structured briefing
- During risk committee meetings requiring event summaries
- When building a risk event register or loss event database
- For regulatory reporting on operational risk events
- When conducting post-event reviews or lessons-learned sessions

## Prerequisites

- **Roles:** `sn_grc.manager`, `sn_risk.manager`, or `admin`
- **Plugins:** `com.sn_grc`, `com.sn_risk`, `com.sn_compliance`
- **Access:** Read access to `sn_risk_event`, `sn_grc_risk`, `sn_compliance_control`, `sn_grc_issue`, `sn_grc_profile`
- **Knowledge:** Understanding of organizational risk taxonomy and event categorization standards

## Key GRC Tables

| Table | Purpose | Key Fields |
|-------|---------|------------|
| `sn_risk_event` | Risk events / loss events | number, short_description, state, category, event_date, impact, likelihood, financial_impact, risk, profile |
| `sn_grc_risk` | Associated risk records | number, risk_score, residual_risk, inherent_risk, treatment, state, category |
| `sn_compliance_control` | Controls that should have mitigated the event | number, state, effectiveness, test_result, control_objective, owner |
| `sn_grc_issue` | Issues generated from events | number, state, priority, risk_rating, source |
| `sn_risk_definition` | Risk definitions and categories | number, short_description, risk_type, category |
| `sn_grc_profile` | Entity profiles | number, profile_type, applies_to |

## Procedure

### Step 1: Retrieve Risk Event Details

Fetch the target risk event with full context fields.

**Using MCP (Claude Code/Desktop):**
```
Tool: SN-Get-Record
Parameters:
  table_name: sn_risk_event
  sys_id: [EVENT_SYS_ID]
  fields: sys_id,number,short_description,description,state,category,subcategory,event_date,discovered_date,impact,likelihood,financial_impact,operational_impact,reputational_impact,regulatory_impact,risk,profile,assigned_to,assignment_group,root_cause,contributing_factors,sys_created_on
```

**Using REST API:**
```bash
GET /api/now/table/sn_risk_event?sysparm_query=number=[EVENT_NUMBER]&sysparm_fields=sys_id,number,short_description,description,state,category,subcategory,event_date,discovered_date,impact,likelihood,financial_impact,operational_impact,reputational_impact,regulatory_impact,risk,profile,assigned_to,root_cause,contributing_factors&sysparm_limit=1&sysparm_display_value=all
```

### Step 2: Gather Associated Risk Context

Pull the risk record linked to the event to understand the broader risk landscape.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_grc_risk
  query: sys_id=[event_risk_sys_id]
  fields: sys_id,number,short_description,risk_score,state,treatment,residual_risk,inherent_risk,category,owner,risk_appetite,risk_tolerance
  limit: 1
```

For all risks under the same profile:
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_grc_risk
  query: profile=[event_profile_sys_id]^active=true
  fields: sys_id,number,short_description,risk_score,residual_risk,inherent_risk,treatment,category
  limit: 25
```

**Using REST API:**
```bash
GET /api/now/table/sn_grc_risk?sysparm_query=profile=[profile_sys_id]^active=true&sysparm_fields=sys_id,number,short_description,risk_score,residual_risk,inherent_risk,treatment,category&sysparm_limit=25&sysparm_display_value=all
```

### Step 3: Identify Affected Controls

Query controls linked to the risk profile to determine which should have prevented the event.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_compliance_control
  query: profile=[event_profile_sys_id]^active=true
  fields: sys_id,number,short_description,state,control_objective,owner,effectiveness,test_result,test_date
  limit: 50
```

**Using REST API:**
```bash
GET /api/now/table/sn_compliance_control?sysparm_query=profile=[profile_sys_id]^active=true&sysparm_fields=sys_id,number,short_description,state,control_objective,owner,effectiveness,test_result,test_date&sysparm_limit=50&sysparm_display_value=all
```

### Step 4: Retrieve Work Notes and Investigation History

Pull investigation notes to capture analyst findings and contributing factor analysis.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sys_journal_field
  query: name=sn_risk_event^element_id=[EVENT_SYS_ID]^element=work_notes^ORDERBYDESCsys_created_on
  fields: value,sys_created_on,sys_created_by
  limit: 25
```

**Using REST API:**
```bash
GET /api/now/table/sys_journal_field?sysparm_query=name=sn_risk_event^element_id=[event_sys_id]^element=work_notes^ORDERBYDESCsys_created_on&sysparm_fields=value,sys_created_on,sys_created_by&sysparm_limit=25
```

### Step 5: Check for Related Issues and Historical Events

Identify GRC issues spawned from the event and similar past events.

**Using MCP:**
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_grc_issue
  query: source_record=[EVENT_SYS_ID]^ORprofile=[event_profile_sys_id]
  fields: sys_id,number,short_description,state,priority,risk_rating,source,sys_created_on
  limit: 20
```

For historical pattern analysis:
```
Tool: SN-Query-Table
Parameters:
  table_name: sn_risk_event
  query: category=[event_category]^sys_id!=[EVENT_SYS_ID]^event_date>=javascript:gs.daysAgo(365)^ORDERBYDESCevent_date
  fields: sys_id,number,short_description,category,event_date,financial_impact,state
  limit: 25
```

### Step 6: Generate Comprehensive Risk Event Summary

**Using MCP:**
```
Tool: SN-Execute-Background-Script
Parameters:
  script: |
    var eventNumber = 'RE0001234'; // Replace with target event
    var gr = new GlideRecord('sn_risk_event');
    gr.addQuery('number', eventNumber);
    gr.query();

    if (!gr.next()) { gs.info('Event not found'); return; }

    var summary = {
      event: {
        number: gr.number.toString(),
        title: gr.short_description.toString(),
        description: gr.description.toString(),
        state: gr.state.getDisplayValue(),
        category: gr.category.getDisplayValue(),
        event_date: gr.event_date.getDisplayValue(),
        discovered_date: gr.discovered_date.getDisplayValue(),
        detection_lag_days: 0
      },
      impact_assessment: {
        overall_impact: gr.impact.getDisplayValue(),
        financial: gr.financial_impact.toString() || 'Not quantified',
        operational: gr.operational_impact.getDisplayValue() || 'Not assessed',
        reputational: gr.reputational_impact.getDisplayValue() || 'Not assessed',
        regulatory: gr.regulatory_impact.getDisplayValue() || 'Not assessed'
      },
      affected_controls: [],
      contributing_factors: [],
      related_issues: [],
      historical_pattern: { similar_events_12mo: 0, total_financial_loss: 0 },
      mitigation_recommendations: []
    };

    // Detection lag
    if (gr.event_date.toString() && gr.discovered_date.toString()) {
      var evtDate = new GlideDateTime(gr.event_date.toString());
      var discDate = new GlideDateTime(gr.discovered_date.toString());
      summary.event.detection_lag_days = parseInt(gs.dateDiff(evtDate.toString(), discDate.toString(), true)) || 0;
    }

    // Contributing factors from record
    if (gr.root_cause.toString()) summary.contributing_factors.push('Root Cause: ' + gr.root_cause.toString());
    if (gr.contributing_factors.toString()) summary.contributing_factors.push('Factors: ' + gr.contributing_factors.toString());

    var profileId = gr.profile.toString();

    // Affected controls
    var ctrl = new GlideRecord('sn_compliance_control');
    ctrl.addQuery('profile', profileId);
    ctrl.addQuery('active', true);
    ctrl.query();
    while (ctrl.next()) {
      var ctrlStatus = ctrl.state.getDisplayValue();
      var wasEffective = (ctrlStatus == 'Compliant' || ctrlStatus == 'Passed');
      summary.affected_controls.push({
        control: ctrl.number.toString(),
        title: ctrl.short_description.toString(),
        state: ctrlStatus,
        effectiveness: ctrl.effectiveness.getDisplayValue(),
        prevented_event: wasEffective,
        owner: ctrl.owner.getDisplayValue()
      });
      if (!wasEffective) {
        summary.contributing_factors.push('Control failure: ' + ctrl.number.toString() + ' (' + ctrlStatus + ')');
      }
    }

    // Related issues
    var issue = new GlideRecord('sn_grc_issue');
    issue.addQuery('profile', profileId);
    issue.addQuery('active', true);
    issue.query();
    while (issue.next()) {
      summary.related_issues.push({
        number: issue.number.toString(),
        title: issue.short_description.toString(),
        priority: issue.priority.getDisplayValue(),
        state: issue.state.getDisplayValue()
      });
    }

    // Historical pattern
    var hist = new GlideRecord('sn_risk_event');
    hist.addQuery('category', gr.category.toString());
    hist.addQuery('sys_id', '!=', gr.sys_id.toString());
    hist.addQuery('event_date', '>=', gs.daysAgo(365));
    hist.query();
    while (hist.next()) {
      summary.historical_pattern.similar_events_12mo++;
      summary.historical_pattern.total_financial_loss += parseFloat(hist.financial_impact.toString()) || 0;
    }

    // Generate mitigation recommendations
    var failedControls = summary.affected_controls.filter(function(c) { return !c.prevented_event; });
    if (failedControls.length > 0) {
      summary.mitigation_recommendations.push('IMMEDIATE: Remediate ' + failedControls.length + ' failed controls identified during event analysis');
    }
    if (summary.event.detection_lag_days > 7) {
      summary.mitigation_recommendations.push('SHORT-TERM: Improve detection capabilities - ' + summary.event.detection_lag_days + ' day detection lag exceeds acceptable threshold');
    }
    if (summary.historical_pattern.similar_events_12mo >= 3) {
      summary.mitigation_recommendations.push('STRATEGIC: Investigate systemic root cause - ' + summary.historical_pattern.similar_events_12mo + ' similar events in past 12 months indicates pattern');
    }
    summary.mitigation_recommendations.push('ONGOING: Update risk assessment to reflect materialized event and adjust residual risk scores');

    gs.info('RISK EVENT SUMMARY:\n' + JSON.stringify(summary, null, 2));
  description: "GRC: Generate comprehensive risk event summary with impact assessment"
```

### Step 7: Generate Executive Narrative

**Using MCP:**
```
Tool: SN-Execute-Background-Script
Parameters:
  script: |
    var narrative = [];
    narrative.push('=== RISK EVENT EXECUTIVE SUMMARY ===');
    narrative.push('');

    var agg = new GlideAggregate('sn_risk_event');
    agg.addQuery('event_date', '>=', gs.daysAgo(90));
    agg.addAggregate('COUNT');
    agg.groupBy('category');
    agg.query();

    narrative.push('RISK EVENTS - LAST 90 DAYS BY CATEGORY:');
    while (agg.next()) {
      narrative.push('  ' + agg.category.getDisplayValue() + ': ' + agg.getAggregate('COUNT') + ' events');
    }
    narrative.push('');

    // Top events by financial impact
    narrative.push('TOP EVENTS BY FINANCIAL IMPACT:');
    var top = new GlideRecord('sn_risk_event');
    top.addQuery('event_date', '>=', gs.daysAgo(90));
    top.addNotNullQuery('financial_impact');
    top.orderByDesc('financial_impact');
    top.setLimit(5);
    top.query();
    var idx = 1;
    while (top.next()) {
      narrative.push('  ' + idx + '. ' + top.number + ' - ' + top.short_description);
      narrative.push('     Financial Impact: $' + top.financial_impact + ' | Category: ' + top.category.getDisplayValue());
      idx++;
    }

    gs.info(narrative.join('\n'));
  description: "GRC: Generate quarterly risk event narrative for leadership"
```

## Tool Usage

| Operation | MCP Tool | REST Endpoint |
|-----------|----------|---------------|
| Read Event | SN-Get-Record | GET /api/now/table/sn_risk_event/{sys_id} |
| Query Events | SN-Query-Table | GET /api/now/table/sn_risk_event |
| Query Controls | SN-Query-Table | GET /api/now/table/sn_compliance_control |
| Query Risks | SN-Query-Table | GET /api/now/table/sn_grc_risk |
| Aggregate Analysis | SN-Execute-Background-Script | POST /api/now/table/sys_trigger |
| Search Events | SN-Natural-Language-Search | N/A |

## Best Practices

- **Timeliness:** Generate summaries within 24 hours of event discovery while details are fresh
- **Quantify Impact:** Always attempt to quantify financial impact, even as an estimate with confidence range
- **Root Cause Depth:** Distinguish between immediate causes and systemic contributing factors
- **Control Mapping:** Explicitly identify which controls should have prevented or detected the event
- **Historical Context:** Include trend data to distinguish one-off events from systemic patterns
- **Actionable Recommendations:** Every summary should end with specific, assignable mitigation actions
- **Regulatory Awareness:** Flag events that may trigger regulatory notification requirements

## Troubleshooting

### Risk Event Table Not Found

**Symptom:** `sn_risk_event` returns no results or table not found
**Cause:** The risk event table name may differ across ServiceNow versions; some use `sn_risk_event` while others use `sn_grc_loss_event`
**Solution:**
```
Tool: SN-Discover-Table-Schema
Parameters:
  table_name: sn_risk_event
```
If not found, search for tables containing "risk_event" or "loss_event" in `sys_db_object`.

### Financial Impact Field Empty

**Symptom:** Financial impact data is consistently null despite events having known costs
**Cause:** Financial impact may be tracked in a related loss record rather than on the event itself
**Solution:** Check for related tables like `sn_risk_loss` or custom financial impact assessment records linked via reference fields.

### No Controls Linked to Event Profile

**Symptom:** Control analysis returns empty results for the event profile
**Cause:** The event may not be linked to a GRC profile, or controls use a different relationship path
**Solution:** Check the `item` field on the event instead of `profile`, or query `sn_grc_m2m_item_profile` for the relationship mapping.

## Examples

### Example 1: Operational Risk Event Summary

**Scenario:** System outage event RE0002345 affecting payment processing

- **Event:** Unplanned outage of payment gateway, 4-hour duration
- **Detection Lag:** 15 minutes (automated monitoring alert)
- **Financial Impact:** $180,000 in lost transaction revenue
- **Failed Controls:** 2 -- disaster recovery test (not tested in 14 months), capacity monitoring threshold (set too high)
- **Contributing Factors:** Infrastructure change without proper testing, single point of failure in payment routing
- **Similar Events (12 months):** 2 prior events totaling $95,000
- **Recommendations:** Update DR testing schedule, lower capacity thresholds, implement redundant payment routing

### Example 2: Compliance Risk Event Summary

**Scenario:** Data breach event RE0003001 involving customer PII exposure

- **Event:** Unauthorized access to customer database via compromised service account
- **Detection Lag:** 12 days (flagged by external security researcher)
- **Records Affected:** 15,000 customer records
- **Regulatory Impact:** GDPR Article 33 notification required within 72 hours
- **Failed Controls:** 3 -- privileged access review, service account rotation, database activity monitoring
- **Recommendations:** Immediate credential rotation, deploy database activity monitoring, establish 72-hour notification procedure

## Related Skills

- `grc/issue-summarization` - Summarize GRC issues generated from risk events
- `grc/risk-assessment-summarization` - Broader risk assessment context
- `grc/suggest-remediation-tasks` - Generate remediation tasks for event-related control gaps
- `grc/regulatory-alert-analysis` - Identify regulatory implications of risk events
- `grc/control-objective-management` - Manage controls affected by events

