Skip to main content

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!

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.


Reply