Published on: May 13, 2026
9 min read
Default CVSS scores don't reflect your actual risk. Use GitLab severity override policies to automate adjustments based on CVE, CWE, file path, and directory.

A typical enterprise vulnerability report surfaces hundreds of findings per scan cycle, all ranked by the Common Vulnerability Scoring System (CVSS). The problem: CVSS describes the theoretical characteristics of a Common Vulnerabilities and Exposures (CVE), not whether it matters in your environment. A Critical vulnerability in an internal-only utility library is not the same risk as a Medium vulnerability in a public-facing authentication service, but they're treated identically until someone manually triages each one. That triage work doesn't scale.
GitLab vulnerability management policies can now automatically override those default CVSS severity levels based on conditions you define, so your vulnerability report reflects your actual risk model instead of a generic one.
A severity override policy is a type of vulnerability management policy that adjusts vulnerability severity levels automatically on every default-branch pipeline. You define rules with match criteria (CVE ID, CWE ID, file path, or directory) and an override action. When a vulnerability matches, GitLab's Security Policy Bot updates its severity immediately.
Three override operations are available:
Manual overrides by authorized users always take precedence over policy overrides. Every automated change is logged in the vulnerability's history and audit events, so you maintain a complete record of what changed and why.
Each example below includes a policy configuration you can copy, customize, and apply immediately.
Security scanners don't know which projects are internal tools, test utilities, or production services. They rate every CVE the same regardless of deployment context. For teams running internal admin dashboards, developer tooling, or batch processing jobs that never face external traffic, a Critical-rated dependency vulnerability often doesn't warrant the same response as one in a customer-facing API.
This policy decreases the severity of specific CVEs found in internal service directories:
vulnerability_management_policy:
- name: "Downgrade CVEs in internal services"
description: "Internal-only services have lower exposure risk"
enabled: true
rules:
- type: detected
criteria:
- type: identifier
identifier_type: cve
values:
- "CVE-2023-44487"
- "CVE-2024-29041"
- type: directory
value: "internal/**/*"
actions:
- type: severity_override
severity_override_operation: decrease
Replace the CVE values with the identifiers your team has assessed as lower risk for internal deployments. The decrease operation drops severity by one level (Critical becomes High, High becomes Medium), preserving relative priority without overreacting to context-inappropriate scores.
Some vulnerability classes warrant a stronger response when found in production source code. Cross-site scripting (CWE-79) and SQL injection (CWE-89) are consistently among the most exploited vulnerability types according to OWASP and CISA's Known Exploited Vulnerabilities (KEV) catalog. If your scanner reports these as Medium or High in your src/ directory, your triage process needs to treat them as Critical.
This policy sets the severity to Critical for XSS and SQLi findings in production code:
vulnerability_management_policy:
- name: "Upgrade XSS and SQLi in production code"
description: "Injection vulnerabilities in src/ are always Critical"
enabled: true
rules:
- type: detected
criteria:
- type: identifier
identifier_type: cwe
values:
- "CWE-79"
- "CWE-89"
- type: directory
value: "src/**/*"
actions:
- type: severity_override
severity_override_operation: set
severity_override_value: critical
Pair this with a merge request approval policy that requires security team approval for Critical findings. Together, the severity override ensures the right findings are flagged and prioritized in the vulnerability report, and the approval policy ensures newly detected findings cannot reach production without review.
Different scanners sometimes assign different severity levels to the same CVE. Your static application security testing (SAST) scanner might rate a finding as High, while dependency scanning calls it Medium. These inconsistencies create confusion during triage and make it harder to set consistent approval thresholds across scan types.
Use a severity override policy to enforce a consistent baseline. If your security team has assessed a specific CVE family and determined it should always be High regardless of which scanner found it, set it explicitly:
vulnerability_management_policy:
- name: "Normalize log4j severity to High"
description: "Consistent severity for log4j CVEs across all scanners"
enabled: true
rules:
- type: detected
criteria:
- type: identifier
identifier_type: cve
values:
- "CVE-2021-44228"
- "CVE-2021-45046"
- "CVE-2021-45105"
actions:
- type: severity_override
severity_override_operation: set
severity_override_value: high
This is especially useful for organizations running multiple scan types (SAST, dependency scanning, container scanning) where the same underlying vulnerability appears with different ratings depending on the detection method.
CVSS scores are static. They don't change when a vulnerability starts being actively exploited, and they don't account for real-world exploitation probability. FIRST's Exploit Prediction Scoring System (EPSS) and CISA's KEV catalog provide the missing signal.
When your threat intelligence tells you a Medium-severity CVE is now actively exploited (KEV) or has a high exploitation probability (EPSS above 0.5), use a severity override to upgrade it:
vulnerability_management_policy:
- name: "Upgrade actively exploited CVEs"
description: "CVEs in CISA KEV catalog should be treated as Critical"
enabled: true
rules:
- type: detected
criteria:
- type: identifier
identifier_type: cve
values:
- "CVE-2024-3094"
- "CVE-2023-4966"
- "CVE-2023-22515"
actions:
- type: severity_override
severity_override_operation: set
severity_override_value: critical
Maintain a living list of KEV entries relevant to your stack and update the policy as new CVEs are added to the catalog. This creates a feedback loop between threat intelligence and developer-facing severity, without requiring analysts to manually adjust each finding.
Individual project policies don't scale when your organization has hundreds or thousands of projects. Severity override policies can be applied at the group level, affecting every project in the group. Combined with policy_scope, you can target policies to projects matching a specific compliance framework label.
For example, an organization with a "PCI-DSS" compliance framework can enforce stricter severity treatment for injection vulnerabilities across all PCI-scoped projects, while applying a lighter policy to internal tooling groups:
vulnerability_management_policy:
- name: "PCI projects: upgrade injection severity"
description: "All injection vulnerabilities are Critical in PCI scope"
enabled: true
policy_scope:
compliance_frameworks:
- id: 12345
rules:
- type: detected
criteria:
- type: identifier
identifier_type: cwe
values:
- "CWE-79"
- "CWE-89"
- "CWE-78"
- "CWE-94"
actions:
- type: severity_override
severity_override_operation: set
severity_override_value: critical
This pattern means the security team defines the risk model once and it applies consistently everywhere. No per-project configuration. No reliance on individual teams remembering to set things up correctly.
Follow these steps to create vulnerability management policies:
| Parameter | Details |
|---|---|
| Criteria types | file_path, directory, identifier (with optional identifier_type: cve, cwe, owasp) |
| Override operations | set (to specific level), increase (one level up), decrease (one level down) |
| Severity levels | info, low, medium, high, critical |
| Values | Single value or values array (up to 1,000 items, OR logic). Wildcards supported (e.g., CVE-2023-*) |
| Criteria logic | Multiple criteria within a rule = AND (must match all). Multiple rules within a policy = OR (match any) |
| Limits | 3 criteria per rule, 5 rules per policy, 5 policies per security policy project |
| Scope | Project-level or group-level. policy_scope for compliance framework targeting |
| Manual override precedence | Manual overrides by authorized users always take precedence |
What's the difference between auto-dismiss and severity override?
Auto-dismiss removes findings from your active triage queue. Severity override keeps them visible but adjusts their priority level, so they're still tracked and reviewed at the appropriate urgency.
Can I combine severity overrides with other policy types?
Yes. Severity overrides apply to findings on the default branch, affecting vulnerabilities appearing in your GitLab vulnerability reporting. You may then use merge request approval policies to gate newly detected findings.
Do severity overrides apply retroactively to existing vulnerabilities?
Yes. When a severity override policy is applied, it processes matching vulnerabilities with status "Needs triage" or "Confirmed" on the next default-branch pipeline, up to 1,000 per run.
What happens if two policies set conflicting severities?
Manual overrides always take precedence. For policy conflicts, the most recently applied policy takes precedence. Review your policies regularly to avoid overlapping criteria.
Can developers bypass severity override policies?
No. Policies are managed in a security policy project with restricted access. Developers can't modify or disable them. Authorized users can apply manual overrides on individual vulnerabilities, which take precedence.
Ready to make your vulnerability report reflect real risk? Read the severity override policy documentation to get started, or start a free GitLab Ultimate trial to try it today.
Enjoyed reading this blog post or have questions or feedback? Share your thoughts by creating a new topic in the GitLab community forum.
Share your feedback