DeFi Security AllianceRequest an audit
Menu

Audit deliverables

Audit Report Explained: Scope, Severity and Status Fields

An audit report explained properly starts at the scope statement and the dates, not at the findings table. Everything below those pages is conditional on them: which files were read, in what window and under which severity rule the firm writes its labels. This guide walks a real published report end to end, and measures the severity and status vocabulary that member firm reports actually use.

Open bound report with blue tab bookmarks and a column of colored severity swatches, illustrating the structure of a smart contract audit report.

Key facts

Three severity rules
Impact alone at Immunefi, likelihood times impact under the OWASP risk rating, a percentage and dollar loss threshold at Sherlock. The tier is a house decision
Measured vocabulary
Of 80 reports sampled from 17 member firm archives, 53 use the word status and 12 different words carry the response, while only 26 say how the severity was reached
The word nobody writes
Not one of the 80 reports says won't fix, will not fix, declined or risk accepted. The refusal to fix is written as Acknowledged
Fixed is not Resolved
Fixed is usually the client's claim during the engagement. Resolved is a fix reviewer's verdict in a second document, and Trail of Bits reserves it for issues sufficiently resolved
What re-verification costs
Trail of Bits spent two consultants and eight person-weeks on the ChainPort review, then one consultant and one person-day re-checking all 22 fixes

What the document is, in the order it arrives

A smart contract audit report is not a certificate. It is a record of what a named team looked at, for how long and what they found while looking. Every part of it is conditional on the first few pages, which is why so many readers who open at the findings table draw the wrong conclusion from it.

The shape is stable across firms even when the vocabulary is not:

  1. Cover and notices. Client, firm, date, distribution terms, and the disclaimer that says the findings are not a complete list of what is wrong with the system.
  2. Executive summary. Engagement window, team size, effort in person-weeks.
  3. Scope, or project targets. Every repository and commit that was read, with the language and platform of each. This is the section that decides whether the document describes the thing you are looking at.
  4. Coverage and methodology. What the team tried, and where they say they ran out of time.
  5. Findings summary. One row per issue.
  6. Detailed findings. Each issue written out with its exploit scenario, an affected component, and a recommendation the client may or may not have taken.
  7. Appendices. Severity definitions, status definitions, tool output.

Before any of that, work out which kind of document you have, because the sections above describe one of four. A firm review is the case this guide follows. A contest results page is judged under the platform's rules rather than the firm's, so its tiers and its silences mean different things. An automated scan carries no scope statement worth the name. And a public summary letter is a short version of a report you have not been shown. Even between firm reviews the vocabulary moves: in our sample one firm's reports use three severity tiers and five firms' reports use seven.

The scope statement is the section that decides whether the rest of the document applies to the thing you are about to use. Take the public Trail of Bits review of the ChainPort bridge. Its targets are three separate repositories at five separate commits: the Solidity contracts, a Python back end running on AWS Lambda, and a JavaScript front end. A reader who assumes an audit covers "the protocol" would miss that the bridge's off-chain half was reviewed as a distinct target with its own findings, and that a fourth component would have been outside all of it.

Dates deserve the same suspicion. The ChainPort engagement ran from to , with eight person-weeks of effort from two consultants. The report on the cover is dated . Nothing improper happened there, publication simply waits on the client, but the cover date is the date the document became public and not the date anyone read the code. Look for the engagement window in the executive summary and treat that as the age of the review.

Individual findings have their own shape, and it repeats: a title, a severity, the component it lives in, a description with the sequence that triggers it, and a recommendation. The recommendation is worth reading even for findings you do not care about, because it shows whether the reviewer understood the system or was pattern matching. A recommendation that says to add a check is generic. One that names the invariant the check protects came from someone who read the protocol.

Our walkthrough of what happens inside an audit covers the production side of the same document, and the alliance note on building secure crypto projects sets out what a commissioning team should require its report to contain. This guide is written for the person holding the finished PDF.

The severity label is a house word, not a standard

