I'm working with SOAR and I would like to know if it's possible to create an exception through a custom action. The idea is for this action to be triggered once certain conditions are met within a playbook, thereby preventing similar alerts from being generated in the future. In case it is possible, what are the fields that must be added in the code in order to successfully create said exception?
There are a couple of rules generated through EDR that constantly generate the same alerts with the same data. I have a playbook that checks if those alerts are dangerous or not. I want to create a custom action that, in case the playbook confirms that said alert is actually a false alarm, generates an automatic exception in FortiEDR so that it doesn't create another alert in case it sees that there is the same information.
This is the code I have for the moment in the custom action create_exception:
from SiemplifyAction import SiemplifyAction
from SiemplifyUtils import output_handler
from FortiEDRManager import FortiEDRManager
from TIPCommon import extract_configuration_param, extract_action_param
import json
PROVIDER_NAME = "FortiEDR Integration"
SCRIPT_NAME = "CREATE EXCEPTION"
@output_handler
def main():
siemplify = SiemplifyAction()
siemplify.script_name = SCRIPT_NAME
siemplify.LOGGER.info("--------------- Main - Parameter Initialization ---------------")
# Get integration configuration parameters
config = siemplify.get_configuration(PROVIDER_NAME)
api_url = config.get("Instance URL")
username = config.get("Usuario")
password = config.get("Password")
organization = config.get("Organization")
# Initialize the FortiEDR manager
manager = FortiEDRManager(
api_url=api_url,
username=username,
password=password,
organization=organization,
siemplify_logger=siemplify.LOGGER
)
# Get action parameters
event_json_str = extract_action_param(siemplify, param_name="Event JSON", is_mandatory=True)
event_data = json.loads(event_json_str)
# Extract event data
event_id = event_data.get("eventId")
process_name = event_data.get("process")
process_path = event_data.get("processPath")
device_name = event_data.get("collectors", [{}])[0].get("device")
user = event_data.get("loggedUsers", [None])[0]
rules = event_data.get("rules", [])
classification = event_data.get("classification")
certified = event_data.get("certified")
# Try to get the file hash from the event JSON
file_hash = event_data.get("hash")
# If the hash is not present in the event JSON, request it as a parameter
if not file_hash:
hash_param = extract_action_param(siemplify, param_name="Hash", print_value=True)
file_hash = hash_param
# Search for hash details if available
hash_result = None
if file_hash:
siemplify.LOGGER.info(f"Searching for hash: {file_hash}")
try:
hash_result = manager.search_hash(file_hash)
siemplify.LOGGER.info(f"Hash search result: {hash_result}")
except Exception as e:
siemplify.LOGGER.error(f"Failed to search for hash: {e}")
# Build the exception payload
exception_payload = {
"originEventId": event_id,
"userName": username,
"comment": f"Automatically created exception for process {process_name} on device {device_name}",
"selectedDestinations": ["All Destinations"],
"selectedCollectorGroups": ["All Collector Groups"],
"alerts": []
}
for rule in rules:
alert_entry = {
"ruleName": rule,
"process": {
"name": process_name,
"path": process_path,
"usedInException": True,
"useAnyPath": False,
"signed": certified
}
}
# Add the hash if it was found
if file_hash:
alert_entry["process"]["hash"] = file_hash
exception_payload["alerts"].append(alert_entry)
# Send the exception to FortiEDR via the API
try:
response = manager.create_exception(exception_payload)
siemplify.LOGGER.info(f"Exception created successfully: {response}")
siemplify.end("Exception created successfully.", True)
except Exception as e:
siemplify.LOGGER.error(f"Failed to create exception: {e}")
siemplify.end(f"Failed to create exception: {e}", False)
if __name__ == "__main__":
main()
The "Event JSON" is a parameter of code type JSON with this info:
{
"eventId": 92053159,
"process": "MyProcess.exe",
"processPath": "C:\\Program Files (x86)\\Common Files\\Adobe\\ARM\\Execute\\22751\\MyProcess.exe",
"processType": "32 bit",
"firstSeen": "2025-04-29 10:31:27",
"lastSeen": "2025-04-29 10:31:27",
"seen": false,
"handled": false,
"comment": null,
"certified": true,
"archived": false,
"severity": "Medium",
"classification": "Likely Safe",
"destinations": [
"Sensitive Information Access"
],
"rules": [
"Access to Critical System Information"
],
"loggedUsers": [
"PETER\\JGarcia"
],
"organization": "Gaz",
"muted": false,
"muteEndTime": null,
"processOwner": "Local System",
"threatDetails": {
"threatFamily": "Unknown",
"threatType": "Unknown",
"threatName": "Unknown"
},
"collectors": [
{
"lastSeen": "2025-04-29 10:23:18",
"ip": "8.8.8.8",
"collectorGroup": "IGOR",
"macAddresses": [
"Mac_Adress1",
"Mac_Adress2"
],
"id": 75173347,
"device": "LTJGARCIA",
"operatingSystem": "Windows 10 Pro"
}
],
"action": "Block"
}
And I also have the parameter hash with this info: