Skip to content

EPSS Quantile Binning as an SSVC Amplifier

Obtain SSVC Data

If you are using the SSVC Deployer Decision Model, you might already know that the CISA Vulnrichment program provides some SSVC data that is made available via the CVE Services API.

Obtain EPSS Data

You can get EPSS data from the EPSS website or use their API to fetch scores programmatically.

In another how-to, we showed how to use the Exploit Prediction Scoring System (EPSS) probability scores as one of a few different inputs to inform the SSVC Exploitation decision point. This approach can be a useful approach to refine or augment the input to an existing SSVC decision model.

What's in this How-To?

In this how-to, we'll explore a different approach that uses EPSS percentiles as an amplifier to adjust the output of an existing SSVC decision model.

Starting Out with the SSVC Deployer Decision Model

Let's start with the assumption that you're already using the SSVC Deployer Decision Model and have a basic understanding of SSVC. But then after reading Probability, Percentiles, and Binning - How to understand and interpret EPSS Scores, you realize that you would like to use EPSS percentiles to amplify the output of your existing decision model.

Why use percentiles instead of raw probabilities?

Percentiles provide a relative ranking of vulnerabilities based on their EPSS scores. This can be particularly useful when you want to prioritize vulnerabilities in the context of the entire vulnerability landscape. By using percentiles, you can identify which vulnerabilities are more likely to be exploited compared to others. The EPSS SIG blog discusses some of the tradeoffs involved in using percentiles versus raw probabilities.

That said, we are using percentiles for this how-to simply because we already we showed how to use probabilities in another how-to. Either approach can be valid depending on your specific needs and context.

One straightforward way to use EPSS is to create bins based on the EPSS score and use these bins as amplifiers in your SSVC decision-making process.

See Also

See the sidebar in this how-to for a discussion of the tradeoffs involved in binning.

Binning Percentiles

SSVC provides several basic decision points that bin percentiles into discrete quantiles. Expand the example below to see the currently available options.

Exploring Decision Points for Binning Percentiles

Median Split (basic:MEDIAN:1.0.0)

A median split divides a distribution into two equal parts, with 50% of the values falling below the median and 50% above it.

Value Definition
Below Median (B) Quantile < 0.50. The lower half of the range of possible values.
Above Median (A) 0.50 <= Quantile <= 1.0. The upper half of the range of possible values.
Median Split (basic:MEDIAN:1.0.0) JSON Example
{
  "namespace": "basic",
  "key": "MEDIAN",
  "version": "1.0.0",
  "name": "Median Split",
  "definition": "A median split divides a distribution into two equal parts, with 50% of the values falling below the median and 50% above it.",
  "schemaVersion": "2.0.0",
  "values": [
    {
      "key": "B",
      "name": "Below Median",
      "definition": "Quantile < 0.50. The lower half of the range of possible values."
    },
    {
      "key": "A",
      "name": "Above Median",
      "definition": "0.50 <= Quantile <= 1.0. The upper half of the range of possible values."
    }
  ]
}

Quartiles (basic:QUARTILES:1.0.0)

A quartile is one of four equal groups that a population can be divided into according to the distribution of values of a particular variable.

Value Definition
First Quartile (Q1) Quantile < 0.25. The lowest 25% of the range of possible values.
Second Quartile (Q2) 0.25 <= Quantile < 0.50. The second lowest 25% of the range of possible values.
Third Quartile (Q3) 0.50 <= Quantile < 0.75. The second highest 25% of the range of possible values.
Fourth Quartile (Q4) 0.75 <= Quantile <= 1.0. The highest 25% of the range of possible values.
Quartiles (basic:QUARTILES:1.0.0) JSON Example
{
  "namespace": "basic",
  "key": "QUARTILES",
  "version": "1.0.0",
  "name": "Quartiles",
  "definition": "A quartile is one of four equal groups that a population can be divided into according to the distribution of values of a particular variable.",
  "schemaVersion": "2.0.0",
  "values": [
    {
      "key": "Q1",
      "name": "First Quartile",
      "definition": "Quantile < 0.25. The lowest 25% of the range of possible values."
    },
    {
      "key": "Q2",
      "name": "Second Quartile",
      "definition": "0.25 <= Quantile < 0.50. The second lowest 25% of the range of possible values."
    },
    {
      "key": "Q3",
      "name": "Third Quartile",
      "definition": "0.50 <= Quantile < 0.75. The second highest 25% of the range of possible values."
    },
    {
      "key": "Q4",
      "name": "Fourth Quartile",
      "definition": "0.75 <= Quantile <= 1.0. The highest 25% of the range of possible values."
    }
  ]
}

