CVSS Scoring Mistakes in Pentest Reports and How to Fix Them

The CVSS scoring mistakes that survive peer review in pentest reports, what changed in CVSS 4.0, and how to score a finding so the argument stays on the fix.

The CVSS scoring mistakes that do most damage in pentest reports are scoring what you imagine rather than what you observed, treating effort as complexity, reading Privileges Required off the interface, presenting a base score as urgency, and letting the severity label disagree with the vector. Each one invites a conversation about the score instead of the fix, and a client who quietly starts checking your other numbers.

Two things make this harder than it should be. Scoring is genuinely subtle in places, and the industry is running two versions of the standard side by side, with tooling that reports one and specifications that describe the other. A disputed score is also the commonest route into the conversation covered in when a client disputes a finding.

Know which version you are speaking

CVSS v3.1 is still what a great deal of client tooling emits, while some vendors now publish CVSS v4.0 vectors, and the NVD shows a vendor's 4.0 vector next to its own 3.1 score where one has been supplied. CVSS v4.0 is the current specification, and it changed enough that a vector from one is not a vector from the other. Publishing a number without saying which produced it is the first avoidable argument.

ConceptCVSS v3.1CVSS v4.0
Impact beyond the vulnerable componentA single S (Scope) flagSeparate metrics for the vulnerable system (VC/VI/VA) and subsequent systems (SC/SI/SA)
Preconditions outside the attacker's controlFolded into Attack ComplexityIts own metric, Attack Requirements (AT)
User involvementNone or RequiredNone, Passive or Active
NamingBase score, with optional extrasCVSS-B, CVSS-BT, CVSS-BE, CVSS-BTE, stated explicitly
Supplemental contextNot modelledSafety, Automatable, Recovery, Value Density and others

The Scope change is the one that catches people out in reports. If your methodology section still explains how you treat Scope and your vectors are v4.0, one of the two is wrong, and a reviewer who knows the specification will find it. Worked CVSS 4.0 examples for pentest findings show how common findings translate.

State the version once, in the methodology, and use it consistently. Where a client's automated tools report v3.1 and you score in v4.0, say so and give both for anything critical. It takes a sentence and removes an entire class of dispute.

Score what you observed, not what you can imagine

Base metrics describe the vulnerability as it exists. If you achieved read access to one table, the impact metrics describe read access to one table. The chain onward to full compromise belongs in the narrative, and if you actually walked that chain, it belongs in its own finding with its own vector.

The temptation runs the other way when a client has been unresponsive: score it high enough and somebody will finally pay attention. It works exactly once. Afterwards every number you publish is discounted by the reader, including the accurate ones, and the discount is applied by the person you most need to believe you.

Inflation is not a scoring decision. It is a decision to spend credibility you will want later.

Complexity is not effort

Attack Complexity describes conditions the attacker cannot control: a race that has to be won, a deployment state that has to already exist, a value that has to be guessed with meaningful probability of failure. It is not a measure of how long the exploit took you, how much tooling you wrote, or how obscure the technique felt.

A fiddly but reliable exploit is low complexity however long the afternoon felt. In v4.0 the genuinely conditional cases have somewhere better to live: Attack Requirements exists precisely so that "this only works against a specific configuration" stops being crushed into the same metric as "this needs a race condition".

Privileges Required is about the attacker, not the interface

Privileges Required describes what the attacker holds before the attack begins, not what the application asks a legitimate user for. If the endpoint answers unauthenticated requests, the fact that the button is behind a login is irrelevant to the vector.

Client-side gating is a finding in its own right, not a mitigating factor in someone else's score. An admin function hidden by a disabled button and enforced nowhere else is PR:N, and the report should say why.

A base score does not answer "is this urgent for us"

Base metrics are deliberately environment-blind, which is what makes them portable between organisations and what makes them a poor answer to the only question your client actually has. Environmental metrics exist for this, and they are the single most valuable and least used part of the standard in consultancy work.

If you know the asset is internet-facing, holds cardholder data, and sits in the authentication path for everything else in the estate, you know more than the base score does. Say so, adjust, and show both numbers with the reasoning between them.

A client can get a base score from automated tools for nothing. Contextualised severity is the part they are paying a human being for.

Label and vector must never disagree

If your report carries both a severity word and a numeric vector, they have to agree, every time. A finding labelled Critical with a 6.4 vector reads as carelessness even when the label is the more accurate of the two, and it is the first thing a technically literate reviewer picks at. A written mapping of penetration testing severity levels to score ranges settles most of these before review.

Where your professional judgement genuinely overrides the arithmetic, say so inside the finding. "Scored Medium by CVSS, raised to High because this host authenticates every other system in the estate" is defensible and useful. Silence is neither.

