How to Prove a Penetration Test Finding Is Actually Fixed
Picture the week before an audit. The penetration test report is six months old, the tracker shows every critical finding as “done,” and the engineers are confident. Then someone from audit asks a short question: who confirmed these are closed?
“The team did” is a fair answer and a thin one. A fix is what your people say they changed. Evidence is something a second person can look at without taking anyone’s word for it. A retest is the step that turns the first into the second.
Where fixes can fail
A fix can fail without anyone being careless. One server gets the patch and its twin doesn’t. A filter blocks the exact request the tester sent and lets a slightly different one through. Or a later release rolls the change back, and nobody connects the two events. None of that shows up in a ticket, because a ticket records intent.
A retest repeats the attack that proved the finding. If the tester could take over an account on the first run, the retest tries the same thing against the fixed system and reports what happens. Because every finding in our reports is proven in the first place, there is always an exact attack to repeat. A finding that was only ever “likely” gives the retest nothing to hold on to.
One finding, from discovery to closed
On a digital bank’s payment module, a customer’s payment alias could be hijacked, and a missing duplicate check let one payment be credited twice. The fixes added one-time-password checks on alias changes and signed callbacks, and the retest confirmed the fixes before the module launched on plan.
Follow the alias finding through that sequence and you can see what a record has to hold. The report says what was found and how it was proven. The engineers say what they changed and when. Then a second person repeats the original alias-change request against the fixed module, and writes down what came back. That last step is what gives a launch decision something other than the engineers’ word.
Two shorter cases show what else a retest settles. A bank’s mobile QR payment module had printed QR codes that could be swapped and an SDK key that could be intercepted, and the bank moved to signed dynamic QR codes and certificate pinning. A retest confirmed the critical findings were closed before the audit.
At an industrial site, testers worked from the office network toward the plant controllers through a historian password, a jump server and a vendor VPN, and all of it ran on a lab copy. When we retested, every high-risk finding had been closed. For anyone responsible for a plant, that’s the gap between believing the path is shut and having it confirmed.
A record for each finding
You don’t need a special tool. A shared document works if every finding has the same few lines. Here is an entry you could write for the payment alias finding, with the dates left blank:
Finding: Payment alias can be hijacked (severity per your report)
Original proof: the steps and requests from the report, referenced by finding ID
Fix: OTP check added to alias changes. Reported complete by
[fix owner] on [date]
Retest: [date], repeated by [verifier role], ideally not the person
who made the fix
Repeated: the original alias-change request, then variations of it
Observed: what the system returned, with a screenshot or request log
Neighbors: other places that change an alias, or use the same check
Result: Closed / Partly closed / Open
Left over: anything not fixed, what limits the risk meanwhile, and who
accepted it
Two lines do most of the work. On “Retest,” we’d suggest someone other than the author of the fix repeats it, because the author has a stake in the answer. “Left over” matters because some findings can’t be closed on schedule, and a legacy system waiting for replacement is one example. In that case the honest status is “open, with a control and a named owner.” A reviewer who finds that written down has less to ask about.
Say what the retest did not cover as well. If time or access meant it looked only at critical and high findings, write that on the record. A boundary you state yourself shows care, and a boundary someone else discovers looks like a gap.
What the standards say
PCI DSS requirement 11.4.4 asks that exploitable findings are corrected and that testing is then repeated. Ask your assessor early what form of record they want to see for the repeat, because they decide whether what you show is enough. The layout above is a suggestion; no standard prescribes one.
For how a single test serves PCI DSS, ISO/IEC 27001:2022 and SOC 2 audits together, our penetration testing evidence for audit guide covers the whole file.
Questions readers ask
What is a penetration test retest? A retest repeats the attack that proved a finding, after the fix, to see whether it still works.
Is a developer’s confirmation enough to close a finding? It is a good first signal and weak evidence. The person who made the change has a stake in the answer, so the stronger record is one where someone else repeated the attack and wrote down what they saw.
A quick test you can run today
Pick the finding your report rated highest. Without asking anyone, try to answer from the tracker alone: who confirmed it is closed, on what date, and what did they see? If you end up sending a message to fill in any of those, the record is still missing something. Then ask for the same on the next three findings down. The pattern across four will tell you more about your process than the report did.
Fixing that can be a small change. Decide that a finding can’t be marked closed without a linked retest result, and agree who may verify. Plan the retest when you plan the test, so the fix window, the retest and the audit date sit on one calendar. Our penetration tests come with the retest built in.
If you want to plan a test and its retest together, book a free 90-minute scoping session, or request a scoped proposal if you already know the scope. To see how we run the testing itself, read about our penetration testing services.