A vulnerability assessment and penetration test (VAPT) often follows a familiar path. The report arrives, the high severity findings are fixed, the retest passes, and the PDF is filed. A year later the next test finds new instances of the same weaknesses.
The test was not the problem. The organization treated the report as a list of defects to close, when it was also evidence about how its engineering and operations produce defects. This article describes how to read a report, fix what sits behind the findings, and measure whether security is improving.
Why a filed report changes little
A penetration test is a sample. The tester had a fixed scope and a fixed number of days, and reported what they found in that window. Fixing those items removes them. It says nothing about similar items the tester did not reach.
If an API endpoint lacked an authorization check, the useful question is how an endpoint reached production without one. Until that is answered, the next feature can ship with the same flaw. Closing the ticket and passing the retest confirms only that one instance is gone.
Reading the report properly
Validated findings and attack paths
Separate what was demonstrated from what was inferred. A validated finding has evidence: a request and response, proof of the access obtained, a working proof of concept. Scanner output that nobody confirmed is a lead, not a finding, and a good report labels it as such.
Read the narrative before the findings table. The attack path shows how individual issues combine. An information disclosure, a reused service account password and a permissive file share may each look tolerable alone, and together give domain administrator access. Breaking the chain at its cheapest link can matter more than fixing the highest scored item.
Severity as a starting point
CVSS describes the technical severity of a vulnerability. FIRST, which maintains the standard, states that the base score is not a measure of risk. The score does not know whether your system faces the internet, holds regulated data or sits behind other controls.
Adjust each finding for context:
- Exposure. Reachable from the internet, from any internal user, or only from an administrative network.
- Asset value. What data and functions the system holds, and what an attacker could reach from it.
- Exploitability in your environment. Whether the tester exploited it in practice, and which privileges were needed.
- Compensating controls. Whether something else would block or detect the attack, verified and not assumed.
CVSS includes environmental metrics for this purpose, though few reports use them. Ask your tester to explain any rating that differs from the base score, in either direction.
EPSS and CISA KEV for known CVEs
Where a finding is a published CVE, two public sources help with ordering. The CISA Known Exploited Vulnerabilities (KEV) catalog lists CVEs with reliable evidence of exploitation in the wild. The Exploit Prediction Scoring System (EPSS), also run by FIRST, estimates the probability that a CVE will see exploitation activity in the next 30 days.
A KEV entry on an exposed system belongs at the front of the queue whatever its CVSS score. A high EPSS value is a reason to move faster. A low value is not a reason to ignore a finding on a critical system.
Neither source covers findings unique to your own code, such as a business logic flaw or broken access control. For those, the tester's evidence and your own context are the only inputs.
Fixing the class, not the instance
Most findings fall into a small number of root cause classes. Grouping them this way turns a long list into a few engineering problems.
| Root cause class | Typical findings | Fix for the class |
|---|---|---|
| Missing authorization checks | Insecure direct object references, privilege escalation between roles, unprotected admin functions | Central authorization layer, deny by default, authorization tests in CI |
| Secrets handling | Credentials in repositories, configuration files, scripts and images | Secrets manager, secret scanning before commit and in the pipeline, rotation procedure |
| Patching process | Outdated components, end-of-life software | Asset inventory with owners, patch windows, tracked exceptions |
| Hardening baseline | Default credentials, unnecessary services, weak TLS settings, verbose errors | Hardened images and configuration baselines, applied by automation and checked for drift |
| Identity hygiene | Weak or reused passwords, over-privileged service accounts, missing MFA | Tiered administration, managed service accounts, access reviews, MFA coverage |
For each class, ask why the control that should have prevented it did not. Sometimes no control exists. Sometimes it exists and one team sits outside it, which is an ownership problem and not a technical one.
Fix the instance as well, and quickly where the risk warrants it. The instance fix is where the work begins, not where it ends.
Turning findings into backlog items
A finding in a PDF has no owner. Move every accepted finding into the system where the responsible team already tracks its work, so that it competes for priority in the open. Each item needs:
- a named owner in the team that can make the change
- the adjusted severity and a due date that follows from it
- acceptance criteria that someone other than the author can verify, for example "a user with the viewer role receives 403 on every endpoint under /admin, covered by an automated test"
- a link to the tester's evidence and reproduction steps
- a retest before closure, by the original tester or through an independent internal check
Risk acceptance is a legitimate outcome. Record who accepted the risk, the reasoning and an expiry date, so that the decision is reviewed and does not become permanent by default. A vulnerability management process that already handles scanner output can usually absorb penetration test findings with little change.
Feeding findings into development and detection
Into the SDLC
Each root cause class points to a place earlier in the life cycle where it could have been caught.
- Threat modeling. Add the attack path to the threat model of the affected system, and check whether sibling systems share the design.
- SAST and DAST rules. Where a finding has a recognizable code or response pattern, write a custom rule so the pipeline flags the next occurrence. Tune it until developers trust it.
- Secure defaults in templates. Put the fix into service templates, base images and infrastructure modules. New services then start with authentication, security headers, logging and least privilege roles in place.
- Regression tests. Convert the proof of concept into a test that fails if the flaw returns.
This is the practical core of DevSecOps. The pipeline carries what earlier tests taught, so developers do not have to remember it.
Into detection
A penetration test also tests monitoring, whether or not it was scoped that way. Ask the tester for timestamps, source addresses and the techniques used, ideally mapped to MITRE ATT&CK. Then ask the SOC what it saw.
For each technique there are three possible answers. An alert fired and was handled, telemetry existed but nothing alerted, or no telemetry was collected. The second is a detection engineering task. The third is a logging gap that would also hamper an investigation. Both belong in the backlog alongside the vulnerabilities.
Test cadence and the honest measure
When to test, and with what
An annual test is often a compliance minimum. It fits poorly with systems that change every week. Test after significant change: a new authentication flow, a major architectural change, a new internet-facing service, an acquisition or a cloud migration. Smaller tests tied to releases often teach more than one large annual exercise.
It helps to be clear about what each activity is for.
- Vulnerability management is continuous and broad. It finds known weaknesses across the estate and tracks them to closure. It does not show what an attacker could do with them.
- Penetration testing is time-boxed and deep within a scope. A tester exploits and chains weaknesses, including logic and design flaws that scanners cannot find, to show real impact.
- Red teaming is objective-driven. A team pursues a goal, such as access to a payment system, covertly across people, process and technology. Its main output is an assessment of detection and response, not a list of vulnerabilities.
A red team exercise gives poor value while basic penetration testing findings remain open. The team will reach its objective through well-known weaknesses, and the organization will learn little about detection.
Recurrence across tests
Counts of findings per test mislead. They vary with scope, tester skill and the time allowed. A better measure is recurrence. Tag every finding with its root cause class and compare across tests.
- Which classes appeared in the previous test and appear again, in the same system or a different one.
- Whether findings sit in systems built from current templates or in older ones.
- How long findings stayed open against their due dates, by class and by team.
- Which of the tester's techniques were detected, compared with the previous test.
If a class stops recurring in new systems, the class-level fix worked. If it keeps appearing, the fix was local and the process behind it is unchanged.
Where to start
- Take the last two reports, tag each finding with a root cause class, and note what repeats.
- Move open findings into the owning teams' backlogs with owners, acceptance criteria and a retest step.
- Check every CVE-based finding against the CISA KEV catalog and EPSS, then reorder by exposure and business context.
- Pick the most frequent class and fund one class-level fix, such as a central authorization layer or secret scanning in the pipeline.
- Ask for technique timestamps in the next test, and review with the SOC what was seen.
