diff --git a/Plugins/Community Based Plugins/DualSignalContainmentGate/DualSignalContainmentGate.yaml b/Plugins/Community Based Plugins/DualSignalContainmentGate/DualSignalContainmentGate.yaml new file mode 100644 index 00000000..6259ff87 --- /dev/null +++ b/Plugins/Community Based Plugins/DualSignalContainmentGate/DualSignalContainmentGate.yaml @@ -0,0 +1,172 @@ +# Dual-signal Gate/Prove plugin for Microsoft Security Copilot. +# Hard rule: ML confidence is not a classic signature true positive. +# Plugin updated 2026-08-16 +# +# Spacing matters. Use spaces, not tabs. + +Descriptor: + Name: DualSignalContainmentGate + DisplayName: Dual-signal containment gate + Description: > + Classifies Cisco Firepower / Snort-family incidents as ML-only, classic signature, + dual-signal corroborated, or unknown. Forbids recommend-contain on ML-only and unknown. + Optional Sentinel KQL lists GID 411 ML-only events vs high-priority signature events. + + Settings: + - Name: TenantId + Label: TenantId + Description: Azure tenant ID where Sentinel exists. + HintText: Azure tenant ID where Sentinel exists. + SettingType: String + Required: true + + - Name: SubscriptionId + Label: SubscriptionId + Description: Azure subscription ID where Sentinel exists. + HintText: Azure subscription ID where Sentinel exists. + SettingType: String + Required: true + + - Name: WorkspaceName + Label: WorkspaceName + Description: Log Analytics workspace name for Sentinel. + HintText: Log Analytics workspace name for Sentinel. + SettingType: String + Required: true + + - Name: ResourceGroupName + Label: ResourceGroupName + Description: Resource group where Sentinel workspace exists. + HintText: Resource group where Sentinel workspace exists. + SettingType: String + Required: true + + SupportedAuthTypes: + - None + +SkillGroups: + - Format: GPT + Skills: + - Name: ClassifyDualSignalContainment + DisplayName: Classify dual-signal disposition + Description: > + Classify an incident or notable as ml_only, signature, corroborated, or unknown + and decide whether Copilot may recommend containment. + DescriptionForModel: > + You are a detection and remediation gate. Machine-learning confidence is NEVER + equivalent to a classic IDS signature true positive. SnortML GID 411, is_ml_only, + dual-signal:ml-only, and EVE threat confidence >= 80 without a classic signature + are ML-only. Classic Snort GID (not 411) or high-priority classifications are + signature. Signature plus ML/EVE or is_corroborated is corroborated. Empty or + unclear context is unknown and must fail closed. You MUST NOT recommend block IP, + isolate host, quarantine, or any auto-contain when disposition is ml_only or unknown. + Those cases escalate for corroboration and HITL. Signature and corroborated may + recommend gated containment with analyst confirmation, never ungated automation. + ExamplePrompts: + - Should I contain this Firepower incident + - Classify this SnortML alert for containment + - Is this GID 411 event a signature true positive + - Dual-signal gate this intrusion notable before block IP + Inputs: + - Name: incidentText + Description: Incident title, description, notable name, and any GID, classification, SnortML, or EVE text. + Required: true + Settings: + ModelName: gpt-4o + Template: |- + Classify the following security incident for containment. Follow the dual-signal Gate/Prove rules exactly. + + Hard rule: ML confidence is NOT a classic signature true positive. Never equate SnortML / GID 411 / EVE-high to GID 1 signature TP. + + Markers: + - ML-only: gid 411, gid:411, generator id 411, SnortML, is_ml_only, ml-only, dual-signal:ml-only, EVE threat confidence >= 80 without a classic signature. + - Classic signature: generator id not 411, gid 1, high-priority classifications such as attempted-admin, attempted-user, successful-admin, trojan-activity, web-application-attack, A Network Trojan was Detected, Attempted Administrator Privilege Gain. + - Corroborated: is_corroborated, dual-signal:corroborated, signature and ml, classic signature AND (SnortML or EVE-high). + - GID 411 plus a leftover classification string is still ML-only unless an explicit classic GID or corroboration marker is present. + + Return exactly this structure: + DISPOSITION: ml_only | signature | corroborated | unknown + ALLOW_AUTO_CONTAIN: true | false + REQUIRE_HITL: true | false + COPILOT_MAY_RECOMMEND_CONTAIN: true | false + NEXT_ACTION: escalate | gated_contain_with_hitl | fail_closed + REASON: one short paragraph + NEVER_EQUATE_ML_TO_SIGNATURE: true + + Rules for fields: + - ml_only: ALLOW_AUTO_CONTAIN=false, REQUIRE_HITL=true, COPILOT_MAY_RECOMMEND_CONTAIN=false, NEXT_ACTION=escalate + - unknown: ALLOW_AUTO_CONTAIN=false, REQUIRE_HITL=true, COPILOT_MAY_RECOMMEND_CONTAIN=false, NEXT_ACTION=fail_closed + - signature or corroborated: ALLOW_AUTO_CONTAIN=true, REQUIRE_HITL=false (HITL still preferred), COPILOT_MAY_RECOMMEND_CONTAIN=true only as gated HITL, NEXT_ACTION=gated_contain_with_hitl + Never suggest ungated BlockIP, Logic App auto-contain, or SOAR block ip on ml_only or unknown. + + Incident text: + {{incidentText}} + + - Format: KQL + Skills: + - Name: ListSnortMlOnlyFirepowerEvents + DisplayName: List SnortML ML-only events + Description: > + Lists Cisco Firepower / Secure Firewall CommonSecurityLog events that match + SnortML GID 411 or is_ml_only. These are escalate/corroborate, not auto-contain. + ExamplePrompts: + - Show SnortML ML-only Firepower events + - List GID 411 Firepower alerts from Sentinel + - Get recent SnortML events that must not auto-contain + Inputs: + - Name: lookback + PlaceholderValue: 24h + Description: Lookback window such as 1h, 24h, or 7d. + DefaultValue: 24h + Required: false + Settings: + Target: Sentinel + TenantId: "{{TenantId}}" + SubscriptionId: "{{SubscriptionId}}" + ResourceGroupName: "{{ResourceGroupName}}" + WorkspaceName: "{{WorkspaceName}}" + Template: |- + CommonSecurityLog + | where TimeGenerated > ago({{lookback}}) + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | extend Combined = strcat(tostring(Message), " ", tostring(AdditionalExtensions), " ", tostring(Activity), " ", tostring(DeviceEventClassID), " ", tostring(column_ifexists("FlexString1", "")), " ", tostring(column_ifexists("DeviceCustomString1", ""))) + | where Combined matches regex @"(?i)(?:gid|generator[\s_-]?id)[\s:=]*411" or Combined has_any ("SnortML", "snortml", "is_ml_only") + | project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction, DeviceEventClassID, Message + | order by TimeGenerated desc + | take 50 + + - Name: ListFirepowerSignatureHighEvents + DisplayName: List signature-high events + Description: > + Lists Cisco Firepower classic signature high-priority events that are not SnortML GID 411. + Stronger TP candidates than ML-only; still prefer HITL before contain. + ExamplePrompts: + - Show Firepower high priority signature events + - List classic IDS signature alerts that are not SnortML + - Get signature-high Firepower events for gated contain + Inputs: + - Name: lookback + PlaceholderValue: 24h + Description: Lookback window such as 1h, 24h, or 7d. + DefaultValue: 24h + Required: false + Settings: + Target: Sentinel + TenantId: "{{TenantId}}" + SubscriptionId: "{{SubscriptionId}}" + ResourceGroupName: "{{ResourceGroupName}}" + WorkspaceName: "{{WorkspaceName}}" + Template: |- + let HighPriorityClassifications = dynamic(["A Network Trojan was Detected","A Network Trojan was detected","Successful Administrator Privilege Gain","Successful User Privilege Gain","Attempted Administrator Privilege Gain","Attempted User Privilege Gain","Known malware command and control traffic","Malware Command and Control Activity Detected","Known malicious file or file based exploit","Known client side exploit attempt","Large Scale Information Leak","attempted-admin","attempted-user","trojan-activity"]); + CommonSecurityLog + | where TimeGenerated > ago({{lookback}}) + | where DeviceVendor =~ "Cisco" + | where DeviceProduct has_any ("Firepower", "Secure Firewall", "FTD", "NGFW") + | extend Combined = strcat(tostring(Message), " ", tostring(AdditionalExtensions), " ", tostring(Activity), " ", tostring(DeviceEventClassID), " ", tostring(column_ifexists("FlexString1", "")), " ", tostring(column_ifexists("DeviceCustomString1", "")), " ", tostring(DeviceAction)) + | where not(Combined matches regex @"(?i)(?:gid|generator[\s_-]?id)[\s:=]*411") + | where not(Combined has_any ("SnortML", "snortml", "is_ml_only=true")) + | where Combined has_any (HighPriorityClassifications) or Activity has_any (HighPriorityClassifications) + | project TimeGenerated, DeviceName, SourceIP, DestinationIP, DestinationPort, Activity, DeviceAction, DeviceEventClassID, Message + | order by TimeGenerated desc + | take 50 diff --git a/Plugins/Community Based Plugins/DualSignalContainmentGate/Readme.md b/Plugins/Community Based Plugins/DualSignalContainmentGate/Readme.md new file mode 100644 index 00000000..3a666b69 --- /dev/null +++ b/Plugins/Community Based Plugins/DualSignalContainmentGate/Readme.md @@ -0,0 +1,50 @@ +# Dual-signal containment gate (Security Copilot) + +## Purpose + +Stops Microsoft Security Copilot from treating **SnortML / GID 411 / EVE-high** as a classic IDS **signature true positive** and recommending ungated contain (block IP / isolate). + +| Disposition | Copilot may recommend contain | +|---|---| +| ML-only (GID 411, `is_ml_only`, EVE-high without classic signature) | **No** — escalate / HITL | +| Classic signature high priority | Gated HITL only | +| Signature + ML corroboration | Gated HITL only | +| Unknown | **No** — fail closed | + +Hard rule: ML confidence is not a signature true positive. + +Pairs with: + +- Azure Sentinel dual-signal analytics: https://github.com/Azure/Azure-Sentinel/pull/14925 +- Firepower BlockIP Gate/Prove (auto-contain deny on ML-only): https://github.com/Azure/Azure-Sentinel/pull/14926 +- Splunk SOAR `dual_signal_containment_gate`: https://github.com/phantomcyber/playbooks/pull/239 + +## Skills + +1. **Classify dual-signal disposition** (GPT) — paste incident title/description; plugin returns disposition and whether contain is allowed. +2. **List SnortML ML-only events** (KQL) — `CommonSecurityLog` Cisco Firepower/FTD matching GID 411. +3. **List signature-high events** (KQL) — classic high-priority classifications excluding GID 411. + +## Prerequisites + +- [Security Copilot enabled](https://learn.microsoft.com/en-us/security-copilot/get-started-security-copilot) +- [Permission to upload custom plugins](https://learn.microsoft.com/en-us/security-copilot/manage-plugins?tabs=securitycopilotplugin) +- Microsoft Sentinel workspace with Cisco Firepower / Secure Firewall CEF via AMA (`CommonSecurityLog`) for the KQL skills. The GPT skill works with incident text alone. + +## Upload + +1. Download `DualSignalContainmentGate.yaml`. +2. In Security Copilot, **Sources** → custom plugins → upload the YAML. +3. Enter Tenant ID, Subscription ID, Resource Group, and Workspace name (used by the KQL skills). +4. Enable the plugin. + +## Example prompts + +- Should I contain this Firepower incident +- Classify this SnortML alert for containment +- Show SnortML ML-only Firepower events +- List classic IDS signature alerts that are not SnortML + +## Author + +Ahmed Hassan