SuperAPI AI Directory

risk-event-summarization

General & other

View repository

Updated 10-15 22:12

About this skill

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:

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:

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:

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:

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