A vulnerability report gives you a number first. 9.8. 6.8. 2.9. Somewhere near it, usually in smaller type, sits something that looks like a fragment of a URL:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

That string is the part worth reading. The score is derived from it by a published formula, which means the string carries the information and the number is only a summary of it. Two analysts can look at the same bug and write different vectors. Once their vectors match, their scores match, because nothing else feeds in.

Learning to read one takes about ten minutes, and it changes the question you can ask. Instead of wondering whether 7.5 counts as bad, you can see whether the flaw is reachable from the internet, whether an attacker needs an account first, and whether some user has to click something for it to work at all.

What the string is made of#

Every vector opens with the version it was scored under. CVSS:3.1/ and CVSS:4.0/ are the two in current use. After the prefix comes a run of Metric:Value pairs separated by slashes, always in the order the specification defines.

The prefix is not decoration. CVSS v3.0 and v3.1 use different environmental formulas, so a v3.0 vector run through a v3.1 calculator produces a number that is correct for neither version. Our CVSS calculator refuses a CVSS:3.0 prefix outright rather than scoring it anyway, and it also rejects an unknown metric, an unrecognised value for a known metric, a metric that appears twice, and any vector missing a mandatory metric. A calculator that quietly skips what it does not understand will hand you a confident wrong answer, which is worse than an error message.

Each pair abbreviates one question and its answer. AV:N is Attack Vector, value Network. PR:N is Privileges Required, value None. Learn the eight base metrics and most vectors read close to a sentence.

The eight metrics in a v3.1 vector#

A v3.1 base vector always carries the same eight metrics, in this order:

  • Attack Vector (AV): where the attacker has to be. N network, A adjacent network, L local, P physical. AV:N is what drives most scores above 9.
  • Attack Complexity (AC): whether it works every time. L means repeatable. H means the attacker depends on conditions outside their control, such as winning a race.
  • Privileges Required (PR): what the attacker starts with. N nothing, L an ordinary account, H an administrative one.
  • User Interaction (UI): whether a victim has to act. N none, R required.
  • Scope (S): whether the damage stays inside the vulnerable component. U unchanged, C changed. A changed scope is the sandbox-escape case, and it lifts the score sharply.
  • Confidentiality, Integrity, Availability (C, I, A): what is actually lost. Each is N none, L low, or H high.

Now read the example from the top of this article with that key in hand. Reachable over the network, repeatable, no account needed, no victim interaction, damage contained to the component, and total loss of all three impacts. That is as severe as an unchanged-scope vulnerability gets, and it scores 9.8. Change the one metric S:U to S:C, so the flaw reaches beyond the component it lives in, and the same vector scores a flat 10.0.

Severity bands and the rounding rule#

Both versions use the same five qualitative bands:

  • None: 0.0
  • Low: 0.1 to 3.9
  • Medium: 4.0 to 6.9
  • High: 7.0 to 8.9
  • Critical: 9.0 to 10.0

The arithmetic underneath has one property that catches people out. CVSS does not round to the nearest tenth. The specification defines a Roundup function that returns the smallest number, to one decimal place, equal to or higher than its input. An intermediate value of 8.51 becomes 8.6, and so does 8.500001.

That matters at a band edge. A result a hair under 7.0 does not settle at 6.9 and land in Medium. It rounds up to 7.0 and gets reported as High. If you have ever watched two calculators disagree by a tenth on an identical vector, this rule is usually the reason: the obvious floating-point way to write "round up" misfires on values that binary arithmetic stores a fraction above their decimal form, which is why the specification gives the function in integer arithmetic instead.

Base, threat and environmental are three different numbers#

This distinction causes more confusion than anything else in CVSS, because all three groups get reported as "the CVSS score".

The base score covers the intrinsic properties of the flaw, the ones that do not change with time or with who is running the software. The specification is explicit that this reflects severity rather than risk. A base score knows nothing about whether you are exposed.

The temporal group in v3.1, renamed threat in v4.0, adjusts for what is known right now. v3.1 gives it three metrics: Exploit Code Maturity (E), Remediation Level (RL) and Report Confidence (RC). They can only hold the base score level or pull it down. Take that 9.8 vector and append /E:U/RL:O/RC:C, meaning no exploit code is known to exist, an official fix has shipped, and the report is confirmed. The score becomes 8.5.

