Pentest Remediation Evidence: An Audit-Ready Guide
Turn pentest findings into audit-ready remediation evidence. Learn the records to keep, how rescans verify fixes, and what to do with risks you cannot fix.

A Pentest Report Is the Beginning: What Audit-Ready Closure Looks Like
A penetration test report tells you what was wrong. It doesn't, by itself, show an auditor or an enterprise customer's security team what happened next. To do that, you need a clear paper trail that connects each finding to an agreed scope, the code change, the review, and the verification result.
That gap is easy to miss. The team fixes vulnerabilities, then - right before an audit or customer review - realizes the evidence is spread across tickets, pull requests, chat threads, and scanner outputs. The technical work may be done, but proving it's done becomes its own project.
A better approach is to treat evidence as part of remediation, not something you scramble to assemble afterward. This article covers what to record for each finding, what to do when an item shouldn't be "fixed" with a quick code change, and how to avoid common closure mistakes. The examples come from a Fix Sprint using OWASP NodeGoat, a deliberately vulnerable Node.js application. Your auditor or customer may want a different format, so confirm requirements before work starts.
What audit-ready pentest closure means
A pentest report is a diagnostic document. It identifies weaknesses, describes their impact, and gives the team a starting point for remediation. An audit-ready evidence pack has a different job: it lets another person follow the path from the original finding to its final status without relying on informal explanations.
That path should answer four basic questions:
- What was found? The finding should have a stable identifier and enough technical context to locate it.
- Was it agreed to be in scope? The agreed list should make clear what the team committed to address.
- What did the team do? A change, exception, or other decision should be documented and attributable.
- How was the result checked? You should have evidence that the change addressed the finding, plus a record of any remaining risk.
This is not the same as claiming the application is secure. A clean rescan only tells you what that scan checked, against the version and configuration it tested. It doesn't prove every possible weakness is gone. The goal is narrower and more useful: show what was tested, what changed, and what the verification found.
The difference between a report and an evidence pack
A report usually describes the initial state. The evidence pack documents the remediation lifecycle. You should be able to start at a finding in the report and move through its status, the relevant code change, review/merge information, and the verification output.
That distinction matters when a customer asks for proof. Saying "the vulnerability was fixed" is a claim. Pointing to the finding ID, the reviewed pull request, the merged code, and the post-fix scan gives the reviewer something they can inspect.
The reviewer shouldn't have to guess whether an item was fixed, accepted, deferred, or excluded. Those outcomes aren't interchangeable. If you collapse everything into a single "closed" label, the record becomes much harder to trust. A useful pack preserves the outcome honestly, including unresolved or explained findings.
Agree scope before changing code
Write down which findings the remediation effort will address before you start making changes. That creates a baseline for both the team and the reviewer. It also prevents scope from quietly expanding when new issues pop up, and it reduces the chances that an agreed finding disappears from the final record without explanation.
Scope can come from the pentest report, a scanner export, or another agreed list. The key is that each item can be reconciled later: included and addressed, included but not fixed, or explicitly out of scope. If a new issue appears during remediation, record it separately rather than silently adding it to or removing it from the original list.
The six records to keep for every finding
For each finding, keep enough information to trace it from discovery through verification. A spreadsheet or CSV often works as the index. It's not the evidence itself - it points to the pull request, review, and scan output that supports the status.
1. A stable ID and technical description
Give each finding a stable identifier (for example, F-004) and keep the weakness type. Where it's relevant, include a recognized weakness reference such as CWE-601 for an open redirect. Record the affected file and line, or another precise location if the issue isn't tied to a single line.
The identifier should remain stable as the finding moves from the report into a ticket, pull request, or evidence table. If the team renames it, preserve the mapping. Otherwise, a reviewer may not know whether two records are describing the same issue.
2. Evidence that it was in scope
Keep the written scope that was agreed before remediation. Your evidence row should indicate whether the finding was included, excluded, or handled under a separately agreed decision.
This protects against both accidental omissions and retrospective scope changes. If you create the list only after the work is finished, it can't prove what the team originally agreed to close. Keep the original baseline and record any approved changes to it.
3. The code change and its rationale
Link the finding to the pull request that addresses it. Describe what changed and why in terms a reviewer can connect back to the original weakness.
A diff alone can be hard to evaluate without context. The reviewer needs to understand how the change blocks the weakness and whether it affects nearby behavior. Usually, a short explanation in the pull request is enough - the goal is traceability, not an essay.
When practical, keep changes small and focused. Ideally, one pull request per weakness makes the relationship easy to verify. If changes are grouped for a legitimate operational reason, map each finding to the relevant change so the connection doesn't become guesswork.
4. Who made and reviewed the change
Record the author and the review/merge details from your team. A remediation provider can propose a fix, but the application owner is still responsible for deciding whether it's appropriate to merge into the product.
This separation matters in real life. The person who implemented the change may understand the intended behavior, while the owning team can judge compatibility with the rest of the system. Save the actual review record; don't rely on "someone looked at it" notes.
5. Verification after the change
Keep the post-fix scan result and summarize what it showed: whether the original finding remained, and whether the scan found anything new. Link the result to the code version that was tested when you can.
A rescan isn't a substitute for tests or code review. It answers one question: did the check that originally identified the finding still identify it after the change? CI, application tests, and manual review cover other risks. Use the evidence together instead of treating one scan as proof of overall security.
6. The date the change was merged
Record the merge date, not just when someone started working on the fix. If the audit period matters, the merge date helps show when the change actually entered the codebase.
Be explicit about which version was rescanned. A passing scan on an unmerged branch doesn't prove the production-bound code contains the fix. The record should make the sequence clear: reviewed, merged, then the relevant version checked.
A practical evidence table might include columns for finding ID, weakness, location, scope status, disposition, pull request, author, reviewer, merge date, and verification result. Keep the row concise and link to supporting records rather than copying everything into the spreadsheet.
A real example: one fixed finding and one explained finding
In a Fix Sprint on 14 October 2026, the team used OWASP NodeGoat, a deliberately vulnerable Node.js application, as a remediation rehearsal. Sixteen findings were in scope. The exercise summary says fifteen were fixed across five pull requests: six using Railo's rule-based fixes and nine written manually by an engineer. One finding was explained rather than changed.
The useful lesson isn't the number of fixes. It's that the final record distinguishes outcomes and points back to evidence. For example, a row for F-004 identifies an open redirect, CWE-601, at app/routes/index.js, line 72. It records who supplied the fix, links to the pull request, and states that the finding was gone after verification, with no new findings reported.
There's also a practical nuance in the example: the exercise reports fifteen fixes across five pull requests, even though the general recommendation is one pull request per weakness wherever possible. The count alone doesn't tell you how the changes were grouped. In your own evidence pack, make the mapping explicit. If one pull request addresses several findings, identify the exact changes for each one - don't make the reviewer infer the connection.
Why the unmodified finding matters
F-007 was a TLS private key committed to the repository. Deleting the file may remove it from the current working tree, but it doesn't remove the key from Git history. If the key was exposed, treat it as compromised. The right response isn't to mark the original finding as fixed just because the file disappeared.
In the evidence pack, the item is recorded as explained, not changed, and the recommendation is documented: create a new key and certificate, store them outside the repository, remove the committed file, and rewrite history if the repository is or was public. The exact response depends on exposure and repository access - but the key point is to record the real disposition and the remaining actions.
The final scan of the merged code found only that one finding. That's exactly the kind of candid detail a reviewer needs: the scoped items were addressed except for one, and the reason it remains listed is documented. An exception with a clear rationale is more credible than a clean-looking report that hides the risk.
The full evidence pack and CSV are available at railo.dev/sample-evidence. The original source article describes the exercise and its records in more detail.
A practical closure workflow - and where teams go wrong
Evidence is easier to assemble when the workflow generates it as you go. A workable sequence is:
- Baseline the findings. Assign stable IDs and agree in writing which items are in scope.
- Choose a disposition for each item. Decide whether it will be fixed, explained, deferred, or excluded, and record the reason when needed.
- Implement focused changes. Link each finding to the relevant pull request and describe what changed and why.
- Review and merge through the owning team. Keep authorship and review visible; don't treat a proposed patch as an approved change.
- Rescan the merged version. Save the output and record the version or commit that was checked.
- Reconcile the pack. Confirm that every scoped finding has a status and supporting evidence, including those not fixed.
This sequence isn't complicated. The value is that each step creates a record the next step can reuse. If you wait until the customer asks for evidence, you end up reconstructing decisions from scattered systems and people's memory. You can do that once. Doing it for every report turns into avoidable operational debt.
Three closure mistakes that weaken the evidence
Deleting the evidence instead of fixing the weakness. Removing a file, a line, or a scanner rule can make an alert disappear without addressing the underlying risk. The fix should change the relevant behavior or exposure, and the record should show what changed. Suppressing a scanner finding can be appropriate in some situations, but it needs a documented rationale and shouldn't be presented as remediation.
Merging without a rescan. A patch can fail to remove the original finding, introduce a new issue, or break behavior elsewhere. A post-change scan checks whether the original signal remains and whether new findings appeared within the scan's coverage. CI and application tests still matter, and a rescan doesn't replace them.
Using one giant pull request for unrelated fixes. Large batches are harder to review and make it difficult to link a particular change to a particular finding. Focused pull requests improve traceability and make rollback or follow-up easier. You can still group changes when it's operationally reasonable, but the evidence must map each finding to its change.
Keep the pack proportional
Audit evidence doesn't have to turn into a second security platform. For a small remediation effort, one well-maintained table plus links to source records may be enough. Larger teams may prefer an issue tracker or workflow that captures the same fields automatically.
The right approach depends on repetition and risk. If you close a handful of findings once, a spreadsheet is practical. If multiple product teams close findings every month, manually assembling the same records is a good way to introduce omissions. Automate ID transfer, pull request links, review status, merge dates, and scan results where your existing tools support it.
Don't automate the judgment itself. A scanner can't decide whether a credential should be rotated, whether a change is safe for the product, or whether a documented exception will satisfy a customer. Automation should reduce clerical work, while keeping ownership and risk decisions visible.