Two firms can look at the same bug and file it two tiers apart without either being wrong, because they are answering different questions. There are three families of answer in circulation.

Impact only

Immunefi classifies on a four level scale of Critical, High, Medium and Low, decided largely by the consequence of a successful exploit. The smart contract table is explicit about where the line falls: permanent freezing of funds is Critical, temporary freezing of funds is High. The same defect in the same file changes tier on how long the money stays stuck. Griefing with no profit motive lands at Medium, and a contract that fails to deliver promised returns without losing value is Low.

Likelihood times impact

The OWASP Risk Rating Methodology scores likelihood and impact separately on a 0 to 9 scale, buckets each as Low, Medium or High, then reads the pair off a matrix whose worst cell is Critical and whose mildest is called Note. This is where the phrase "likelihood and impact" in a firm's appendix usually comes from. Worth separating from it: the OWASP Smart Contract Top 10, which lists SC01 Access Control through SC10 Denial of Service. That is a list of categories, not a severity scale, and a report citing it has told you what kind of bug it is, not how much it matters.

Loss thresholds

Contest platforms need severity to be arbitrable between strangers, so they write it as arithmetic. Sherlock recognizes only high and medium findings, and defines a high as a direct loss where users lose more than 1 percent and more than 10 dollars of their principal, yield or fees, with medium set at more than 0.01 percent and more than 10 dollars under constrained conditions. Its guidelines state that likelihood is not considered at all. A front running issue that rates high on Ethereum mainnet is downgraded to medium on a chain with a private mempool, which makes deployment chain part of the severity.

Code4rena runs a third variant: 3 for High where assets can be stolen or lost directly, 2 for Medium where availability or protocol function is hit, and QA for everything else. Its rules assume every role the system assigns is trustworthy and send direct misuse of privileges into a QA report, with privilege escalation judged up to medium. So the sentence "an admin can move user funds" appears in a Code4rena report as a quality assurance note, while the same sentence in a firm audit may be the headline Critical. Reading a contest report with a firm report's expectations produces exactly the wrong impression.

The practical consequence is small and worth adopting. Read the impact sentence of a finding before its tier, and use the tier only to sort. Two reports cannot be compared on their severity counts unless both appendices are open in front of you, and most of the time only one of them exists.

Four published severity systems, compared on what decides the tier (checked )
System Tiers What sets the tier Where the surprise is
Immunefi v2.3 Critical, High, Medium, Low Impact of a successful exploit, downgraded when it needs privileges or odd user interaction Permanent freezing is Critical, temporary freezing is High
OWASP Risk Rating Note, Low, Medium, High, Critical Likelihood and impact scored 0 to 9 each, read off a matrix Business impact can pull the overall rating below the technical one
Sherlock High, Medium Size of the loss against percentage and dollar floors Likelihood is excluded, and a private mempool downgrades a high
Trail of Bits Informational, Undetermined, Low, Medium, High Severity plus a separate difficulty of exploitation axis There is no Critical tier, and Low can mean the client said it does not matter

That last row is the one people misread most often. Trail of Bits defines Low as a risk that is small or is not one the client has indicated is important, and pairs every severity with a difficulty rating of Undetermined, Low, Medium or High. A Medium at high difficulty and a Medium at low difficulty are different problems, and only the second number tells you which.

What the published reports actually say

Method

Measured
Population
23 member firms; 17 listable GitHub archives
Sample
Up to 5 reports per archive: 80 readable reports
Detection
A tier or status term needs 2 occurrences in extracted PDF text; the literal words severity and status need 1

Reproduction uses seo/research/report-vocabulary-survey.py and saved output seo/research/report-vocabulary-2026-09-03.json are kept in the site repository and are not published as web pages. The figures retain their original measurement date.

Limits

  • This counts whole-document text, not parsed finding-table columns. Prose can trigger a match.
  • An unused severity tier may be absent from a report. The counts do not reconstruct a firm's full published scale.

Results