Quintiles (basic:QUINTILES:1.0.0)

A quintile is one of five equal groups that a population can be divided into according to the distribution of values of a particular variable.

Value Definition
First Quintile (Q1) Quantile < 0.20. The lowest 20% of the range of possible values.
Second Quintile (Q2) 0.20 <= Quantile < 0.40. The second lowest 20% of the range of possible values.
Third Quintile (Q3) 0.40 <= Quantile < 0.60. The middle 20% of the range of possible values.
Fourth Quintile (Q4) 0.60 <= Quantile < 0.80. The second highest 20% of the range of possible values.
Fifth Quintile (Q5) 0.80 <= Quantile <= 1.0. The highest 20% of the range of possible values.
Quintiles (basic:QUINTILES:1.0.0) JSON Example
{
  "namespace": "basic",
  "key": "QUINTILES",
  "version": "1.0.0",
  "name": "Quintiles",
  "definition": "A quintile is one of five equal groups that a population can be divided into according to the distribution of values of a particular variable.",
  "schemaVersion": "2.0.0",
  "values": [
    {
      "key": "Q1",
      "name": "First Quintile",
      "definition": "Quantile < 0.20. The lowest 20% of the range of possible values."
    },
    {
      "key": "Q2",
      "name": "Second Quintile",
      "definition": "0.20 <= Quantile < 0.40. The second lowest 20% of the range of possible values."
    },
    {
      "key": "Q3",
      "name": "Third Quintile",
      "definition": "0.40 <= Quantile < 0.60. The middle 20% of the range of possible values."
    },
    {
      "key": "Q4",
      "name": "Fourth Quintile",
      "definition": "0.60 <= Quantile < 0.80. The second highest 20% of the range of possible values."
    },
    {
      "key": "Q5",
      "name": "Fifth Quintile",
      "definition": "0.80 <= Quantile <= 1.0. The highest 20% of the range of possible values."
    }
  ]
}

Now, your primary concern is to ensure that you are addressing the vulnerabilities that are most likely to be exploited. In conversations with your organization's risk owners, you determine that they'd like to apply a policy that is consistent with the following:

  • If the EPSS percentile is significantly higher than the median, the vulnerability should be prioritized two levels higher than the default SSVC recommendation.
  • If the EPSS percentile is above the median but not significantly so, the vulnerability should be prioritized one level higher than the default SSVC recommendation.
  • If the EPSS percentile is significantly lower than the median, the vulnerability should be deprioritized lower than the default SSVC recommendation.

You can achieve this with the quartiles decision point:

Quartiles (basic:QUARTILES:1.0.0)

A quartile is one of four equal groups that a population can be divided into according to the distribution of values of a particular variable.

Value Definition
First Quartile (Q1) Quantile < 0.25. The lowest 25% of the range of possible values.
Second Quartile (Q2) 0.25 <= Quantile < 0.50. The second lowest 25% of the range of possible values.
Third Quartile (Q3) 0.50 <= Quantile < 0.75. The second highest 25% of the range of possible values.
Fourth Quartile (Q4) 0.75 <= Quantile <= 1.0. The highest 25% of the range of possible values.
Quartiles (basic:QUARTILES:1.0.0) JSON Example
{
  "namespace": "basic",
  "key": "QUARTILES",
  "version": "1.0.0",
  "name": "Quartiles",
  "definition": "A quartile is one of four equal groups that a population can be divided into according to the distribution of values of a particular variable.",
  "schemaVersion": "2.0.0",
  "values": [
    {
      "key": "Q1",
      "name": "First Quartile",
      "definition": "Quantile < 0.25. The lowest 25% of the range of possible values."
    },
    {
      "key": "Q2",
      "name": "Second Quartile",
      "definition": "0.25 <= Quantile < 0.50. The second lowest 25% of the range of possible values."
    },
    {
      "key": "Q3",
      "name": "Third Quartile",
      "definition": "0.50 <= Quantile < 0.75. The second highest 25% of the range of possible values."
    },
    {
      "key": "Q4",
      "name": "Fourth Quartile",
      "definition": "0.75 <= Quantile <= 1.0. The highest 25% of the range of possible values."
    }
  ]
}

