All articles
Smart Contracts·June 26, 2026·6 min read

After the Audit: Remediation and Re-Verification Explained

What post audit remediation actually involves: the fix-verify-certify loop, why re-verification catches regressions, and what the final report means.

An audit report is not a finish line. It's a punch list, and what a team does with that punch list over the following one to three weeks matters more than the audit itself. Most of the actual security work in a post audit remediation cycle happens after the PDF lands — in the fixes, the re-reads, and the second pass that catches what the fixes broke.

What the fix-verify-certify loop actually looks like

A typical audit report groups findings by severity: critical, high, medium, low, and informational/gas. For a mid-sized DeFi contract set (say 1,500–3,000 lines across 6–10 contracts), a first pass usually turns up somewhere between 15 and 40 findings, with 2–6 of those in the critical/high band. The remediation loop runs like this:

  1. Triage. The dev team and the auditor agree on which findings get fixed, which get accepted as risk (with a written rationale), and which get reclassified after discussion — auditors are sometimes wrong about severity, and a good one will say so when shown context.
  2. Fix. Developers patch the code, ideally one commit per finding so the diff maps cleanly to the report item.
  3. Self-verify. The team runs its own test suite plus targeted PoCs against the fix before sending anything back.
  4. Re-verification. The auditor reviews each fix individually against the original finding, not just "does this look better."
  5. Certification. Once every finding is closed, mitigated, or explicitly accepted, the auditor issues a final report — the version that actually gets published and linked from the dApp's docs.

Skipping step 4 is the single most common corner cut in the industry, usually under launch-date pressure. It's also the step where the second-most-dangerous class of bugs gets introduced: fixes that solve the reported issue but open a new one.

A worked example: fixing a reentrancy finding

Say the audit flags a classic reentrancy issue in a staking contract's withdraw function:

// BEFORE — flagged as High
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "insufficient balance");
    (bool ok, ) = msg.sender.call{value: amount}("");
    require(ok, "transfer failed");
    balances[msg.sender] -= amount;
}

The external call happens before the state update, so a malicious contract can re-enter withdraw and drain the pool before balances is decremented. The obvious fix — and the one most teams ship first — is to reorder the lines:

// AFTER — first patch attempt
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "insufficient balance");
    balances[msg.sender] -= amount;
    (bool ok, ) = msg.sender.call{value: amount}("");
    require(ok, "transfer failed");
}

This closes the original finding. But it's exactly the kind of change that needs a fresh look rather than a rubber stamp, because reordering doesn't cover every re-entrant path — if withdraw is called from a batch function that touches balances again before the outer call returns, there's still a cross-function reentrancy window. A thorough re-verification pass checks the call graph, not just the diff:

// AFTER — verified fix
function withdraw(uint256 amount) external nonReentrant {
    require(balances[msg.sender] >= amount, "insufficient balance");
    balances[msg.sender] -= amount;
    (bool ok, ) = msg.sender.call{value: amount}("");
    require(ok, "transfer failed");
}

Adding nonReentrant (OpenZeppelin's ReentrancyGuard) on top of the checks-effects-interactions reorder gives defense in depth. It costs roughly 2,300 extra gas per call for the storage read/write on the guard's lock variable — worth checking whether that's acceptable for a high-frequency function before shipping it everywhere by default.

Why re-verification is a distinct engineering task, not a formality

Re-verification isn't "check the box next to each finding." A serious re-verification pass does three things a first read of the diff won't catch:

  • Confirms the fix actually addresses the root cause, not just the specific PoC the auditor supplied. Auditors write one exploit path per finding; a narrow fix can pass that exact test and still leave the underlying pattern exploitable elsewhere.
  • Checks for regressions the fix introduced. Adding access control to one function sometimes breaks a legitimate call path from another contract in the system (a router, a proxy admin, a keeper bot). This is where integration tests matter more than unit tests.
  • Re-runs static analysis and fuzzing against the patched codebase, not just the flagged functions. Slither, Mythril, and Echidna runs from the original audit get re-executed against the new commit, because a fix in one function can shift storage layout or control flow in ways that create new findings elsewhere.

On our own re-verification passes, it's common to find 1–3 new low-or-medium issues introduced by the fixes themselves, particularly around access control and event emission that got dropped during a refactor. None of that shows up if the re-check is a five-minute glance at the pull request.

What the final certificate actually certifies

The certificate a team publishes should reflect the last commit hash reviewed, not the commit that triggered the original audit. If code changes after certification — even a config value or a constructor argument — the certificate technically no longer applies to what's deployed. Reputable audit firms hash-pin the report to a specific commit for exactly this reason, and teams should redeploy from that exact commit rather than a "close enough" branch.

This is also why timelines slip: a report that flags 25 findings on a Friday rarely gets a clean re-verification by Monday. Budget one to two weeks for remediation plus re-verification on top of the original audit timeline, more if criticals turn up. For context on how audit scope and duration map to cost across different chains, see our breakdown of smart contract audit pricing across EVM, Solana, and TON. Teams building on TON specifically should also check the FunC and Tact audit checklist, since remediation patterns there differ from Solidity in ways that trip up teams porting fixes across chains.

If you're still deciding whether an audit is necessary before you ship, that's a separate question worth answering first — see do you need a smart contract audit before mainnet launch for how to think about it.

Practical guidance for teams going through remediation

A few habits make the loop faster and less painful:

  • One finding, one commit, one commit message referencing the report ID. Makes re-verification traceable instead of guesswork.
  • Don't bundle unrelated refactors into remediation commits. It forces the auditor to review scope creep instead of just the fix.
  • Write down the rationale for every "accepted risk" finding. Six months later, nobody remembers why a low-severity issue was left in.
  • Re-run your full test suite, not just the tests touching the changed function, before sending fixes back.

Good remediation is a joint effort between your engineers and whoever reviewed the code originally — a second set of eyes that already knows the codebase moves faster and catches more than a cold re-read. If you're weighing a full independent pass on top of internal fixes, a code review and audit engagement scoped specifically to remediation is usually cheaper than a second full audit, and it pairs well with teams that also need ongoing smart contract development support to implement the fixes correctly the first time.

If your project is heading toward a fix-verify-certify cycle of its own, our smart contract audit service runs re-verification as a standard part of every engagement, not an optional add-on.

Need a bot like this built?

We design, build and run trading bots on Solana, Hyperliquid and Polymarket.

Start a project
#post audit remediation#smart contract audit#security engineering#code review#re-verification