Severity and status vocabulary in 80 reports sampled from 17 member firm archives ()
Measure Reports of 80 Reading
Use the word severity 70 The label is near universal
Name an external scale 21 CVSS, OWASP, Immunefi, SWC or CWE cited anywhere in the document
State likelihood and impact together 26 The rest give a tier without saying how it was reached
Show a Critical tier 42 Highest is a common ceiling, so High does not always mean second worst
Use the word status 53 Another 6 carry a status word such as Fixed without ever naming the column

The first line is the one to hold on to. Almost every report labels its findings by severity, and roughly a third say anything about how that label was reached. For the rest, the tier is an assertion by the firm, defensible and probably right, but not reproducible by the reader.

The 12 status words, counted across 80 reports

The status vocabulary is where the lack of a standard bites hardest. Of the 19 status terms the script looks for, 12 turn up, all for the same handful of real states, and the two most common are not synonyms of each other in any appendix that defines them.

Status words counted across the sampled reports, most common first ()
Word Reports using it What it usually means
Fixed 45 The client says a change was made
Acknowledged 31 Read, and left in place on purpose
Resolved 23 Someone re-checked, usually in a fix review
Open 19 Nothing had happened by the cutoff date
Partially resolved 7 The fix covers part of the finding
Verified 6 The fix was confirmed, wording varies by firm
Pending 5 A fix was promised and not seen
Accepted 3 The risk is being carried deliberately
Mitigated 2 The path was narrowed, the bug remains
Partially fixed 2 The client's wording for partially resolved
Closed 2 The ticket is closed, which is not the same as the bug
Remediated 2 A synonym of fixed with a compliance accent

What is missing matters more than what is there. None of the four phrases "won't fix", "will not fix", "declined" or "risk accepted" reaches the two occurrence threshold in any of the 80 reports, and the raw counts for all four are zero, though those are the states a client is in when a finding stays open by choice. The industry expresses refusal as Acknowledged, a word that reads like agreement and means the opposite of a fix.

Reading the status column

Status is the only column in the report written partly by the client. Knowing who is speaking in each cell is most of the skill.

Fixed
Usually the client's claim, collected during the engagement. On its own it says a change was made, not that anyone re-read the change. Ask which commit.
Resolved
In a fix review this is the auditor's verdict. Trail of Bits defines it as sufficiently resolved and keeps Partially Resolved and Unresolved for the rest, which is a stricter statement than Fixed.
Mitigated
The bug is still there and the path to it was narrowed, by a cap, a role check or a monitoring alert. Useful and not the same as gone. Ask what still triggers it.
Acknowledged
The client has read the finding and left it in place. One word covers three situations that behave nothing alike, and the report will not say which one you are looking at.
Open
Pending
Nothing has happened yet, or nothing had happened by the cutoff date of the document. The date matters more than the word.

Every status also has a date attached to it, whether or not the document prints one. The column reflects the state of the code on the day the report was frozen. Six months of development later it describes nothing, which is why an old report with a clean status column is weaker evidence than a recent report with open findings.

When a finding you care about is marked Acknowledged, the productive question is not whether the team is negligent. It is which of the three situations applies, and that is answerable: ask the team to say in writing whether the finding is out of scope, accepted or disputed. If it is accepted, ask what compensating control exists. A team that has thought about it answers in a sentence. A team that has not will say the auditor was being cautious.

How one finding picks up four labels A finding passes through four hands. An auditor writes the severity by one of three rules: impact only, likelihood times impact or a loss threshold. A client then writes the response, either fixed or acknowledged. A fix review, which is a separate engagement and is often skipped, turns fixed into resolved, partially resolved or unresolved. Last comes the reader, who has to check that the resolved commit is the one deployed on chain. No document in the set states that. FOUR HANDS, FOUR VOCABULARIES Auditor writes the severity by one of three rules Client writes the response Fixed or Acknowledged Fix review separate document, often never ordered You match the commit to the address Severity rule impact only likelihood times impact loss above a threshold Response Fixed, a claim Acknowledged, a refusal Mitigated, a narrowing Verdict Resolved Partially Resolved Unresolved Left to the reader the deployed bytecode, which no report can state A finding marked Fixed has been re-read by nobody outside the team unless a fix review exists and says so.
Each label in a findings table is written by a different party, and only the fix review column carries an outside verdict.

