Skip to main content

Issue with create_exception in FortiEDR

  • May 7, 2025
  • 1 reply
  • 25 views

mikelmi01
Forum|alt.badge.img+5

I'm trying to create an exception in FortiEDR using the create_exception method from the Exceptions class in the fortiedr Python library. I have confirmed that the credentials that I am using are correct and are working perfectly. 

Here is the script I'm using (Exception_generator.py):

 

 

 

import requests import json from fortiedr import auth, Events, Administrator, Policies, Audit, SystemInventory, Forensics, HashSearch, ignore_certificate, Exceptions from urllib.parse import urljoin class FortiEDRManager: def __init__(self, api_url, username, password, organization, siemplify_logger=None): ignore_certificate() self.api_url = api_url.rstrip('/') self.username = username self.password = password self.organization = organization self.logger = siemplify_logger self.session = self._authenticate() def _authenticate(self): session = auth( user=self.username, passw=self.password, host=self.api_url, org=self.organization ) if not session: raise Exception("Authentication failed") return session def create_exception(self, exception_payload): exceptions_client = Events() response = exceptions_client.create_exception( allCollectorGroups=exception_payload.get("allCollectorGroups", False), allDestinations=exception_payload.get("allDestinations", False), allOrganizations=exception_payload.get("allOrganizations", False), allUsers=exception_payload.get("allUsers", False), collectorGroups=exception_payload.get("collectorGroups", []), comment=exception_payload.get("comment", ""), destinations=exception_payload.get("destinations", []), eventId=exception_payload.get("eventId"), exceptionId=exception_payload.get("exceptionId"), useAnyPath=exception_payload.get("useAnyPath"), useCommandLine=None, useInException=exception_payload.get("useInException"), wildcardFiles=exception_payload.get("wildcardFiles"), wildcardPaths=exception_payload.get("wildcardPaths"), forceCreate=exception_payload.get("forceCreate", False), isHidden=exception_payload.get("isHidden", False), organization=self.organization, users=exception_payload.get("users", []) ) return response # ====================== REAL CONFIGURATION ====================== API_URL = "https://<YOUR_INSTANCE_URL>" # 🔒 Replace with your real URL USERNAME = "<YOUR_USERNAME>" # 🔒 Replace with your actual username PASSWORD = "<YOUR_PASSWORD>" # 🔒 Replace with your actual password ORGANIZATION = "<YOUR_ORGANIZATION>" # 🔒 Exact organization name in FortiEDR # ================================================================ # Real event provided event_data = { "eventId": 92053159, "process": "MyProcess.exe", "processPath": "C:\\\\Program Files (x86)\\\\Common Files\\\\Adobe\\\\ARM\\\\Execute\\\\22751\\\\MyProcess.exe", "certified": True, "rules": ["Access to Critical System Information"], "loggedUsers": ["PETER\\\\JGarcia"], "collectors": [{"device": "LTJGARCIA", "collectorGroup": "IGOR"}], "classification": "Likely Safe", "hash": "abcdef1234567890", "destinations": ["Sensitive Information Access"] } # Extract key data event_id = event_data["eventId"] process_name = event_data["process"] process_path = event_data["processPath"] device_name = event_data["collectors"][0]["device"] collector_group = event_data["collectors"][0]["collectorGroup"] user = event_data["loggedUsers"][0] rules = event_data["rules"] certified = event_data["certified"] file_hash = event_data.get("hash") destinations = event_data.get("destinations", []) # Initialize FortiEDR Manager manager = FortiEDRManager( api_url=API_URL, username=USERNAME, password=PASSWORD, organization=ORGANIZATION ) # Build exception payload compatible with create_exception exception_payload = { "allCollectorGroups": True, "allDestinations": False, "allOrganizations": False, "allUsers": False, "collectorGroups": ["IGOR"], "comment": f"Automatically created exception for {process_name} on {device_name}", "destinations": destinations, "eventId": event_id, "exceptionId": None, "useAnyPath": None, "useInException": None, "wildcardFiles": None, "wildcardPaths": None, "forceCreate": True, "isHidden": False, "organization": ORGANIZATION, "users": [user] } # Submit the exception try: print("📦 exception_payload:") for k, v in exception_payload.items(): print(f" {k}: {v} (type: {type(v).__name__})") print("\\n⏳ Attempting create_exception...") response = manager.create_exception(exception_payload) print("✅ create_exception executed successfully.") print(json.dumps(response, indent=4)) except Exception as e1: import traceback print("❌ Error in create_exception:") traceback.print_exc() print("Error type:", type(e1)) print("Error details:", e1)

 

 

 

 

When I try to send this using:

 

 

response = manager.create_exception(exception_payload)

 

 

The call returns:

 

 

{ "status": false, "data": { "status_code": 400, "error_message": "Total Exception count exceeded max count of 30,000" } }

 

 

 

 

This doesn’t make sense — I have access to the FortiEDR console and I can confirm I don’t even have 600 exceptions, let alone 30,000. So I suspect the error might be generic or misleading.

