← Back to Blog

How to Read a Smart Contract Audit Report: Severity, Findings, and Next Steps

2026-07-27 smart contract audit audit report security findings solidity defi security remediation 2026

You received your smart contract audit report. Now what? Audit reports from different firms use different formats, severity scales, and risk frameworks. This guide explains how to read and act on a report, regardless of which auditor produced it.


Understanding Severity Levels

Most audit firms use a 4–5 tier severity scale. The labels differ, but the meaning is consistent:

Severity Typical Labels Meaning
Critical Critical, P0, Severity 1 Direct loss of funds, immediate threat, deploy immediately exploitable
High High, P1, Severity 2 Significant loss potential, requires specific conditions to exploit
Medium Medium, P2, Severity 3 Limited impact or requires multiple conditions to exploit
Low Low, P3, Informational Best practice violations, minor bugs with negligible direct impact
Informational Info, Gas, Note Code quality, gas optimization, style suggestions

Critical: These are deploy blockers. A Critical finding means funds are at risk now or under trivially achievable conditions. Fix before mainnet. No exceptions.

High: Should be fixed before mainnet. Some teams defer High findings with documented mitigations (e.g., "High finding X requires admin key compromise — mitigated by multi-sig"). This is acceptable only with explicit justification.

Medium: Risk-assess each one. Many Medium findings require specific conditions (e.g., "only if the oracle is compromised first") that may be acceptable depending on your threat model. Document why you defer any Medium.

Low/Informational: Address in a subsequent audit cycle. Don't block your launch over gas optimization notes.


Anatomy of a Finding

Every finding should contain:

Finding ID: M-03
Title: Unchecked Return Value in withdraw()
Severity: Medium
Status: Open / Acknowledged / Fixed

The withdraw() function calls token.transfer() without checking the return
value. ERC-20 tokens that return false on failure instead of reverting (e.g., LEND, ZRX)
will silently fail, leaving user funds locked. Additionally, tokens that do not return
a boolean value on transfer (e.g., USDT) will cause standard Solidity interfaces to revert
due to return-value decode failure.

Impact:
Users attempting to withdraw via non-standard ERC-20 tokens may lose access
to their funds without receiving any error message.

Recommendation:
Use SafeERC20.safeTransfer() from OpenZeppelin instead of token.transfer().

References:
- EIP-20 specification
- OpenZeppelin SafeERC20 documentation

Developer Response:
Fixed in commit abc1234. Changed to SafeERC20.safeTransfer().

Auditor Verification:
Confirmed fixed in the final review.

What each field means for you:


Prioritization Framework

Not all findings are equal urgency. After reading the report, categorize findings:

Tier 1 — Fix before launch (blocking):
- All Critical findings
- High findings with no viable mitigation
- Any finding that could cause permanent loss of user funds

Tier 2 — Fix before launch if time permits:
- High findings with documented mitigations
- Medium findings with straightforward fixes

Tier 3 — Fix in next contract version:
- Medium findings with complex fixes that would require new auditing
- Low findings
- Gas optimizations

Tier 4 — Acknowledge with documentation:
- Findings the auditor marked as accepted-risk
- Findings that require prerequisites your threat model considers acceptable


Common Finding Categories and What They Mean

Reentrancy

The contract makes external calls before updating state. A malicious recipient can call back into the contract before balances are adjusted.

Immediate fix required for any function that handles ETH or tokens.

Access Control

A function lacks proper authorization, or the wrong party has admin rights.

Critical if it allows anyone to drain funds. High if it requires a specific role.

Integer Overflow/Underflow

Arithmetic can wrap to unexpected values. In Solidity 0.8+, this causes reverts by default — but unchecked blocks disable this protection.

Check whether the overflow is in a path that accepts external input.

Oracle Manipulation

Price data can be manipulated via flash loans or other mechanisms.

Severity depends on whether your protocol uses spot prices (high risk) or TWAP oracles (lower risk).

Uninitialized Storage / Proxy Issues

Variables or proxy contracts weren't properly initialized.

Critical for upgradeable contracts — can lead to complete protocol takeover.

Business Logic Flaws