Remediation is a second document, and a much smaller one

The fix review is where Fixed becomes Resolved, and it is a separate engagement with its own price. Look at the proportions in the ChainPort pair. Two consultants spent eight person-weeks producing the original review, and on , one consultant spent one person-day re-checking all 22 fixes.

Trail of Bits ChainPort fix review, 22 findings by severity and outcome ()
Severity Findings Resolved Unresolved
Medium 3 3 0
Low 10 6 4
Informational 6 3 3
Undetermined 3 2 1
Total 22 14 8

That is a healthy pattern and worth recognizing when you see it: everything that mattered was closed, and what stayed open was low, informational or never scoped. The report says plainly that the client has acknowledged the issues that remain unresolved, which is the honest version of the Acknowledged status.

One caution about scope creep in the other direction. A fix review reads the fixes, not the codebase. The notice in the document says the work involves a review of specific areas of the source code and system configuration, so a bug introduced by the fix in a file nobody was asked to look at is outside it. If months of development happened between the audit and the fix review, the second document does not cover any of it.

Three things to ask for when a team tells you the findings were fixed:

  • the commit that contains the fixes
  • whether a fix review exists and is public
  • whether the address you are about to use was deployed from that commit

The third is the one that fails most often, and the procedure for checking it is in our guide to telling a real report from a fake one.

What a clean report does not mean

Reports do use the word "passed", 21 of the 80 sampled ones, so look at what it is attached to. In the reports that lean on it, it is the status of one line in a checklist of named checks. A typical token review may mark many numbered items from compiler errors to timestamp dependence as Passed one by one. That is a verdict on a check, not on the engagement.

The engagement speaks in the notices section, and it says the opposite. Trail of Bits states that its findings should not be considered a comprehensive list of security issues, and the ChainPort review makes the point twice over: it opens by saying the audit did not uncover significant flaws, and it still lists 22 findings across three components.

  • Zero criticals is not a property of the code. It is a joint property of the code, the scope, the time box and the scale in use, and on a scale with no Critical tier the number is zero before anyone opens an editor.
  • The scope was a subset. Everything outside the file list was reviewed by nobody, which is how a bridge with an audited contract layer fails in its off-chain half.
  • A missing tier is a policy. A Sherlock contest report carries no Low findings because the platform does not judge them.
  • The code moves. Deployment happens after the report and upgrades happen after that.

None of this argues for ignoring reports. It argues for reading a report as one control among several, next to the tests the team runs on every commit. A review finds what people notice by reading, and a stateful fuzz suite finds the state sequences nobody thought to read for, which is why the two show up in different findings.

The useful reframing is that a report tells you what a team of a stated size found in a stated time in a stated set of files. That is genuinely valuable, and it is not a warranty. Our analysis of audit companies and the individual member profiles cover the other half of the question, which is how much weight the name on the cover carries.

Ten minutes with a report you have never seen

Both ChainPort documents are public, so this can be followed along rather than taken on trust. The order matters: three of these steps change how you read the findings table, so doing them afterwards wastes the reading.

  1. Scope first. Find the targets section and write down the repositories and commits. Anything not listed is not covered. ChainPort lists three repositories and five commits.
  2. Dates second. Take the engagement window from the executive summary, not the cover. Here it is June 2022, with publication in February 2023.
  3. Effort third. Two consultants and eight person-weeks is a real review. Two days on a protocol of the same size is a different document wearing the same clothes, and the executive summary is where that difference is stated in numbers rather than adjectives.
  4. Read the severity appendix before the findings. This is the step almost everyone skips. In this report it tells you there is no Critical tier and that every finding also carries a difficulty rating.
  5. Now read the table. Count by tier, then read the title of every High and Medium.
  6. Check who wrote the status. Fixed is a claim by the client. Resolved in a fix review is a verdict by someone who read the change.
  7. Match the commit to the chain. The report ends at a commit and your money is at an address. Open the address on the block explorer, check that its source is verified, and compare the files there against the repository at the commit the report names. If the explorer shows the address is a proxy, the code you just compared is not the code that runs: read the implementation address out of the contract and repeat the comparison against that. This is where a genuine report most often stops describing the deployment, and the full procedure is in our guide to telling a real report from a fake one.

