Tracking Pentest Findings in a Spreadsheet, and When to Stop

Track pentest findings in Excel or Google Sheets with a fixed ID, CVSS vector, owner, target date and retest result on every row, and know when to stop.

A pentest findings tracker in Excel or Google Sheets needs one row per finding with an ID that never changes, the severity and CVSS vector, the affected assets, a status from a defined list, a named owner, a target date, the latest retest result and a link to the evidence. It stays honest while one person owns it, IDs are never reused and history is added rather than overwritten, and it is time to stop when the firm and the client are both editing copies of it.

One set of findings, two trackers

A testing firm keeps a tracker to know which findings are open across its engagements, which are due a retest and what each retest found. The client receiving the findings keeps one to run remediation: who is fixing what, by when, and what was decided about the rest. Both start from the same report and need most of the same columns. The difference is ownership. The firm owns the ratings and the retest results, the client owns the people and the progress, and most of the trouble below comes from a sheet either side can change.

The columns that matter

ColumnWhat goes in itWhy
Finding IDThe engagement reference and a number, such as ACM-031-07Tickets, emails and retests all refer to it. Titles get reworded; the ID never changes.
TitleThe title exactly as the report gives itSo anyone can find the finding in the document.
ReportedThe date the client was told, and the report versionThe remediation clock starts here.
Severity and CVSSThe rating, the score and the full vector string, which begins with its versionA score without its vector cannot be checked, and when a rating changes the vector shows what moved.
Affected assetsEvery host, URL or component, or a tab with one row per finding and assetFixes land asset by asset. A finding on forty hosts is fixed when the fortieth is.
StatusOne value from a defined listEvery count and filter depends on it.
OwnerA named personA team or a distribution list is not an owner.
Target dateA date taken from the agreed remediation timelineIt turns a severity into a date somebody can be held to.
Retest result and dateThe outcome of each retest, and when it was doneIt separates fixes the client reported from fixes somebody verified.
EvidenceA link to the evidence in the report or your controlled storeThe evidence itself never goes in the sheet.

Target dates should come from a table agreed before testing, not negotiated finding by finding afterwards; vulnerability remediation timelines sets one out, with where each figure comes from. On the client's side, add a column for the ticket in their own system, so the sheet points at the work rather than replacing it.

Rules that keep a sheet honest

  • One sheet, one owner. Decide whose copy is the record and who answers for it, and let it be the only copy. If both sides edit it, give each side its own columns: in Google Sheets, protect the ID, rating and retest columns so only the firm can edit them; in Excel, unlock the columns the client fills in and protect the rest of the sheet.
  • IDs are never reused. A finding withdrawn in QA or after a dispute keeps its row and its ID, marked withdrawn with the reason. Never number by row, never renumber after a sort, and give anything found during a retest a new ID.
  • Statuses are defined. Put the list and what each status means on a tab of its own, and make the column a dropdown.
  • History is added, not overwritten. When a severity, status or target date changes, add a dated line to a change log tab with the old value, the new one, who changed it and why. Version history shows that a cell changed; only the log says why.
  • The sheet is as sensitive as the report. Unfixed weaknesses listed against hostnames are exactly what an attacker would want. Share it with named people, never through a link anyone can open, and remove access when the engagement ends.

A status list that covers most engagements:

StatusMeansSet by
OpenReported, with no fix yetThe firm, at delivery
In progressSomebody named is working on itThe client
Fix reportedThe client says the fix is deployed to the tested environmentThe client
RemediatedA retest found the weakness goneThe firm
Part remediatedA retest found some of it still presentThe firm
Not remediatedA retest found it unchangedThe firm
Risk acceptedA named person decided not to fix it, with a date to revisit itThe client, recorded by the firm
WithdrawnRemoved after QA or a dispute, with the reasonThe firm

Separating fix reported from remediated is the point: a sheet that only says "fixed" cannot tell a claim from a verified result. Risk accepted is a status of its own rather than a kind of closed, for the reasons in when a client accepts the risk instead of fixing it.

