skills/grc/risk-event-summarization/SKILL.md
Summarize risk events with impact assessment, affected controls, contributing factors, and recommended mitigation actions
npx skillsauth add happy-technologies-llc/happy-servicenow-skills risk-event-summarizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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:
When to use:
sn_grc.manager, sn_risk.manager, or admincom.sn_grc, com.sn_risk, com.sn_compliancesn_risk_event, sn_grc_risk, sn_compliance_control, sn_grc_issue, sn_grc_profile| 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 |
Fetch the target risk event with full context fields.
Using MCP (Claude Code/Desktop):
Tool: SN-Read-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
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
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
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
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
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"
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"
| Operation | MCP Tool | REST Endpoint | |-----------|----------|---------------| | Read Event | SN-Read-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 |
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.
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.
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.
Scenario: System outage event RE0002345 affecting payment processing
Scenario: Data breach event RE0003001 involving customer PII exposure
grc/issue-summarization - Summarize GRC issues generated from risk eventsgrc/risk-assessment-summarization - Broader risk assessment contextgrc/suggest-remediation-tasks - Generate remediation tasks for event-related control gapsgrc/regulatory-alert-analysis - Identify regulatory implications of risk eventsgrc/control-objective-management - Manage controls affected by eventstesting
Manage supplier onboarding, qualification, performance monitoring, and offboarding with auditable lifecycle controls
tools
Identify emerging risks, prioritize intake signals, and route candidates into formal GRC risk assessment workflows
documentation
Screen inbound documents for completeness, policy risk, and routing readiness before extraction or case workflows
testing
Generate concise task summaries with status, timeline, blockers, SLA risk, and recommended next actions