Nothing in that sequence requires reading Solidity. It requires reading the front matter, which most people skip because the findings table looks like the interesting part. The findings table is the interesting part only after you know what it covers.

Under time pressure, steps 1, 2 and 7 are the ones that cannot be skipped, because each of them can invalidate the whole document for your purposes. A treasury or an integration decision needs steps 4 and 6 as well, since that is where the difference between a resolved finding and a claimed one lives. Our smart contract audit checklist covers the same ground from the commissioning side, and the guide to smart contract auditing sets out what to expect before a report exists at all.

Frequently asked questions

The report gives severity labels but no appendix defining them. What do I do?

Go to the firm's own methodology page and use the scale published there, because the labels in the document are that firm's private ordering until something defines them. If the firm publishes nothing, ignore the tier and read the impact sentence of each finding instead: a finding that says user funds can be taken is what it is, whatever word sits in the column. In our sample 70 of 80 reports carry the word severity and 21 name any external scale such as CVSS or OWASP, so falling back on the text is the normal case rather than the exception.

Can I compare two firms by counting the findings in their reports?

Not directly, because three things differ before the count does. Scope size sets the ceiling, a review of six contracts and a review of sixty produce different totals from equally good work. Severity definitions differ, so one firm's twelve informational notes are another firm's zero. And house style differs on gas findings, which some firms file as a tier and others leave out of the report entirely. If you want a comparison, count only the findings at high and above, and read them against the number of files in scope.

The report is a file in a GitHub repository, not a PDF on the firm's website. Does that make it less official?

No, and the format tells you nothing about provenance either way. Most member firms keep their public archive as a repository directory rather than a page, and OpenZeppelin keeps its audit history inside openzeppelin-contracts under audits, where the earliest entry is Markdown and everything since is PDF. A file in the firm's own account is easier to check than a PDF someone emailed you, because its history is public and the account is the firm's. What makes a report official is that it sits on infrastructure the firm controls and names a commit you can open.

The project's summary of the audit and the report itself disagree. Who is right?

The report, and the disagreement is usually about severity rather than facts. A team writing its own launch post has an incentive to describe a Medium as a minor issue and an Acknowledged finding as reviewed. Read the finding text yourself, then ask the team which of the three Acknowledged situations applies. If the summary claims a finding was fixed and the report does not say so, the missing item is a fix review, and asking for it is a reasonable request rather than an accusation.

Comments

5
  1. Noah G.

    The severity definitions need to be read before comparing finding counts. Two firms can use the same label for different combinations of impact and likelihood. I would compare the underlying impact descriptions before using totals to rank the reports.

  2. Theo Z.

    Accepted and resolved should not be treated as interchangeable statuses. I would want to see what evidence supports each closed finding. An accepted issue should retain the reason for that decision. A resolved issue should point to the reviewed change and its verification.

  3. Lena Y.

    The smaller fix-review document is easy to miss when a project links only its original report. The remediation record needs to be discoverable from that link. Could the original report page point directly to the latest fix review? I would keep the earlier version available for comparison. The reader should be able to follow a finding through both records without searching a project chat.

  4. Sara L.

    Before using a findings table for a launch decision, I would match the report's code version to the proposed deployment.

  5. Oscar P.

    An empty critical-findings column still leaves the limitations section and untested integration assumptions to examine.

Leave a comment

Share a question or observation about this article.

10 to 3,000 characters.