The habit that prevents most disagreement is writing the vector before the prose. Fixing a vector after the narrative is written creates quiet pressure to leave the narrative alone, and the two drift apart over a long report. Vector first, then describe what the vector says, and they cannot contradict each other. Then ask the review question: could a competent reader reconstruct your vector from your description alone, without looking at the string? If not, one of the two is wrong, and it is usually the description.

  • Version stated once, and the same version used throughout.
  • Vector matches the described access, preconditions and demonstrated impact.
  • Chains scored as separate findings rather than inflating one.
  • Environmental adjustment applied where you know enough to apply it, with its reasoning stated.
  • Severity label and score agree, or the divergence is argued explicitly.
  • Anything the client's automated tools also reported carries both versions if the numbers differ.

Scoring consistently across a team

Everything above is about one person scoring one finding. The harder problem is five people scoring forty findings across a quarter and arriving somewhere consistent, because inconsistency between testers is what a returning client notices first.

Three things move the needle more than training does.

  • Write the house position down. Not the specification, which already exists, but the calls your firm makes: how you treat an unauthenticated endpoint hidden behind a client-side check, when a chain gets its own finding, whether you apply environmental metrics by default. One page, agreed once.
  • Score in review, not only in writing. The reviewer checks the vector against the description as a matter of course. It takes seconds and it catches the drift early, while the finding is still cheap to change.
  • Reuse the wording, not just the score. A weakness your firm has described well once should be described that way every time, which is the case for a findings library your team actually uses.

Exploit Maturity is the metric that dates your report

v4.0 keeps a threat group, with Exploit Maturity in place of v3.1's Exploit Code Maturity, and it is the one metric that is a statement about the week you wrote the report rather than about the vulnerability. A base score stays true. A score carrying Exploit Maturity stops being true the moment somebody publishes working code.

The naming makes this explicit: a base-only score is CVSS-B, base plus threat is CVSS-BT, base plus environmental is CVSS-BE, and everything together is CVSS-BTE. If you publish a BT score, publish the date you assessed it, because a reader six months later has no way to know it was accurate when written.

For most consultancy work, publish CVSS-B in the vector and put exploitability in the narrative, where it can carry a date and a caveat and be re-read as an observation rather than arithmetic. The exception is worth making deliberately: where a weaponised exploit exists on the day you report, that belongs in front of the client in whatever form they will actually act on.

One weakness on forty hosts is not forty findings

The same missing patch across an estate is one finding with forty affected assets, not forty findings with identical text. Splitting it inflates the count, buries the interesting work under repetition, and gives the client forty rows to project-manage where they have one decision to take.

The exception is the host that genuinely differs. If thirty-nine are internal and one is internet-facing, that one has a different environmental score and often a different urgency, and it earns its own entry with the reason stated. Merging without noticing the outlier is the failure that matters here, and it is the one a client discovers at the worst possible moment.

Findings are scored with CVSS 3.1 or CVSS 4.0, whichever your firm chooses, and the score is calculated from the vector rather than typed, so the number in the report is always the number the vector produces. A finding your firm has written and scored well can be added to the findings Library and imported into the next engagement, which keeps testers starting from the agreed version. Reviewers comment and suggest changes in the QA queue before the report goes out. See how findings and scoring work.

Common Questions

Should a penetration test report use CVSS 3.1 or CVSS 4.0?
Either can be defended, provided the report states which one in the methodology and uses it consistently. CVSS 4.0 is the current specification and models impact on subsequent systems better than the old Scope flag. Plenty of client tooling still reports 3.1, so for anything critical, where a client's tools show a 3.1 number that differs from yours, give both and say why.
What is the difference between CVSS-B, CVSS-BT and CVSS-BTE?
They name which metric groups went into a CVSS 4.0 score. CVSS-B is base metrics only, BT adds the threat metrics such as Exploit Maturity, BE adds environmental metrics, and BTE uses all three. A BT score dates as soon as exploit code is published, so most consultancy reports are better publishing CVSS-B and describing exploitability, with a date, in the narrative.
Does Attack Complexity mean how hard the exploit was to write?
No. Attack Complexity describes conditions outside the attacker's control, such as a race that has to be won or a value that must be guessed. It does not measure how long the exploit took or how much tooling you wrote. A fiddly but reliable exploit is low complexity. In CVSS 4.0, preconditions about the target's configuration belong in Attack Requirements instead.
Should one vulnerability on many hosts be one finding or many?
One finding with a list of affected assets, unless a host genuinely differs. Forty identical entries inflate the count and give the client forty rows to manage where they have one decision. The exception is the outlier, such as the one internet-facing host among thirty-nine internal ones, which earns its own entry with a different environmental score and the reason stated.

Keep Reading

Setup guide

See the product set up, end to end

The whole setup in 10:01, with chapters you can jump to: registering, your own domain, your own database in any of three places, your own mail server, branding, the first sign-in, updating the database on Supabase Cloud, and moving the database if you change your mind.

  • 0:00 · Registering, signing in, and the free trial
  • 0:44 · Your name and your firm’s name
  • 0:50 · Custom domain
  • +6 more