The environmental group belongs to you rather than to the vendor. It holds security requirements for confidentiality, integrity and availability (CR, IR, AR) alongside modified versions of every base metric, so you can record that the affected machine sits on an isolated segment or holds nothing sensitive. This group moves the score in both directions. The same 9.8 vector with /CR:L/IR:L/AR:L falls to 8.0.

One asymmetry between the versions is worth carrying around. In v3.1, leaving a security requirement undefined scores the same as Medium. In v4.0, an undefined requirement is treated as High, on worst-case grounds. The identical omission therefore inflates a v4.0 score relative to a v3.1 one, so "we left the environmental metrics blank" does not mean the same thing in both.

What v4.0 changed#

v4.0 is a genuine revision rather than a tidy-up, and its vectors look different enough to trip you up.

  • Attack Requirements (AT) joins the exploitability metrics, separating "this attack is technically fiddly" from "the target has to already be in a particular state".
  • Scope is gone. Impacts are now recorded twice: once for the vulnerable system (VC, VI, VA) and once for subsequent systems downstream (SC, SI, SA). Rather than a yes-or-no flag for blast radius, v4.0 asks how badly the blast radius is hit.
  • The threat group shrank to a single metric, Exploit Maturity (E).
  • Supplemental metrics arrived: Safety, Automatable, Recovery, Value Density, Vulnerability Response Effort and Provider Urgency. These are recorded but never scored, so adding them leaves the number untouched.

v4.0 also names its scores. Because "9.3" alone does not say whether anybody considered exploitation or environment, the specification defines CVSS-B for base only, CVSS-BT for base plus threat, CVSS-BE for base plus environmental, and CVSS-BTE for all three. Our calculator reports which of the four you are looking at instead of printing a bare number.

The rescaling shows at the top of the range. The v4.0 counterpart of that maximal network vector, CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N, scores 9.3 rather than 9.8, because nothing downstream is affected. Append /E:U for an exploit nobody has reported and it drops to 8.1, and the label shifts from CVSS-B to CVSS-BT.

Reading a low-scoring vector#

Severe vectors are easy to read. The instructive ones sit near the bottom, where a small number hides a lot of shape. Consider:

CVSS:3.1/AV:L/AC:H/PR:H/UI:R/S:U/C:L/I:L/A:N

That scores 2.9, Low. Read it left to right. The attacker needs local access before they start, the attack does not work reliably, they need administrative privileges, a user still has to interact, nothing escapes the component, and the result is partial disclosure and partial tampering with no availability effect. Almost every gate is closed, which is why the score collapses.

The useful exercise is working out which gate is load-bearing. Flip PR:H to PR:N, so no privileges are needed at all, and the score moves to 3.6. Still Low. The privilege requirement was not holding it down on its own. Open two more gates, setting AC:L and UI:N, and the same impacts score 5.1, Medium. No single metric shifted the band; it took three assumptions failing together.

That is the practical value of reading the string. It tells you which assumptions the severity depends on, and therefore which detail about your own environment would undermine it.

What the vector cannot tell you#

A vector describes a vulnerability, not your exposure to it. It does not know whether you run the affected version, whether the service faces the internet, or whether anyone is exploiting it this week. Those are separate questions with separate data sources, and the base score is deliberately silent on all of them.

This is why severity alone makes a poor patch queue. Exploit prediction and confirmed-exploitation catalogues answer the "is anybody actually doing this" question that CVSS does not, and we walk through how the three signals fit together in CVSS, EPSS, and KEV. When you are working down a list of real advisories, CVE Explorer and CVE Triage take these vectors as input and put the surrounding context back around them.

Read the string first, though. It costs seconds once the abbreviations are familiar, and it is the difference between repeating a number somebody else computed and understanding what it was computed from.

Try it

Paste a vector, or build one

Score a CVSS v3.1 or v4.0 vector metric by metric, or paste one straight from an advisory. You get the score, the severity band, which score type it is, and a plain-English reading of every value in the string.

Open the CVSS calculator →