DeFi Security Alliance

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.

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 )
SystemTiersWhat sets the tierWhere the surprise is
Immunefi v2.3Critical, High, Medium, LowImpact of a successful exploit, downgraded when it needs privileges or odd user interactionPermanent freezing is Critical, temporary freezing is High
OWASP Risk RatingNote, Low, Medium, High, CriticalLikelihood and impact scored 0 to 9 each, read off a matrixBusiness impact can pull the overall rating below the technical one
SherlockHigh, MediumSize of the loss against percentage and dollar floorsLikelihood is excluded, and a private mempool downgrades a high
Trail of BitsInformational, Undetermined, Low, Medium, HighSeverity plus a separate difficulty of exploitation axisThere 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

Rather than assume that this variety shows up in delivered work, we measured it. The script at seo/research/report-vocabulary-survey.py resolves the public archive of each of the 23 member firms of the DeFi Security Alliance, samples reports evenly across the archive listing, converts them with pdftotext and counts the severity and status words each document uses. A word counts when it appears at least twice, which keeps one sentence of prose from registering as a scale label.

Two limits before the numbers. This is a text measure over the whole document and not a parse of the findings table, so a report discussing a fix in prose registers the word. And the tiers seen are the tiers used in those particular reports: an engagement that produced no critical findings will not print the word critical, so a firm's absence from a tier is a floor and not its published scale.

Severity and status vocabulary in 80 reports sampled from 17 member firm archives ()
MeasureReportsReading
Use the word severity70 of 80The label is near universal
Name an external scale21 of 80CVSS, OWASP, Immunefi, SWC or CWE cited anywhere in the document
State likelihood and impact together26 of 80The rest give a tier without saying how it was reached
Show a Critical tier42 of 80Highest is a common ceiling, so High does not always mean second worst
Use the word status53 of 80The rest publish findings with no response column at all

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 status vocabulary is where the lack of a standard bites hardest. Across the sample, 12 distinct words are used 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 ()
WordReports using itWhat it usually means
Fixed45The client says a change was made
Acknowledged31Read, and left in place on purpose
Resolved23Someone re-checked, usually in a fix review
Open19Nothing had happened by the cutoff date
Partially resolved7The fix covers part of the finding
Verified6The fix was confirmed, wording varies by firm
Pending5A fix was promised and not seen
Accepted3The risk is being carried deliberately
Mitigated2The path was narrowed, the bug remains
Partially fixed2The client's wording for partially resolved
Closed2The ticket is closed, which is not the same as the bug
Remediated2A synonym of fixed with a compliance accent

What is missing matters more than what is there. Not one sampled report writes "won't fix", "will not fix", "declined" or "risk accepted", 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. This covers three different situations that the word does not distinguish: out of scope for this release, accepted as a business risk, or disputed on the merits.
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 ()
SeverityFindingsResolvedUnresolved
Medium330
Low1064
Informational633
Undetermined321
Total22148

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, and 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

No serious firm writes the word "passed", and the reason is in the notices section of every report. 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, so closing that gap is a separate job with its own procedure.

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 most reports carry the word severity while a minority 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.