The code does what it says but what it says is wrong — the logic doesn't match the intended behavior.

These are the hardest to fix because they often require redesign, not just a code patch.


What Auditors Often Don't Cover

Even comprehensive audits have gaps. Don't assume an audit covers:

Economic attacks: Flash loan attack simulations, oracle sandwich attacks, and MEV-specific exploits often require specialized economic modeling that goes beyond standard code review.

Operational security: Key management, multi-sig setup, deployment process, and team access controls are operational — not in-scope for most code audits.

Integration risks: How your contract interacts with external protocols (Uniswap, Chainlink, Aave) is often partially or fully out of scope, especially if the external protocol could change.

Known-safe libraries: Auditors typically don't re-audit imported OpenZeppelin contracts, but your usage of them could still be wrong.

Post-deployment monitoring: Detecting attacks in progress, incident response, and upgrade processes are out of scope for a static audit.


Verifying Your Fixes

After making changes based on audit findings, don't assume the fix is correct:

1. Get a remediation review

Most audit firms offer a follow-up review of your fixes at reduced cost. Request it for Critical and High findings — the auditor checks that your fix addresses the root cause without introducing new issues.

2. Run automated tools after patching

Before the remediation review, run automated scanning to catch any regressions you introduced:

# Run ContractScan on your fixed contracts
curl -X POST https://contract-scanner.raccoonworld.xyz/scan \
  -H "X-Api-Key: YOUR_KEY" \
  -F "files=@src/VaultV2.sol"

New code paths in your fix may introduce new vulnerabilities. Automated scanning catches the common ones before a human reviewer sees them.

3. Test the specific vulnerability scenario

Write a test that reproduces the finding and verify it no longer passes:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Test} from "forge-std/Test.sol";

contract VaultTest is Test {
    // Test that the reentrancy fix actually works
    function test_cannotReentrant_afterFix() public {
        // Setup malicious contract
        ReentrantAttacker attacker = new ReentrantAttacker(vault);
        deal(address(token), address(attacker), 1 ether);

        // Attempt reentrancy attack
        vm.expectRevert();  // should revert now that fix is applied
        attacker.attack();
    }
}

4. Check fix scope

Common mistake: fixing the vulnerability in the reported function but not in other functions with the same pattern.

If finding M-03 reports "unchecked transfer in withdraw()", also check emergencyWithdraw(), claimRewards(), and any other function that calls token.transfer().


Reading Between the Lines

Audit reports contain signals beyond the formal findings:

Auditor confidence language: Phrases like "the auditors couldn't determine whether..." or "further analysis would require..." signal areas where confidence was low. Treat adjacent code as potentially riskier.

Acknowledged findings: When an auditor accepts a risk, they often write something like "the team confirmed this is acceptable given X." Read those justifications — if X no longer holds at launch, the risk re-opens.

"Fixed" without verification: Some teams mark findings as "Fixed" before the auditor has reviewed the fix. Look for auditor confirmation in the Status field, not just developer response.

Scope limitations: Most audit reports list what was in scope. Code added or modified after the audit cutoff date hasn't been reviewed — including your fixes.


After the Audit: Ongoing Security

An audit is a point-in-time review. Security is ongoing:

  1. Run automated checks on every PR — CI/CD scanning catches regressions before they hit mainnet
  2. Set up a bug bounty — incentivize continued external review post-launch
  3. Monitor for anomalies — unusual transaction patterns often precede exploits
  4. Re-audit before major upgrades — any significant contract change needs fresh review

ContractScan integrates with CI/CD via API — scan every pull request automatically to catch regressions that might reopen closed audit findings.


Related: Smart Contract Audit Cost in 2026 — what you'll pay at each tier and how to choose the right firm.

Related: Smart Contract Security Checklist Before Mainnet — the pre-launch checklist to complement your audit report.

Important Notes

This post is for informational and educational purposes only. It does not constitute financial, legal, or investment advice. The security analysis provided is based on available data and automated tools, which may not capture all potential vulnerabilities. Always conduct a professional audit before deploying smart contracts.

Scan your contract for this vulnerability
Free QuickScan — Unlimited quick scans. No signup required.. No signup required.
Scan a Contract →