We're not saying this is a good rule set!

The rules given here are just an example to illustrate how you might use EPSS percentiles as an amplifier in your decision-making process. We are not suggesting that this is a good idea or that you should follow these rules. In fact, these rules are rather aggressive and could result in fully half of all vulnerabilities being prioritized higher than they would without the EPSS data. Your organization's risk owners should determine the appropriate policy for your context, but we would recommend something considerably less aggressive than this example.

You decide to apply the following rules:

EPSS Quartile Amplification Factor Deployer Outcome Change
Q1 -1 D → D, S → D, O → S, I → O
Q2 0 D → D, S → S, O → O, I → I
Q3 +1 D → S, S → O, O → I, I → I
Q4 +2 D → O, S → I, O → I, I → I

Building the Decision Table

Given the rules outlined above, you build a new Decision Table that takes the default outcome from the SSVC Deployer Decision Model and applies the EPSS quartile information to amplify it. The resulting decision table looks like this:

Row Quartiles v1.0.0 (basic) Defer, Scheduled, Out-of-Cycle, Immediate v1.0.0 example:DSOI:1.0.0
0 first quartile defer d
1 second quartile defer d
2 first quartile scheduled d
3 third quartile defer s
4 second quartile scheduled s
5 first quartile out-of-cycle s
6 fourth quartile defer o
7 third quartile scheduled o
8 second quartile out-of-cycle o
9 first quartile immediate o
10 fourth quartile scheduled i
11 third quartile out-of-cycle i
12 second quartile immediate i
13 fourth quartile out-of-cycle i
14 third quartile immediate i
15 fourth quartile immediate i

A diagram of the decision model is shown below.

Example Decision Table Diagram
---
title: Example EPSS Quartile Decision Table Decision Table (example:DT_EPSS_QRT:0.0.1)
---
graph LR
subgraph inputs[Inputs]
n1(( ))
subgraph s1["basic:QUARTILES:1.0.0"]
Q1_L0([Q1])
Q2_L0([Q2])
Q3_L0([Q3])
Q4_L0([Q4])
end
subgraph s2["ssvc:DSOI:1.0.0"]
Q1_D_L1([D])
Q2_D_L1([D])
Q1_S_L1([S])
Q3_D_L1([D])
Q2_S_L1([S])
Q1_O_L1([O])
Q4_D_L1([D])
Q3_S_L1([S])
Q2_O_L1([O])
Q1_I_L1([I])
Q4_S_L1([S])
Q3_O_L1([O])
Q2_I_L1([I])
Q4_O_L1([O])
Q3_I_L1([I])
Q4_I_L1([I])
end
end
subgraph outputs[Outcome]
subgraph s3["example:DSOI:1.0.0"]
Q1_D_D_L2([D])
Q2_D_D_L2([D])
Q1_S_D_L2([D])
Q3_D_S_L2([S])
Q2_S_S_L2([S])
Q1_O_S_L2([S])
Q4_D_O_L2([O])
Q3_S_O_L2([O])
Q2_O_O_L2([O])
Q1_I_O_L2([O])
Q4_S_I_L2([I])
Q3_O_I_L2([I])
Q2_I_I_L2([I])
Q4_O_I_L2([I])
Q3_I_I_L2([I])
Q4_I_I_L2([I])
end
end
n1 --- Q1_L0
n1 --- Q2_L0
n1 --- Q3_L0
n1 --- Q4_L0
Q1_L0 --- Q1_D_L1
Q1_D_L1 --- Q1_D_D_L2
Q2_L0 --- Q2_D_L1
Q2_D_L1 --- Q2_D_D_L2
Q1_L0 --- Q1_S_L1
Q1_S_L1 --- Q1_S_D_L2
Q3_L0 --- Q3_D_L1
Q3_D_L1 --- Q3_D_S_L2
Q2_L0 --- Q2_S_L1
Q2_S_L1 --- Q2_S_S_L2
Q1_L0 --- Q1_O_L1
Q1_O_L1 --- Q1_O_S_L2
Q4_L0 --- Q4_D_L1
Q4_D_L1 --- Q4_D_O_L2
Q3_L0 --- Q3_S_L1
Q3_S_L1 --- Q3_S_O_L2
Q2_L0 --- Q2_O_L1
Q2_O_L1 --- Q2_O_O_L2
Q1_L0 --- Q1_I_L1
Q1_I_L1 --- Q1_I_O_L2
Q4_L0 --- Q4_S_L1
Q4_S_L1 --- Q4_S_I_L2
Q3_L0 --- Q3_O_L1
Q3_O_L1 --- Q3_O_I_L2
Q2_L0 --- Q2_I_L1
Q2_I_L1 --- Q2_I_I_L2
Q4_L0 --- Q4_O_L1
Q4_O_L1 --- Q4_O_I_L2
Q3_L0 --- Q3_I_L1
Q3_I_L1 --- Q3_I_I_L2
Q4_L0 --- Q4_I_L1
Q4_I_L1 --- Q4_I_I_L2

