Skip to main content
Panther Knowledge Base

How can I control Panther's deduplication period from within my detection code?

Issue

In my detection, there are scenarios where I want the alert deduplication period to be different from my default. Does Panther provide a function like dedup_minutes that I can use?

Resolution

Panther does not currently provide such a function, but you can work around this requirement by being creative with your dedup function.

  1. First, at the top of your detection code, import the time module.
  2. Write your dedup function as you normally would.
  3. Add some logic to calculate when how long the dedup period (in minutes) should be.
  4. Adjust the return value to return the usual dedup string, plus the suffix shown in the example.

Note that using this method, you can make the effective dedup period shorter, but not longer.

Example:

import time

... other detection code here ...

def dedup(event):
    # Determine the dedup string as you normally would:
    dedup_str = ... 
    
    # Specify the dynamic dedup period, using whatever logic is necessary
    dedup_minutes = ...
    
    # Return the dedup_str, plus the special suffix
    return dedup_str + str(time.time() * 60 // dedup_minutes * dedup_minutes)

Explanation

This process works by using the current time inside the dedup string, grouping alerts over specific intervals. If the time passes from one interval to the next, the dedup string will change, triggering a new alert to be raised.

Let's walk through the code more directly:

  • dedup_str = ...
    This line is a placeholder where you would normally determine a string that represents how you want to group the events. It could be something like a description or identifier for the group. Oftentimes, you can simply use the title by invoking title(event).

  • dedup_minutes = ...
    This line is another placeholder where you would decide how long you want the grouping time period to be, measured in minutes. You can set this value based on your needs, like 5 minutes, 10 minutes, etc.

  • return dedup_str + str(time.time() * 60 // (dedup_minutes) * dedup_minutes)
    In this line, the code calculates a special value by combining the dedup_str (the grouping description) with a time-based suffix.

    • time.time()
      This part fetches the current time in seconds since a specific reference point, typically January 1, 1970. Think of it like checking the time on a clock.
    • time.time() * 60
      This step converts the current time from seconds to minutes by multiplying it by 60. This helps ensure that our calculations are consistent with the dedup_minutes value.
    • (time.time() * 60 // dedup_minutes)
      This division and flooring operation finds out how many whole dedup_minutes periods have occurred since the reference time. It's like counting how many times your chosen time interval fits within the current time, considering only complete intervals.
    • * dedup_minutes 
      This step multiplies the result from the previous step by dedup_minutes, converting the count of intervals back to minutes.
    • str(...)
      This converts the calculated time (in minutes) into a string so that it can be combined with the dedup_str.

 

  • Was this article helpful?