What breaks as volume grows

A sheet like this holds up for one engagement and one contact. With several of each, it fails in four places.

Copies edited by both sides. The firm sends the sheet, the client adds columns and renames two statuses, the firm records a retest in its own copy in the meantime, and somebody merges the two by hand. Every merge is a chance to lose an update, and the one lost is usually the retest result.

The report and the sheet disagree. A finding withdrawn in QA stays in the sheet, or a severity lowered after the debrief changes in the report but not in the tracker the retest will start from. Two records of one engagement drift apart, for the reasons set out in Word and spreadsheets or a reporting platform.

Evidence does not travel. A link to the firm's file share means nothing to the client's engineer, and screenshots pasted into cells go wherever the sheet is forwarded. The developer fixing the finding needs the request and the response; the sheet gives them a title and a colour.

Retests and auditors ask for history. An auditor wants to know when a finding was reported, how it was rated then, when it was fixed and who verified it. A retest starts from the original finding, its evidence and the client's account of the fix, as how to run a retest properly sets out. A sheet with overwritten cells cannot answer either, and a weakness raised again next year under a new ID hides that it came back.

When to stop

The signals are about how the sheet is used, not how many rows it has. Stop when you merge copies more than once an engagement, when retest requests arrive as edited spreadsheets by email, when the client's engineers already work from a ticketing system and the sheet has become a copy of their tickets, or when somebody asks for a history you would have to rebuild from old versions.

What replaces it depends on your side. A client should move remediation into its own ticketing system, one ticket per finding carrying the finding ID, which is what what happens after a penetration test recommends on the day the report lands. A testing firm should move to a record that the report, the tracker and the client's view are all generated from, so nothing needs reconciling.

The spreadsheet does not disappear. It becomes an export: a dated, read-only snapshot for a board pack, an auditor or a client who wants to filter findings their own way. A snapshot that says when it was taken is useful. A copy that passes itself off as the record is where the trouble started.

Our free reporting tool and the Portal share the same reporting. Findings go out to Excel, PDF or Word for one finding, an engagement or every phase at once (one Excel file with a tab per phase), with the columns you choose, a summary tab of severity counts per phase and a figures tab linking every figure back to its finding. Change the sheet in Excel and bring it back, and you see what would change and what would be deleted before anything is. In the Portal, clients sign in to read their findings, ask for retests and comment on the engagement, and findings can be pushed to their Jira, ServiceNow and other trackers with their state read back, as retests and your client's issue tracker explains. Exporting findings to Excel, Word or PDF covers the exports.

Common Questions

What columns should a pentest findings tracker have?
One row per finding, with an ID that never changes, the title as the report gives it, the date and report version it was reported in, the severity with its CVSS score and full vector, the affected assets, a status from a defined list, a named owner, a target date from the agreed remediation timeline, the latest retest result and date, and a link to the evidence. Clients should add the ticket reference from their own system.
Who should own a pentest remediation tracker, the client or the testing firm?
Both have a part, so split the columns rather than sharing everything. The testing firm owns the ratings, CVSS vectors and retest results, because those are its findings. The client owns the owner, target date and progress columns, because the work is theirs. Keep one copy as the record, protect each side's columns, and send updates to whoever owns them rather than keeping a second copy that has to be merged later.
How should pentest findings be numbered?
Give each finding an ID made from the engagement reference and a sequence number, and never change or reuse it. A finding withdrawn in QA or after a dispute keeps its ID, with a withdrawn status and the reason. Do not use row numbers, which change when somebody sorts the sheet, and give anything new found during a retest a fresh ID rather than borrowing an old one.
When should you stop tracking pentest findings in a spreadsheet?
When you merge copies edited by both sides more than once an engagement, when retest requests arrive as edited sheets by email, when the client's engineers already work in a ticketing system, or when an auditor asks for a history you would have to rebuild from old versions. At that point the client should track remediation in its own tickets and the firm in a system that generates the report and the tracker from one record.

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