And here is a JSON object representation of the decision table for programmatic use:

Example Decision Table JSON

The JSON representation of the decision table is shown below.

{
  "namespace": "example",
  "key": "DT_EPSS_QRT",
  "version": "0.0.1",
  "name": "Example EPSS Quartile Decision Table",
  "definition": "An example decision table using EPSS quartiles to adjust the SSVC Deployer Table outcome.",
  "schemaVersion": "2.0.0",
  "registered": false,
  "decision_points": {
    "basic:QUARTILES:1.0.0": {
      "namespace": "basic",
      "key": "QUARTILES",
      "version": "1.0.0",
      "name": "Quartiles",
      "definition": "A quartile is one of four equal groups that a population can be divided into according to the distribution of values of a particular variable.",
      "schemaVersion": "2.0.0",
      "values": [
        {
          "key": "Q1",
          "name": "First Quartile",
          "definition": "Quantile < 0.25. The lowest 25% of the range of possible values."
        },
        {
          "key": "Q2",
          "name": "Second Quartile",
          "definition": "0.25 <= Quantile < 0.50. The second lowest 25% of the range of possible values."
        },
        {
          "key": "Q3",
          "name": "Third Quartile",
          "definition": "0.50 <= Quantile < 0.75. The second highest 25% of the range of possible values."
        },
        {
          "key": "Q4",
          "name": "Fourth Quartile",
          "definition": "0.75 <= Quantile <= 1.0. The highest 25% of the range of possible values."
        }
      ]
    },
    "ssvc:DSOI:1.0.0": {
      "namespace": "ssvc",
      "key": "DSOI",
      "version": "1.0.0",
      "name": "Defer, Scheduled, Out-of-Cycle, Immediate",
      "definition": "The original SSVC outcome group.",
      "schemaVersion": "2.0.0",
      "values": [
        {
          "key": "D",
          "name": "Defer",
          "definition": "Defer"
        },
        {
          "key": "S",
          "name": "Scheduled",
          "definition": "Scheduled"
        },
        {
          "key": "O",
          "name": "Out-of-Cycle",
          "definition": "Out-of-Cycle"
        },
        {
          "key": "I",
          "name": "Immediate",
          "definition": "Immediate"
        }
      ]
    },
    "example:DSOI:1.0.0": {
      "namespace": "example",
      "key": "DSOI",
      "version": "1.0.0",
      "name": "Defer, Scheduled, Out-of-Cycle, Immediate",
      "definition": "The original SSVC outcome group.",
      "schemaVersion": "2.0.0",
      "values": [
        {
          "key": "D",
          "name": "Defer",
          "definition": "Defer"
        },
        {
          "key": "S",
          "name": "Scheduled",
          "definition": "Scheduled"
        },
        {
          "key": "O",
          "name": "Out-of-Cycle",
          "definition": "Out-of-Cycle"
        },
        {
          "key": "I",
          "name": "Immediate",
          "definition": "Immediate"
        }
      ]
    }
  },
  "outcome": "example:DSOI:1.0.0",
  "mapping": [
    {
      "basic:QUARTILES:1.0.0": "Q1",
      "ssvc:DSOI:1.0.0": "D",
      "example:DSOI:1.0.0": "D"
    },
    {
      "basic:QUARTILES:1.0.0": "Q2",
      "ssvc:DSOI:1.0.0": "D",
      "example:DSOI:1.0.0": "D"
    },
    {
      "basic:QUARTILES:1.0.0": "Q1",
      "ssvc:DSOI:1.0.0": "S",
      "example:DSOI:1.0.0": "D"
    },
    {
      "basic:QUARTILES:1.0.0": "Q3",
      "ssvc:DSOI:1.0.0": "D",
      "example:DSOI:1.0.0": "S"
    },
    {
      "basic:QUARTILES:1.0.0": "Q2",
      "ssvc:DSOI:1.0.0": "S",
      "example:DSOI:1.0.0": "S"
    },
    {
      "basic:QUARTILES:1.0.0": "Q1",
      "ssvc:DSOI:1.0.0": "O",
      "example:DSOI:1.0.0": "S"
    },
    {
      "basic:QUARTILES:1.0.0": "Q4",
      "ssvc:DSOI:1.0.0": "D",
      "example:DSOI:1.0.0": "O"
    },
    {
      "basic:QUARTILES:1.0.0": "Q3",
      "ssvc:DSOI:1.0.0": "S",
      "example:DSOI:1.0.0": "O"
    },
    {
      "basic:QUARTILES:1.0.0": "Q2",
      "ssvc:DSOI:1.0.0": "O",
      "example:DSOI:1.0.0": "O"
    },
    {
      "basic:QUARTILES:1.0.0": "Q1",
      "ssvc:DSOI:1.0.0": "I",
      "example:DSOI:1.0.0": "O"
    },
    {
      "basic:QUARTILES:1.0.0": "Q4",
      "ssvc:DSOI:1.0.0": "S",
      "example:DSOI:1.0.0": "I"
    },
    {
      "basic:QUARTILES:1.0.0": "Q3",
      "ssvc:DSOI:1.0.0": "O",
      "example:DSOI:1.0.0": "I"
    },
    {
      "basic:QUARTILES:1.0.0": "Q2",
      "ssvc:DSOI:1.0.0": "I",
      "example:DSOI:1.0.0": "I"
    },
    {
      "basic:QUARTILES:1.0.0": "Q4",
      "ssvc:DSOI:1.0.0": "O",
      "example:DSOI:1.0.0": "I"
    },
    {
      "basic:QUARTILES:1.0.0": "Q3",
      "ssvc:DSOI:1.0.0": "I",
      "example:DSOI:1.0.0": "I"
    },
    {
      "basic:QUARTILES:1.0.0": "Q4",
      "ssvc:DSOI:1.0.0": "I",
      "example:DSOI:1.0.0": "I"
    }
  ]
}

Now you can use this decision table in your SSVC implementation to adjust the prioritization of vulnerabilities based on their EPSS percentiles.

How can I sort work items within a given SSVC outcome category?

While we don't usually recommend sorting within a given SSVC outcome category, we recognize that some organizations may want to do this.

If you want to sort vulnerabilities within a given SSVC outcome (e.g., all vulnerabilities that are classified as "Immediate"), you can use the raw EPSS probability score as a secondary sorting key. This way, even if multiple vulnerabilities fall into the same SSVC category, you can still prioritize them based on their predicted likelihood of exploitation.

Conclusion

In this how-to, we've demonstrated how to use EPSS percentiles as an amplifier to adjust the output of an existing SSVC decision model. While the example provided is considerably more aggressive than we would recommend in practice, it illustrates one way to incorporate EPSS data into an established SSVC-based vulnerability management strategy. By incorporating statistical insights from EPSS, you can prioritize vulnerabilities more effectively based on their likelihood of exploitation.