I also tried sending values for useAnyPath, useInException, wildcardFiles, and wildcardPaths as dicts or lists, as shown here:

 

 

import requests import json from fortiedr import auth, Events, Administrator, Policies, Audit, SystemInventory, Forensics, HashSearch, ignore_certificate, Exceptions from urllib.parse import urljoin class FortiEDRManager: def __init__(self, api_url, username, password, organization, siemplify_logger=None): ignore_certificate() self.api_url = api_url.rstrip('/') self.username = username self.password = password self.organization = organization self.logger = siemplify_logger self.session = self._authenticate() def _authenticate(self): session = auth( user=self.username, passw=self.password, host=self.api_url, org=self.organization ) if not session: raise Exception("Authentication failed") return session def create_exception(self, exception_payload): exceptions_client = Events() response = exceptions_client.create_exception( allCollectorGroups=exception_payload.get("allCollectorGroups", False), allDestinations=exception_payload.get("allDestinations", False), allOrganizations=exception_payload.get("allOrganizations", False), allUsers=exception_payload.get("allUsers", False), collectorGroups=exception_payload.get("collectorGroups", []), comment=exception_payload.get("comment", ""), destinations=exception_payload.get("destinations", []), eventId=exception_payload.get("eventId"), exceptionId=exception_payload.get("exceptionId"), useAnyPath=exception_payload.get("useAnyPath"), useCommandLine=None, useInException=exception_payload.get("useInException"), wildcardFiles=exception_payload.get("wildcardFiles"), wildcardPaths=exception_payload.get("wildcardPaths"), forceCreate=exception_payload.get("forceCreate", False), isHidden=exception_payload.get("isHidden", False), organization=self.organization, users=exception_payload.get("users", []) ) return response # ====================== REAL CONFIGURATION ====================== API_URL = "https://<YOUR_INSTANCE_URL>" # 🔒 Replace with your real URL USERNAME = "<YOUR_USERNAME>" # 🔒 Replace with your actual username PASSWORD = "<YOUR_PASSWORD>" # 🔒 Replace with your actual password ORGANIZATION = "<YOUR_ORGANIZATION>" # 🔒 Exact organization name in FortiEDR # ================================================================ # Real event provided event_data = { "eventId": 92053159, "process": "MyProcess.exe", "processPath": "C:\\\\Program Files (x86)\\\\Common Files\\\\Adobe\\\\ARM\\\\Execute\\\\22751\\\\MyProcess.exe", "certified": True, "rules": ["Access to Critical System Information"], "loggedUsers": ["PETER\\\\JGarcia"], "collectors": [{"device": "LTJGARCIA", "collectorGroup": "IGOR"}], "classification": "Likely Safe", "hash": "abcdef1234567890", "destinations": ["Sensitive Information Access"] } # Extract key data event_id = event_data["eventId"] process_name = event_data["process"] process_path = event_data["processPath"] device_name = event_data["collectors"][0]["device"] collector_group = event_data["collectors"][0]["collectorGroup"] user = event_data["loggedUsers"][0] rules = event_data["rules"] certified = event_data["certified"] file_hash = event_data.get("hash") destinations = event_data.get("destinations", []) # Initialize FortiEDR Manager manager = FortiEDRManager( api_url=API_URL, username=USERNAME, password=PASSWORD, organization=ORGANIZATION ) # Build exception payload compatible with create_exception exception_payload = { "allCollectorGroups": True, "allDestinations": False, "allOrganizations": False, "allUsers": False, "collectorGroups": ["IGOR"], "comment": f"Automatically created exception for {process_name} on {device_name}", "destinations": destinations, "eventId": event_id, "exceptionId": None, "useAnyPath": { process_name: { rule: False for rule in rules } }, "useInException": { process_name: { rule: True for rule in rules } }, "wildcardFiles": [process_name], "wildcardPaths": [process_path.rsplit("\\\\", 1)[0] + "\\\\"], "forceCreate": True, "isHidden": False, "organization": ORGANIZATION, "users": [user] } # Submit the exception try: print("📦 exception_payload:") for k, v in exception_payload.items(): print(f" {k}: {v} (type: {type(v).__name__})") print("\\n⏳ Attempting create_exception...") response = manager.create_exception(exception_payload) print("✅ create_exception executed successfully.") print(json.dumps(response, indent=4)) except Exception as e1: import traceback print("❌ Error in create_exception:") traceback.print_exc() print("Error type:", type(e1)) print("Error details:", e1)

 

 

But that resulted in a KeyError: 'object' inside the validate_params function of the SDK, which seems to treat those parameters strangely.

Has anyone encountered this before? Is there a special format for these fields that avoids the 'object' key error, or is there something wrong on the FortiEDR backend?

Any help would be much appreciated!

1 reply

kentphelps
Staff
Forum|alt.badge.img+12
  • Staff
  • May 12, 2025

Have you contacted Fortinet at all on the issues you are seeing here.  For something this involved you may need a partner (https://cloud.google.com/find-a-partner/) or work with your sales team to engage Professional Services for SecOps.