06.02 The Risk Formula
Reference for SimpleRisk's six scoring methods — Classic, CVSS, DREAD, OWASP, Custom, and Contributing Risk. Includes each formula, the score normalization to 0–10, the score-to-level mapping, and the SLA thresholds. Use this article when you need exact behavior for a methodology.
Why this is a reference article
This article documents how SimpleRisk computes risk scores. For the operator workflow of picking a methodology, see Default Risk Scoring Method. For configuring a custom matrix, see Custom Risk Scoring. What follows is exact behavior (formulas, ranges, defaults, mapping rules) at the level a reviewer needs to verify a specific score or troubleshoot a per-risk display.
The six scoring methods
The system identifies methods by numeric ID (1–6); the IDs are stable across versions and appear in the risk_scoring.scoring_method column for each risk. The methods:
1: Classic
- Per-risk score formula:
(L × I) + (2 × I) - Maximum-score formula:
(L_max × I_max) + (2 × I_max)
2: CVSS
- Per-risk score formula:
(L × I) + I - Maximum-score formula:
(L_max × I_max) + I_max
3: DREAD
- Per-risk score formula:
L × I - Maximum-score formula:
L_max × I_max
4: OWASP
- Per-risk score formula:
(L × I) + L - Maximum-score formula:
(L_max × I_max) + L_max
5: Custom
- Per-risk score formula: Lookup from custom matrix
- Maximum-score formula: (Defined per matrix; default 10)
6: Contributing Risk
- Per-risk score formula:
(L × I) + (2 × L) - Maximum-score formula:
(L_max × I_max) + (2 × L_max)
Where:
- L = the per-risk likelihood value (an integer drawn from the configured likelihood scale).
- I = the per-risk impact value (an integer drawn from the configured impact scale).
- L_max = the maximum likelihood value (typically 5; configurable via
count_of_likelihoods). - I_max = the maximum impact value (typically 5; configurable via
count_of_impacts).
The formulas are intentionally simple — three are arithmetic operations on impact and likelihood, with different additive terms that produce different weightings. They aren't full implementations of the externally-named frameworks (CVSS isn't the actual CVSS metric vector calculation; DREAD doesn't take five separate inputs; OWASP isn't the OWASP Risk Rating Methodology). Treat the names as labels for the weighting characteristic, not as standards conformance.
Score normalization
Raw formula output ranges from 0 to the methodology's maximum. With the typical L_max = I_max = 5:
Classic
- Raw min: 0
- Raw max: 35
CVSS
- Raw min: 0
- Raw max: 30
DREAD
- Raw min: 0
- Raw max: 25
OWASP
- Raw min: 0
- Raw max: 30
Contributing Risk
- Raw min: 0
- Raw max: 35
Different methods produce different raw maxes, which makes cross-methodology score comparison meaningless without normalization.
The setting need_risk_score_normalization (boolean — default true) controls whether scores are normalized to 0–10 for display. When normalization is on:
displayed_score = (raw_score / max_raw_score_for_methodology) × 10
Every methodology produces 0–10 displayed scores, comparable across methodologies. When normalization is off, the raw score is shown — methodology-specific ranges as above. Most installs leave normalization on.
Score-to-level mapping
The numeric score maps to a qualitative level (Insignificant / Low / Medium / High / Very High) via the risk_levels table. The default thresholds (assuming normalized 0–10 scores):
Very High
- Score range: > 7.5
- Default color: Red
High
- Score range: > 5 to ≤ 7.5
- Default color: Orange
Medium
- Score range: > 2.5 to ≤ 5
- Default color: Yellow
Low
- Score range: > 0 to ≤ 2.5
- Default color: Green
Insignificant
- Score range: ≤ 0
- Default color: Light grey
The thresholds are configurable via the risk_levels table; the management surface is on the Configure → Settings → Risk Formula page (the "Risk Levels" section). Each row in risk_levels has:
id— internal level identifier (1–5 for the defaults).name— internal name (e.g., "VeryHigh", "High").display_name— the user-facing label (e.g., "Very High", "Critical" if your program renames it).value— the score threshold (the upper bound of the level above this one).color— the display hex color or named color.
To rename levels, update display_name. To shift thresholds, update value (which represents the lower bound of this level — anything ≥ value is in this level).
Functions that resolve a score to a level:
get_risk_level_name($score)— returns the level'sdisplay_namefor a numeric score.get_risk_color($score)— returns the level's color for a numeric score.
SLA thresholds
Each level has an associated review-cadence SLA — the number of days within which a risk at that level should be reviewed. The settings:
sla_threshold_very_high— default30days.sla_threshold_high— default60days.sla_threshold_medium— default90days.sla_threshold_low— default180days.sla_threshold_insignificant— default180days.
Range: 1–3650 days. The SLAs feed the next-review-date computation (see Risk Review Cadence).
Inputs to the per-risk score
Every risk record carries the inputs that drive its score. The risk_scoring table:
id— the risk ID (1:1 with therisktable).scoring_method— the methodology ID (1–6).- Per-method input columns (the specific columns differ by methodology):
- Classic / CVSS / DREAD / OWASP / Contributing Risk:
CLASSIC_likelihood,CLASSIC_impact(or methodology-specific column names that follow the same pattern). - Custom (5): lookup against the custom matrix; per-risk impact and likelihood values still stored.
calculated_risk— the most recent computed score for the risk. Updated bycalculate_risk()whenever the risk's inputs change.
When the score is computed
Recompute triggers:
- At submission —
submit_risk()callscalculate_risk()to populate the initialcalculated_risk. - At edit — when impact or likelihood is changed via the UI or the API,
update_risk()recomputes. - At residual-risk change — mitigation effectiveness can update the residual risk score (a separate value tracked alongside the inherent risk).
- At methodology change for the specific risk — if a user edits a risk and changes its
scoring_method, the new method's formula applies. - At bulk recalculation —
recalculate_all_risk_scores()iterates every risk and recomputes against its current methodology and inputs. Triggered by the Recalculate Risk Scores admin action.
The score is not recomputed automatically when:
- The system default
risk_modelsetting changes — only new submissions pick it up; existing risks need a recalculate. - The
risk_levelsthresholds change — the score is unchanged; only its level mapping shifts. - The
count_of_likelihoodsorcount_of_impactschanges — the maximum changes (which affects normalization), but no per-risk recomputation occurs until triggered.
Inherent vs residual risk
SimpleRisk tracks two scores per risk:
- Inherent risk — the score computed from the (impact, likelihood) inputs as submitted, with no mitigation considered. This is the
calculated_riskvalue. - Residual risk — the post-mitigation score, computed from the inherent risk reduced by the mitigation effectiveness. The
residual_riskvalue.
Both are produced from the same methodology; the difference is that residual factors in the mitigation. Reports and dashboards typically display calculated_risk (inherent) by default; programs focused on post-mitigation posture may switch displays to residual_risk.
The next_review_date_uses setting (values: inherent or residual) controls which score drives the review-cadence calculation (see Risk Review Cadence).
Default fallback
For invalid inputs (a risk with scoring_method outside 1–6, or Custom method 5 with no matrix configured), the system returns default_risk_score (default 10). This is a safety net, not a correctness guarantee — risks scoring as the default value should be investigated.
Putting it together: an example
Take a risk with: - Likelihood = 3 (on a 1–5 scale; count_of_likelihoods = 5). - Impact = 4 (on a 1–5 scale; count_of_impacts = 5). - Methodology: Classic (ID 1).
Step 1 — Compute the raw score:
Raw = (L × I) + (2 × I)
= (3 × 4) + (2 × 4)
= 12 + 8
= 20
Step 2 — Compute the methodology max:
Max_Classic = (L_max × I_max) + (2 × I_max)
= (5 × 5) + (2 × 5)
= 25 + 10
= 35
Step 3 — Normalize (need_risk_score_normalization = true):
Displayed = (20 / 35) × 10
= 5.71
Step 4 — Map to level (defaults: > 5 to ≤ 7.5 = High):
Level = High
The risk displays as 5.71 / High in the UI.
For comparison, the same (L=3, I=4) risk scored under DREAD (ID 3):
Raw = L × I = 3 × 4 = 12
Max_DREAD = 5 × 5 = 25
Displayed = (12 / 25) × 10 = 4.80
Level = Medium (> 2.5 to ≤ 5)
Same inputs, different methodology, different level. This is why methodology matters and why mixed-methodology registers are hard to interpret.
Reference
- Implementing files:
simplerisk/includes/functions.php(calculate_risk($impact, $likelihood)~line 6045 — the dispatch and per-method computation;calculate_maximum_risk_score($scoring_method)~line 6141 — the per-method maximum;get_scoring_method_name($method)~line 17225 — method-ID to display-name;get_risk_color($score),get_risk_level_name($score)— score-to-level resolution;recalculate_all_risk_scores());simplerisk/admin/configure_risk_formula.php(configuration UI). - Database tables:
risk_scoring(per-risk inputs andcalculated_risk);risk_levels(level thresholds and display);settings(the configuration values). - Key settings:
risk_model(system default method 1–6);need_risk_score_normalization(boolean — defaulttrue);default_risk_score(fallback for invalid inputs, default10);count_of_likelihoods(likelihood scale max, typically 5);count_of_impacts(impact scale max, typically 5);next_review_date_uses(inherentorresidual— which score drives review cadence);sla_threshold_very_high,sla_threshold_high,sla_threshold_medium,sla_threshold_low,sla_threshold_insignificant(SLA days per level — defaults 30/60/90/180/180). - Built-in methods:
1Classic,2CVSS,3DREAD,4OWASP,5Custom (Customization Extra),6Contributing Risk. Method 5 (Custom) uses a per-cell matrix lookup; the other five use the formulas in the table above.
Related
- Default Risk Scoring Method
- Risk Review Cadence
- Custom Risk Scoring
- Managing Dropdown Values (for impact and likelihood label management)