Skip to content
HomeAboutServicesGuidesContact

Guide

How to read a smart contract audit report

Severity scales, scope statements, commit hashes, and the sections most people skip. Explained against reports you can open in the next tab.

In short

  • Read the scope before the findings. A report is bounded by a commit hash and a file list, and the out-of-scope line is where it tells you what nobody looked at.
  • Severity scales are not standardised. A report that does not define what it means by Critical is asking you to supply the meaning yourself.
  • Status matters more than count. Findings are normal in a good codebase; findings the team accepted rather than fixed are the ones you are now deciding to live with.
  • Audited means a named team read named code at a named commit. It does not mean secure, and no audit can prove the absence of a flaw.

Start at the scope, not the findings

Almost everyone opens an audit report at the findings table. It is the wrong end. A finding only means something against a scope, and the scope is where a report quietly tells you how much of the product nobody looked at.

Three things belong there. The commit hash, which pins the report to exact code. The file list, which tells you which contracts were read. And an out-of-scope line, which tells you what was not.

The commit hash is the one to check first. If the hash in the report is not the hash you deployed, the report describes different code — and the difference might be one line or six months of work. Nothing else in the document can tell you which.

The out-of-scope line is the one firms are tempted to leave vague. Ours on the technical sample reads: front-end, third-party bridge, off-chain keeper bots. That is three places an attacker can stand that the report says nothing about, stated plainly rather than left for you to infer.

Severity scales are not standardised

Critical, High, Medium, Low, Informational looks like an industry standard. It is a common convention, which is a different thing. Each firm defines its own, and two reports using the same five words can mean materially different things by them.

So the first question is not how many Criticals there are. It is whether the report defines what it means by Critical at all. A report that uses the labels without defining them is asking you to supply the meaning yourself.

Ours is impact-first — what happens if someone exploits it, rather than how likely they are to try:

SeverityWhat we mean by it
CriticalDirect loss or freezing of user funds, exploitable by anyone
HighLoss under realistic conditions, or trust assumptions broken
MediumBounded loss, or requires unusual conditions to exploit
LowBest-practice gap with indirect or operational risk
InformationalCode quality, gas and hardening notes; no direct risk

Severity can be inflated, and it can be buried

Both directions happen. Some firms label low-severity issues high, because a report with three Criticals looks like better value than one with three Lows. Others downgrade, because a client reads a Critical as an accusation and the relationship is easier without one.

You can usually tell by reading the impact statement rather than the label. A Critical whose worst case is described as "could cause confusion" has been inflated. A Medium whose impact paragraph describes funds leaving has been buried.

The impact statement is harder to fake than the label, because it has to describe something specific.

The section most people skip

Privileged roles. Who holds admin keys, what those keys can do, and how fast they can do it.

This matters more than most findings, because it is not a bug. It is the system working as designed, and the design might be one multisig away from a rug. A protocol with flawless code and an unaccountable owner key is not safe; it is trusting.

The question to ask of that section is narrow: can any role move user funds directly? On our access control sample, the last row of the capability matrix answers it — no role, including Owner, can transfer user balances. Everything above that row is a question of degree. That row is categorical.

If a report does not contain that section at all, you have not been told whether anyone can empty the contract by design.

The anatomy of a finding worth reading

A finding that says "reentrancy risk in withdraw()" tells you a category. A finding worth reading tells you seven things, and you can check for them without understanding the code.

Where it is. A file, a function, a line range. If a finding cannot point at code, it is an opinion.

What it is. The mechanism, in the auditor's terms. This part is for your engineers.

What it is in plain terms. The same mechanism for everyone else — the people approving the budget and deciding whether to launch. A firm that cannot write this part may not have understood the finding either.

What it costs. Impact, stated as consequence rather than category. "Mispriced swaps whenever the upstream feed stalls, scaling with market movement" is an impact. "Could lead to loss of funds" is a shrug.

Proof. What was actually run. Ours on the stale-oracle finding: a 30-minute feed halt simulated on a fork while moving the market 12%, with the pool accepting swaps at the stale rate throughout. A finding with no proof has not been demonstrated, only suspected.

What to do. A specific remediation, not "follow best practice".

What happened. The resolution, re-tested. "Fixed and verified: the halt simulation now pauses the pool within one block" closes the loop. "Fixed" on its own does not say who checked.

Run those seven against any finding in any report. The ones that fail tend to fail at proof and at impact, which are the two that take real work.

Count tells you less than status

Findings are normal. A mature codebase reviewed properly produces them, and a report with none is more likely to indicate a shallow review than clean code.

What matters is what happened next. Every finding should carry a status, and the statuses that matter are the ones that are not "fixed": accepted, mitigated, or acknowledged without action. Those are the risks the team decided to live with, and you are now deciding whether to live with them too.

Our technical sample has one. TA-07, a medium, where long-term stakers could eventually be locked out of their own rewards. The team accepted it for launch with a capped epoch count and a refactor scheduled. We re-tested the cap and published the finding at full length anyway.

A report where everything was fixed is either a very short engagement or an incomplete account of one.

What "audited" does not mean

It does not mean secure. It means a named team read named code at a named commit, in a named window, and wrote down what they found.

It does not cover code changed after the review. It does not cover what was out of scope. It does not cover the parts of your system that are not code at all — the admin laptop, the deploy pipeline, the person with the hardware key.

And it cannot prove the absence of a flaw. An audit raises the cost of attacking you considerably. It does not reduce that cost to infinity, and a firm that implies otherwise is selling you something an audit cannot deliver.

The honest version of the claim is narrow, and it is the one worth looking for: these contracts, at this commit, were reviewed by these people, who found these things, of which these were fixed.

Red flags

None of these prove a bad audit on their own. Two or three together usually mean the report was written to be shown rather than read.

What you seeWhat it usually means
No findings at allA shallow review, or findings removed before publication
No severity definitionsThe labels mean whatever the reader assumes
No per-finding statusYou cannot tell what was fixed
A positive conclusion above unresolved CriticalsThe summary and the body disagree; trust the body
No commit hashNothing ties the report to code
A badge on a website, no reportThere may be a report. You have not read it
No privileged-roles sectionNobody has told you who can move the funds

The checklist

Seven questions, in the order worth asking them. Run them against any report you are handed, including ours.

One. Does the commit hash in the report match the code that is deployed?

Two. Do the audited files cover the contracts that hold funds and control upgrades?

Three. What does the out-of-scope line say, and does anything in it hold value?

Four. Does the report define its own severity scale?

Five. Does every finding carry a status, and what did the team accept rather than fix?

Six. What can privileged roles do, and can any of them move user funds directly?

Seven. Was there a re-test after remediation, against a named commit?

A report that answers all seven is not necessarily a clean one. It is an honest one, which is the thing you can actually act on.

Questions

Is a critical finding a reason to walk away?

Usually not. Critical findings are found in good codebases by good auditors; that is what the engagement is for. What should concern you is a critical that is still open at launch, or one whose fix was never re-tested.

The commit hash does not match what is deployed. How bad is that?

It depends entirely on what changed, and the report cannot tell you. Ask for the diff between the audited commit and the deployed one. If the team cannot produce it, that is the answer.

Does a longer report mean a better audit?

No. Length tracks the number of informational notes more than the depth of review. Read the scope and the severity definitions; they tell you more about rigour than the page count does.

Should I trust an audit by a firm I have never heard of?

Judge the report rather than the name. The seven questions above work regardless of who wrote it, and a careful report from an unknown firm is worth more than a vague one from a famous one.

The work behind this

Related reading